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
28 #include "gtktextiter.h"
29 #include "gtktextbtree.h"
30 #include "gtktextiterprivate.h"
34 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
36 typedef struct _GtkTextRealIter GtkTextRealIter;
38 struct _GtkTextRealIter
40 /* Always-valid information */
43 /* At least one of these is always valid;
44 if invalid, they are -1.
46 If the line byte offset is valid, so is the segment byte offset;
47 and ditto for char offsets. */
48 gint line_byte_offset;
49 gint line_char_offset;
50 /* These two are valid if >= 0 */
51 gint cached_char_index;
52 gint cached_line_number;
53 /* Stamps to detect the buffer changing under us */
54 gint chars_changed_stamp;
55 gint segments_changed_stamp;
56 /* Valid if the segments_changed_stamp is up-to-date */
57 GtkTextLineSegment *segment; /* indexable segment we index */
58 GtkTextLineSegment *any_segment; /* first segment in our location,
59 maybe same as "segment" */
60 /* One of these will always be valid if segments_changed_stamp is
61 up-to-date. If invalid, they are -1.
63 If the line byte offset is valid, so is the segment byte offset;
64 and ditto for char offsets. */
65 gint segment_byte_offset;
66 gint segment_char_offset;
73 /* These "set" functions should not assume any fields
74 other than the char stamp and the tree are valid.
77 iter_set_common (GtkTextRealIter *iter,
80 /* Update segments stamp */
81 iter->segments_changed_stamp =
82 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
86 iter->line_byte_offset = -1;
87 iter->line_char_offset = -1;
88 iter->segment_byte_offset = -1;
89 iter->segment_char_offset = -1;
90 iter->cached_char_index = -1;
91 iter->cached_line_number = -1;
95 iter_set_from_byte_offset (GtkTextRealIter *iter,
99 iter_set_common (iter, line);
101 if (!_gtk_text_line_byte_locate (iter->line,
105 &iter->segment_byte_offset,
106 &iter->line_byte_offset))
107 g_error ("Byte index %d is off the end of the line",
112 iter_set_from_char_offset (GtkTextRealIter *iter,
116 iter_set_common (iter, line);
118 if (!_gtk_text_line_char_locate (iter->line,
122 &iter->segment_char_offset,
123 &iter->line_char_offset))
124 g_error ("Char offset %d is off the end of the line",
129 iter_set_from_segment (GtkTextRealIter *iter,
131 GtkTextLineSegment *segment)
133 GtkTextLineSegment *seg;
136 /* This could theoretically be optimized by computing all the iter
137 fields in this same loop, but I'm skipping it for now. */
139 seg = line->segments;
140 while (seg != segment)
142 byte_offset += seg->byte_count;
146 iter_set_from_byte_offset (iter, line, byte_offset);
149 /* This function ensures that the segment-dependent information is
150 truly computed lazily; often we don't need to do the full make_real
151 work. This ensures the btree and line are valid, but doesn't
152 update the segments. */
153 static GtkTextRealIter*
154 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
156 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
158 if (iter->chars_changed_stamp !=
159 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
161 g_warning ("Invalid text buffer iterator: either the iterator "
162 "is uninitialized, or the characters/pixbufs/widgets "
163 "in the buffer have been modified since the iterator "
164 "was created.\nYou must use marks, character numbers, "
165 "or line numbers to preserve a position across buffer "
166 "modifications.\nYou can apply tags and insert marks "
167 "without invalidating your iterators,\n"
168 "but any mutation that affects 'indexable' buffer contents "
169 "(contents that can be referred to by character offset)\n"
170 "will invalidate all outstanding iterators");
174 /* We don't update the segments information since we are becoming
175 only surreal. However we do invalidate the segments information
176 if appropriate, to be sure we segfault if we try to use it and we
177 should have used make_real. */
179 if (iter->segments_changed_stamp !=
180 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
182 iter->segment = NULL;
183 iter->any_segment = NULL;
184 /* set to segfault-causing values. */
185 iter->segment_byte_offset = -10000;
186 iter->segment_char_offset = -10000;
192 static GtkTextRealIter*
193 gtk_text_iter_make_real (const GtkTextIter *_iter)
195 GtkTextRealIter *iter;
197 iter = gtk_text_iter_make_surreal (_iter);
199 if (iter->segments_changed_stamp !=
200 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
202 if (iter->line_byte_offset >= 0)
204 iter_set_from_byte_offset (iter,
206 iter->line_byte_offset);
210 g_assert (iter->line_char_offset >= 0);
212 iter_set_from_char_offset (iter,
214 iter->line_char_offset);
218 g_assert (iter->segment != NULL);
219 g_assert (iter->any_segment != NULL);
220 g_assert (iter->segment->char_count > 0);
225 static GtkTextRealIter*
226 iter_init_common (GtkTextIter *_iter,
229 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
231 g_return_val_if_fail (iter != NULL, NULL);
232 g_return_val_if_fail (tree != NULL, NULL);
236 iter->chars_changed_stamp =
237 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
242 static GtkTextRealIter*
243 iter_init_from_segment (GtkTextIter *iter,
246 GtkTextLineSegment *segment)
248 GtkTextRealIter *real;
250 g_return_val_if_fail (line != NULL, NULL);
252 real = iter_init_common (iter, tree);
254 iter_set_from_segment (real, line, segment);
259 static GtkTextRealIter*
260 iter_init_from_byte_offset (GtkTextIter *iter,
263 gint line_byte_offset)
265 GtkTextRealIter *real;
267 g_return_val_if_fail (line != NULL, NULL);
269 real = iter_init_common (iter, tree);
271 iter_set_from_byte_offset (real, line, line_byte_offset);
273 if (real->segment->type == >k_text_char_type &&
274 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
275 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
276 "character; this will crash the text buffer. "
277 "Byte indexes must refer to the start of a character.",
283 static GtkTextRealIter*
284 iter_init_from_char_offset (GtkTextIter *iter,
287 gint line_char_offset)
289 GtkTextRealIter *real;
291 g_return_val_if_fail (line != NULL, NULL);
293 real = iter_init_common (iter, tree);
295 iter_set_from_char_offset (real, line, line_char_offset);
301 invalidate_segment (GtkTextRealIter *iter)
303 iter->segments_changed_stamp -= 1;
307 invalidate_char_index (GtkTextRealIter *iter)
309 iter->cached_char_index = -1;
313 invalidate_line_number (GtkTextRealIter *iter)
315 iter->cached_line_number = -1;
319 adjust_char_index (GtkTextRealIter *iter, gint count)
321 if (iter->cached_char_index >= 0)
322 iter->cached_char_index += count;
326 adjust_line_number (GtkTextRealIter *iter, gint count)
328 if (iter->cached_line_number >= 0)
329 iter->cached_line_number += count;
333 adjust_char_offsets (GtkTextRealIter *iter, gint count)
335 if (iter->line_char_offset >= 0)
337 iter->line_char_offset += count;
338 g_assert (iter->segment_char_offset >= 0);
339 iter->segment_char_offset += count;
344 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
346 if (iter->line_byte_offset >= 0)
348 iter->line_byte_offset += count;
349 g_assert (iter->segment_byte_offset >= 0);
350 iter->segment_byte_offset += count;
355 ensure_char_offsets (GtkTextRealIter *iter)
357 if (iter->line_char_offset < 0)
359 g_assert (iter->line_byte_offset >= 0);
361 _gtk_text_line_byte_to_char_offsets (iter->line,
362 iter->line_byte_offset,
363 &iter->line_char_offset,
364 &iter->segment_char_offset);
369 ensure_byte_offsets (GtkTextRealIter *iter)
371 if (iter->line_byte_offset < 0)
373 g_assert (iter->line_char_offset >= 0);
375 _gtk_text_line_char_to_byte_offsets (iter->line,
376 iter->line_char_offset,
377 &iter->line_byte_offset,
378 &iter->segment_byte_offset);
382 static inline gboolean
383 is_segment_start (GtkTextRealIter *real)
385 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
390 check_invariants (const GtkTextIter *iter)
392 if (gtk_debug_flags & GTK_DEBUG_TEXT)
393 _gtk_text_iter_check (iter);
396 #define check_invariants (x)
400 * gtk_text_iter_get_buffer:
403 * Returns the #GtkTextBuffer this iterator is associated with.
405 * Return value: the buffer
408 gtk_text_iter_get_buffer (const GtkTextIter *iter)
410 GtkTextRealIter *real;
412 g_return_val_if_fail (iter != NULL, NULL);
414 real = gtk_text_iter_make_surreal (iter);
419 check_invariants (iter);
421 return _gtk_text_btree_get_buffer (real->tree);
425 * gtk_text_iter_copy:
428 * Creates a dynamically-allocated copy of an iterator. This function
429 * is not useful in applications, because iterators can be copied with a
430 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
431 * function is used by language bindings.
433 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
436 gtk_text_iter_copy (const GtkTextIter *iter)
438 GtkTextIter *new_iter;
440 g_return_val_if_fail (iter != NULL, NULL);
442 new_iter = g_new (GtkTextIter, 1);
450 * gtk_text_iter_free:
451 * @iter: a dynamically-allocated iterator
453 * Free an iterator allocated on the heap. This function
454 * is intended for use in language bindings, and is not
455 * especially useful for applications, because iterators can
456 * simply be allocated on the stack.
459 gtk_text_iter_free (GtkTextIter *iter)
461 g_return_if_fail (iter != NULL);
467 gtk_text_iter_get_type (void)
469 static GType our_type = 0;
472 our_type = g_boxed_type_register_static ("GtkTextIter",
473 (GBoxedCopyFunc) gtk_text_iter_copy,
474 (GBoxedFreeFunc) gtk_text_iter_free);
480 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
482 GtkTextRealIter *real;
484 g_return_val_if_fail (iter != NULL, 0);
486 real = gtk_text_iter_make_real (iter);
491 check_invariants (iter);
493 g_assert (real->segment != NULL);
495 return real->segment;
499 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
501 GtkTextRealIter *real;
503 g_return_val_if_fail (iter != NULL, 0);
505 real = gtk_text_iter_make_real (iter);
510 check_invariants (iter);
512 g_assert (real->any_segment != NULL);
514 return real->any_segment;
518 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
520 GtkTextRealIter *real;
522 g_return_val_if_fail (iter != NULL, 0);
524 real = gtk_text_iter_make_real (iter);
529 ensure_byte_offsets (real);
531 check_invariants (iter);
533 return real->segment_byte_offset;
537 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
539 GtkTextRealIter *real;
541 g_return_val_if_fail (iter != NULL, 0);
543 real = gtk_text_iter_make_real (iter);
548 ensure_char_offsets (real);
550 check_invariants (iter);
552 return real->segment_char_offset;
555 /* This function does not require a still-valid
558 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
560 const GtkTextRealIter *real;
562 g_return_val_if_fail (iter != NULL, 0);
564 real = (const GtkTextRealIter*)iter;
569 /* This function does not require a still-valid
572 _gtk_text_iter_get_btree (const GtkTextIter *iter)
574 const GtkTextRealIter *real;
576 g_return_val_if_fail (iter != NULL, 0);
578 real = (const GtkTextRealIter*)iter;
588 * gtk_text_iter_get_offset:
591 * Returns the character offset of an iterator.
592 * Each character in a #GtkTextBuffer has an offset,
593 * starting with 0 for the first character in the buffer.
594 * Use gtk_text_buffer_get_iter_at_offset () to convert an
595 * offset back into an iterator.
597 * Return value: a character offset
600 gtk_text_iter_get_offset (const GtkTextIter *iter)
602 GtkTextRealIter *real;
604 g_return_val_if_fail (iter != NULL, 0);
606 real = gtk_text_iter_make_surreal (iter);
611 check_invariants (iter);
613 if (real->cached_char_index < 0)
615 ensure_char_offsets (real);
617 real->cached_char_index =
618 _gtk_text_line_char_index (real->line);
619 real->cached_char_index += real->line_char_offset;
622 check_invariants (iter);
624 return real->cached_char_index;
628 * gtk_text_iter_get_line:
631 * Returns the line number containing the iterator. Lines in
632 * a #GtkTextBuffer are numbered beginning with 0 for the first
633 * line in the buffer.
635 * Return value: a line number
638 gtk_text_iter_get_line (const GtkTextIter *iter)
640 GtkTextRealIter *real;
642 g_return_val_if_fail (iter != NULL, 0);
644 real = gtk_text_iter_make_surreal (iter);
649 if (real->cached_line_number < 0)
650 real->cached_line_number =
651 _gtk_text_line_get_number (real->line);
653 check_invariants (iter);
655 return real->cached_line_number;
659 * gtk_text_iter_get_line_offset:
662 * Returns the character offset of the iterator,
663 * counting from the start of a newline-terminated line.
664 * The first character on the line has offset 0.
666 * Return value: offset from start of line
669 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
671 GtkTextRealIter *real;
673 g_return_val_if_fail (iter != NULL, 0);
675 real = gtk_text_iter_make_surreal (iter);
680 ensure_char_offsets (real);
682 check_invariants (iter);
684 return real->line_char_offset;
688 * gtk_text_iter_get_line_index:
691 * Returns the byte index of the iterator, counting
692 * from the start of a newline-terminated line.
693 * Remember that #GtkTextBuffer encodes text in
694 * UTF-8, and that characters can require a variable
695 * number of bytes to represent.
697 * Return value: distance from start of line, in bytes
700 gtk_text_iter_get_line_index (const GtkTextIter *iter)
702 GtkTextRealIter *real;
704 g_return_val_if_fail (iter != NULL, 0);
706 real = gtk_text_iter_make_surreal (iter);
711 ensure_byte_offsets (real);
713 check_invariants (iter);
715 return real->line_byte_offset;
719 * gtk_text_iter_get_visible_line_offset:
720 * @iter: a #GtkTextIter
722 * Returns the offset in characters from the start of the
723 * line to the given @iter, not counting characters that
724 * are invisible due to tags with the "invisible" flag
727 * Return value: offset in visible characters from the start of the line
730 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
732 GtkTextRealIter *real;
734 GtkTextLineSegment *seg;
737 g_return_val_if_fail (iter != NULL, 0);
739 real = gtk_text_iter_make_real (iter);
744 ensure_char_offsets (real);
746 check_invariants (iter);
748 vis_offset = real->line_char_offset;
750 g_assert (vis_offset >= 0);
752 _gtk_text_btree_get_iter_at_line (real->tree,
757 seg = _gtk_text_iter_get_indexable_segment (&pos);
759 while (seg != real->segment)
761 /* This is a pretty expensive call, making the
762 * whole function pretty lame; we could keep track
763 * of current invisibility state by looking at toggle
764 * segments as we loop, and then call this function
765 * only once per line, in order to speed up the loop
768 if (_gtk_text_btree_char_is_invisible (&pos))
769 vis_offset -= seg->char_count;
771 _gtk_text_iter_forward_indexable_segment (&pos);
773 seg = _gtk_text_iter_get_indexable_segment (&pos);
776 if (_gtk_text_btree_char_is_invisible (&pos))
777 vis_offset -= real->segment_char_offset;
784 * gtk_text_iter_get_visible_line_index:
785 * @iter: a #GtkTextIter
787 * Returns the number of bytes from the start of the
788 * line to the given @iter, not counting bytes that
789 * are invisible due to tags with the "invisible" flag
792 * Return value: byte index of @iter with respect to the start of the line
795 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
797 GtkTextRealIter *real;
799 GtkTextLineSegment *seg;
802 g_return_val_if_fail (iter != NULL, 0);
804 real = gtk_text_iter_make_real (iter);
809 ensure_byte_offsets (real);
811 check_invariants (iter);
813 vis_offset = real->line_byte_offset;
815 g_assert (vis_offset >= 0);
817 _gtk_text_btree_get_iter_at_line (real->tree,
822 seg = _gtk_text_iter_get_indexable_segment (&pos);
824 while (seg != real->segment)
826 /* This is a pretty expensive call, making the
827 * whole function pretty lame; we could keep track
828 * of current invisibility state by looking at toggle
829 * segments as we loop, and then call this function
830 * only once per line, in order to speed up the loop
833 if (_gtk_text_btree_char_is_invisible (&pos))
834 vis_offset -= seg->byte_count;
836 _gtk_text_iter_forward_indexable_segment (&pos);
838 seg = _gtk_text_iter_get_indexable_segment (&pos);
841 if (_gtk_text_btree_char_is_invisible (&pos))
842 vis_offset -= real->segment_byte_offset;
852 * gtk_text_iter_get_char:
855 * Returns the Unicode character at this iterator. (Equivalent to
856 * operator* on a C++ iterator.) If the element at this iterator is a
857 * non-character element, such as an image embedded in the buffer, the
858 * Unicode "unknown" character 0xFFFC is returned. If invoked on
859 * the end iterator, zero is returned; zero is not a valid Unicode character.
860 * So you can write a loop which ends when gtk_text_iter_get_char ()
863 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
866 gtk_text_iter_get_char (const GtkTextIter *iter)
868 GtkTextRealIter *real;
870 g_return_val_if_fail (iter != NULL, 0);
872 real = gtk_text_iter_make_real (iter);
877 check_invariants (iter);
879 if (gtk_text_iter_is_end (iter))
881 else if (real->segment->type == >k_text_char_type)
883 ensure_byte_offsets (real);
885 return g_utf8_get_char (real->segment->body.chars +
886 real->segment_byte_offset);
890 /* Unicode "unknown character" 0xFFFC */
891 return GTK_TEXT_UNKNOWN_CHAR;
896 * gtk_text_iter_get_slice:
897 * @start: iterator at start of a range
898 * @end: iterator at end of a range
900 * Returns the text in the given range. A "slice" is an array of
901 * characters encoded in UTF-8 format, including the Unicode "unknown"
902 * character 0xFFFC for iterable non-character elements in the buffer,
903 * such as images. Because images are encoded in the slice, byte and
904 * character offsets in the returned array will correspond to byte
905 * offsets in the text buffer. Note that 0xFFFC can occur in normal
906 * text as well, so it is not a reliable indicator that a pixbuf or
907 * widget is in the buffer.
909 * Return value: slice of text from the buffer
912 gtk_text_iter_get_slice (const GtkTextIter *start,
913 const GtkTextIter *end)
915 g_return_val_if_fail (start != NULL, NULL);
916 g_return_val_if_fail (end != NULL, NULL);
918 check_invariants (start);
919 check_invariants (end);
921 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
925 * gtk_text_iter_get_text:
926 * @start: iterator at start of a range
927 * @end: iterator at end of a range
929 * Returns <emphasis>text</emphasis> in the given range. If the range
930 * contains non-text elements such as images, the character and byte
931 * offsets in the returned string will not correspond to character and
932 * byte offsets in the buffer. If you want offsets to correspond, see
933 * gtk_text_iter_get_slice ().
935 * Return value: array of characters from the buffer
938 gtk_text_iter_get_text (const GtkTextIter *start,
939 const GtkTextIter *end)
941 g_return_val_if_fail (start != NULL, NULL);
942 g_return_val_if_fail (end != NULL, NULL);
944 check_invariants (start);
945 check_invariants (end);
947 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
951 * gtk_text_iter_get_visible_slice:
952 * @start: iterator at start of range
953 * @end: iterator at end of range
955 * Like gtk_text_iter_get_slice (), but invisible text is not included.
956 * Invisible text is usually invisible because a #GtkTextTag with the
957 * "invisible" attribute turned on has been applied to it.
959 * Return value: slice of text from the buffer
962 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
963 const GtkTextIter *end)
965 g_return_val_if_fail (start != NULL, NULL);
966 g_return_val_if_fail (end != NULL, NULL);
968 check_invariants (start);
969 check_invariants (end);
971 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
975 * gtk_text_iter_get_visible_text:
976 * @start: iterator at start of range
977 * @end: iterator at end of range
979 * Like gtk_text_iter_get_text (), but invisible text is not included.
980 * Invisible text is usually invisible because a #GtkTextTag with the
981 * "invisible" attribute turned on has been applied to it.
983 * Return value: string containing visible text in the range
986 gtk_text_iter_get_visible_text (const GtkTextIter *start,
987 const GtkTextIter *end)
989 g_return_val_if_fail (start != NULL, NULL);
990 g_return_val_if_fail (end != NULL, NULL);
992 check_invariants (start);
993 check_invariants (end);
995 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
999 * gtk_text_iter_get_pixbuf:
1000 * @iter: an iterator
1002 * If the element at @iter is a pixbuf, the pixbuf is returned
1003 * (with no new reference count added). Otherwise,
1004 * %NULL is returned.
1006 * Return value: the pixbuf at @iter
1009 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1011 GtkTextRealIter *real;
1013 g_return_val_if_fail (iter != NULL, NULL);
1015 real = gtk_text_iter_make_real (iter);
1020 check_invariants (iter);
1022 if (real->segment->type != >k_text_pixbuf_type)
1025 return real->segment->body.pixbuf.pixbuf;
1029 * gtk_text_iter_get_child_anchor:
1030 * @iter: an iterator
1032 * If the location at @iter contains a child anchor, the
1033 * anchor is returned (with no new reference count added). Otherwise,
1034 * %NULL is returned.
1036 * Return value: the anchor at @iter
1039 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1041 GtkTextRealIter *real;
1043 g_return_val_if_fail (iter != NULL, NULL);
1045 real = gtk_text_iter_make_real (iter);
1050 check_invariants (iter);
1052 if (real->segment->type != >k_text_child_type)
1055 return real->segment->body.child.obj;
1059 * gtk_text_iter_get_marks:
1060 * @iter: an iterator
1062 * Returns a list of all #GtkTextMark at this location. Because marks
1063 * are not iterable (they don't take up any "space" in the buffer,
1064 * they are just marks in between iterable locations), multiple marks
1065 * can exist in the same place. The returned list is not in any
1068 * Return value: list of #GtkTextMark
1071 gtk_text_iter_get_marks (const GtkTextIter *iter)
1073 GtkTextRealIter *real;
1074 GtkTextLineSegment *seg;
1077 g_return_val_if_fail (iter != NULL, NULL);
1079 real = gtk_text_iter_make_real (iter);
1084 check_invariants (iter);
1087 seg = real->any_segment;
1088 while (seg != real->segment)
1090 if (seg->type == >k_text_left_mark_type ||
1091 seg->type == >k_text_right_mark_type)
1092 retval = g_slist_prepend (retval, seg->body.mark.obj);
1097 /* The returned list isn't guaranteed to be in any special order,
1103 * gtk_text_iter_get_toggled_tags:
1104 * @iter: an iterator
1105 * @toggled_on: %TRUE to get toggled-on tags
1107 * Returns a list of #GtkTextTag that are toggled on or off at this
1108 * point. (If @toggled_on is %TRUE, the list contains tags that are
1109 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1110 * range of characters following @iter has that tag applied to it. If
1111 * a tag is toggled off, then some non-empty range following @iter
1112 * does <emphasis>not</emphasis> have the tag applied to it.
1114 * Return value: tags toggled at this point
1117 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1118 gboolean toggled_on)
1120 GtkTextRealIter *real;
1121 GtkTextLineSegment *seg;
1124 g_return_val_if_fail (iter != NULL, NULL);
1126 real = gtk_text_iter_make_real (iter);
1131 check_invariants (iter);
1134 seg = real->any_segment;
1135 while (seg != real->segment)
1139 if (seg->type == >k_text_toggle_on_type)
1141 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1146 if (seg->type == >k_text_toggle_off_type)
1148 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1155 /* The returned list isn't guaranteed to be in any special order,
1161 * gtk_text_iter_begins_tag:
1162 * @iter: an iterator
1163 * @tag: a #GtkTextTag, or %NULL
1165 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1166 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1167 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1168 * <emphasis>start</emphasis> of the tagged range;
1169 * gtk_text_iter_has_tag () tells you whether an iterator is
1170 * <emphasis>within</emphasis> a tagged range.
1172 * Return value: whether @iter is the start of a range tagged with @tag
1175 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1178 GtkTextRealIter *real;
1179 GtkTextLineSegment *seg;
1181 g_return_val_if_fail (iter != NULL, FALSE);
1183 real = gtk_text_iter_make_real (iter);
1188 check_invariants (iter);
1190 seg = real->any_segment;
1191 while (seg != real->segment)
1193 if (seg->type == >k_text_toggle_on_type)
1196 seg->body.toggle.info->tag == tag)
1207 * gtk_text_iter_ends_tag:
1208 * @iter: an iterator
1209 * @tag: a #GtkTextTag, or %NULL
1211 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1212 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1213 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1214 * <emphasis>end</emphasis> of the tagged range;
1215 * gtk_text_iter_has_tag () tells you whether an iterator is
1216 * <emphasis>within</emphasis> a tagged range.
1218 * Return value: whether @iter is the end of a range tagged with @tag
1222 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1225 GtkTextRealIter *real;
1226 GtkTextLineSegment *seg;
1228 g_return_val_if_fail (iter != NULL, FALSE);
1230 real = gtk_text_iter_make_real (iter);
1235 check_invariants (iter);
1237 seg = real->any_segment;
1238 while (seg != real->segment)
1240 if (seg->type == >k_text_toggle_off_type)
1243 seg->body.toggle.info->tag == tag)
1254 * gtk_text_iter_toggles_tag:
1255 * @iter: an iterator
1256 * @tag: a #GtkTextTag, or %NULL
1258 * This is equivalent to (gtk_text_iter_begins_tag () ||
1259 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1260 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1262 * Return value: whether @tag is toggled on or off at @iter
1265 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1268 GtkTextRealIter *real;
1269 GtkTextLineSegment *seg;
1271 g_return_val_if_fail (iter != NULL, FALSE);
1273 real = gtk_text_iter_make_real (iter);
1278 check_invariants (iter);
1280 seg = real->any_segment;
1281 while (seg != real->segment)
1283 if ( (seg->type == >k_text_toggle_off_type ||
1284 seg->type == >k_text_toggle_on_type) &&
1286 seg->body.toggle.info->tag == tag) )
1296 * gtk_text_iter_has_tag:
1297 * @iter: an iterator
1298 * @tag: a #GtkTextTag
1300 * Returns %TRUE if @iter is within a range tagged with @tag.
1302 * Return value: whether @iter is tagged with @tag
1305 gtk_text_iter_has_tag (const GtkTextIter *iter,
1308 GtkTextRealIter *real;
1310 g_return_val_if_fail (iter != NULL, FALSE);
1311 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1313 real = gtk_text_iter_make_surreal (iter);
1318 check_invariants (iter);
1320 if (real->line_byte_offset >= 0)
1322 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1323 real->line_byte_offset, tag);
1327 g_assert (real->line_char_offset >= 0);
1328 return _gtk_text_line_char_has_tag (real->line, real->tree,
1329 real->line_char_offset, tag);
1334 * gtk_text_iter_get_tags:
1335 * @iter: a #GtkTextIter
1337 * Returns a list of tags that apply to @iter, in ascending order of
1338 * priority (highest-priority tags are last). The #GtkTextTag in the
1339 * list don't have a reference added, but you have to free the list
1342 * Return value: list of #GtkTextTag
1345 gtk_text_iter_get_tags (const GtkTextIter *iter)
1352 g_return_val_if_fail (iter != NULL, NULL);
1354 /* Get the tags at this spot */
1355 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1357 /* No tags, use default style */
1358 if (tags == NULL || tag_count == 0)
1366 /* Sort tags in ascending order of priority */
1367 _gtk_text_tag_array_sort (tags, tag_count);
1371 while (i < tag_count)
1373 retval = g_slist_prepend (retval, tags[i]);
1379 /* Return tags in ascending order of priority */
1380 return g_slist_reverse (retval);
1384 * gtk_text_iter_editable:
1385 * @iter: an iterator
1386 * @default_setting: %TRUE if text is editable by default
1388 * Returns whether the character at @iter is within an editable region
1389 * of text. Non-editable text is "locked" and can't be changed by the
1390 * user via #GtkTextView. This function is simply a convenience
1391 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1392 * to this text affect editability, @default_setting will be returned.
1394 * You don't want to use this function to decide whether text can be
1395 * inserted at @iter, because for insertion you don't want to know
1396 * whether the char at @iter is inside an editable range, you want to
1397 * know whether a new character inserted at @iter would be inside an
1398 * editable range. Use gtk_text_iter_can_insert() to handle this
1401 * Return value: whether @iter is inside an editable range
1404 gtk_text_iter_editable (const GtkTextIter *iter,
1405 gboolean default_setting)
1407 GtkTextAttributes *values;
1410 g_return_val_if_fail (iter != NULL, FALSE);
1412 values = gtk_text_attributes_new ();
1414 values->editable = default_setting;
1416 gtk_text_iter_get_attributes (iter, values);
1418 retval = values->editable;
1420 gtk_text_attributes_unref (values);
1426 * gtk_text_iter_can_insert:
1427 * @iter: an iterator
1428 * @default_editability: %TRUE if text is editable by default
1430 * Considering the default editability of the buffer, and tags that
1431 * affect editability, determines whether text inserted at @iter would
1432 * be editable. If text inserted at @iter would be editable then the
1433 * user should be allowed to insert text at @iter.
1434 * gtk_text_buffer_insert_interactive() uses this function to decide
1435 * whether insertions are allowed at a given position.
1437 * Return value: whether text inserted at @iter would be editable
1440 gtk_text_iter_can_insert (const GtkTextIter *iter,
1441 gboolean default_editability)
1443 g_return_val_if_fail (iter != NULL, FALSE);
1445 if (gtk_text_iter_editable (iter, default_editability))
1447 /* If at start/end of buffer, default editability is used */
1448 else if ((gtk_text_iter_is_start (iter) ||
1449 gtk_text_iter_is_end (iter)) &&
1450 default_editability)
1454 /* if iter isn't editable, and the char before iter is,
1455 * then iter is the first char in an editable region
1456 * and thus insertion at iter results in editable text.
1458 GtkTextIter prev = *iter;
1459 gtk_text_iter_backward_char (&prev);
1460 return gtk_text_iter_editable (&prev, default_editability);
1466 * gtk_text_iter_get_language:
1467 * @iter: an iterator
1469 * A convenience wrapper around gtk_text_iter_get_attributes (),
1470 * which returns the language in effect at @iter. If no tags affecting
1471 * language apply to @iter, the return value is identical to that of
1472 * gtk_get_default_language ().
1474 * Return value: language in effect at @iter
1477 gtk_text_iter_get_language (const GtkTextIter *iter)
1479 GtkTextAttributes *values;
1480 PangoLanguage *retval;
1482 values = gtk_text_attributes_new ();
1484 gtk_text_iter_get_attributes (iter, values);
1486 retval = values->language;
1488 gtk_text_attributes_unref (values);
1494 * gtk_text_iter_starts_line:
1495 * @iter: an iterator
1497 * Returns %TRUE if @iter begins a paragraph,
1498 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1499 * However this function is potentially more efficient than
1500 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1501 * the offset, it just has to see whether it's 0.
1503 * Return value: whether @iter begins a line
1506 gtk_text_iter_starts_line (const GtkTextIter *iter)
1508 GtkTextRealIter *real;
1510 g_return_val_if_fail (iter != NULL, FALSE);
1512 real = gtk_text_iter_make_surreal (iter);
1517 check_invariants (iter);
1519 if (real->line_byte_offset >= 0)
1521 return (real->line_byte_offset == 0);
1525 g_assert (real->line_char_offset >= 0);
1526 return (real->line_char_offset == 0);
1531 * gtk_text_iter_ends_line:
1532 * @iter: an iterator
1534 * Returns %TRUE if @iter points to the start of the paragraph
1535 * delimiter characters for a line (delimiters will be either a
1536 * newline, a carriage return, a carriage return followed by a
1537 * newline, or a Unicode paragraph separator character). Note that an
1538 * iterator pointing to the \n of a \r\n pair will not be counted as
1539 * the end of a line, the line ends before the \r. The end iterator is
1540 * considered to be at the end of a line, even though there are no
1541 * paragraph delimiter chars there.
1543 * Return value: whether @iter is at the end of a line
1546 gtk_text_iter_ends_line (const GtkTextIter *iter)
1548 GtkTextRealIter *real;
1551 g_return_val_if_fail (iter != NULL, FALSE);
1553 real = gtk_text_iter_make_real (iter);
1555 check_invariants (iter);
1557 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1558 * Unicode 3.0; update this if that changes.
1560 #define PARAGRAPH_SEPARATOR 0x2029
1562 wc = gtk_text_iter_get_char (iter);
1564 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1566 else if (wc == '\n')
1568 /* need to determine if a \r precedes the \n, in which case
1569 * we aren't the end of the line
1571 GtkTextIter tmp = *iter;
1572 if (!gtk_text_iter_backward_char (&tmp))
1575 return gtk_text_iter_get_char (&tmp) != '\r';
1582 * gtk_text_iter_is_end:
1583 * @iter: an iterator
1585 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1586 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1587 * the most efficient way to check whether an iterator is the end
1590 * Return value: whether @iter is the end iterator
1593 gtk_text_iter_is_end (const GtkTextIter *iter)
1595 GtkTextRealIter *real;
1597 g_return_val_if_fail (iter != NULL, FALSE);
1599 real = gtk_text_iter_make_surreal (iter);
1604 check_invariants (iter);
1606 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1609 /* Now we need the segments validated */
1610 real = gtk_text_iter_make_real (iter);
1615 return _gtk_text_btree_is_end (real->tree, real->line,
1617 real->segment_byte_offset,
1618 real->segment_char_offset);
1622 * gtk_text_iter_is_start:
1623 * @iter: an iterator
1625 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1626 * if @iter has a character offset of 0.
1628 * Return value: whether @iter is the first in the buffer
1631 gtk_text_iter_is_start (const GtkTextIter *iter)
1633 return gtk_text_iter_get_offset (iter) == 0;
1637 * gtk_text_iter_get_chars_in_line:
1638 * @iter: an iterator
1640 * Returns the number of characters in the line containing @iter,
1641 * including the paragraph delimiters.
1643 * Return value: number of characters in the line
1646 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1648 GtkTextRealIter *real;
1650 GtkTextLineSegment *seg;
1652 g_return_val_if_fail (iter != NULL, FALSE);
1654 real = gtk_text_iter_make_surreal (iter);
1659 check_invariants (iter);
1661 if (real->line_char_offset >= 0)
1663 /* We can start at the segments we've already found. */
1664 count = real->line_char_offset - real->segment_char_offset;
1665 seg = _gtk_text_iter_get_indexable_segment (iter);
1669 /* count whole line. */
1670 seg = real->line->segments;
1677 count += seg->char_count;
1682 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1683 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1689 * gtk_text_iter_get_bytes_in_line:
1690 * @iter: an iterator
1692 * Returns the number of bytes in the line containing @iter,
1693 * including the paragraph delimiters.
1695 * Return value: number of bytes in the line
1698 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1700 GtkTextRealIter *real;
1702 GtkTextLineSegment *seg;
1704 g_return_val_if_fail (iter != NULL, FALSE);
1706 real = gtk_text_iter_make_surreal (iter);
1711 check_invariants (iter);
1713 if (real->line_byte_offset >= 0)
1715 /* We can start at the segments we've already found. */
1716 count = real->line_byte_offset - real->segment_byte_offset;
1717 seg = _gtk_text_iter_get_indexable_segment (iter);
1721 /* count whole line. */
1722 seg = real->line->segments;
1728 count += seg->byte_count;
1733 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1734 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1740 * gtk_text_iter_get_attributes:
1741 * @iter: an iterator
1742 * @values: a #GtkTextAttributes to be filled in
1744 * Computes the effect of any tags applied to this spot in the
1745 * text. The @values parameter should be initialized to the default
1746 * settings you wish to use if no tags are in effect. You'd typically
1747 * obtain the defaults from gtk_text_view_get_default_attributes().
1749 * gtk_text_iter_get_attributes () will modify @values, applying the
1750 * effects of any tags present at @iter. If any tags affected @values,
1751 * the function returns %TRUE.
1753 * Return value: %TRUE if @values was modified
1756 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1757 GtkTextAttributes *values)
1762 /* Get the tags at this spot */
1763 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1765 /* No tags, use default style */
1766 if (tags == NULL || tag_count == 0)
1774 /* Sort tags in ascending order of priority */
1775 _gtk_text_tag_array_sort (tags, tag_count);
1777 _gtk_text_attributes_fill_from_tags (values,
1787 * Increments/decrements
1790 /* The return value of this indicates WHETHER WE MOVED.
1791 * The return value of public functions indicates
1792 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1794 * This function will not change the iterator if
1795 * it's already on the last (end iter) line, i.e. it
1796 * won't move to the end of the last line.
1799 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1801 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1803 GtkTextLine *new_line;
1805 new_line = _gtk_text_line_next (real->line);
1806 g_assert (new_line);
1807 g_assert (new_line != real->line);
1808 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1810 real->line = new_line;
1812 real->line_byte_offset = 0;
1813 real->line_char_offset = 0;
1815 real->segment_byte_offset = 0;
1816 real->segment_char_offset = 0;
1818 /* Find first segments in new line */
1819 real->any_segment = real->line->segments;
1820 real->segment = real->any_segment;
1821 while (real->segment->char_count == 0)
1822 real->segment = real->segment->next;
1828 /* There is no way to move forward a line; we were already at
1829 * the line containing the end iterator.
1830 * However we may not be at the end iterator itself.
1838 /* The return value of this indicates WHETHER WE MOVED.
1839 * The return value of public functions indicates
1840 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1842 * This function is currently unused, thus it is #if-0-ed. It is
1843 * left here, since it's non-trivial code that might be useful in
1847 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1849 GtkTextLine *new_line;
1851 new_line = _gtk_text_line_previous (real->line);
1853 g_assert (new_line != real->line);
1855 if (new_line != NULL)
1857 real->line = new_line;
1859 real->line_byte_offset = 0;
1860 real->line_char_offset = 0;
1862 real->segment_byte_offset = 0;
1863 real->segment_char_offset = 0;
1865 /* Find first segments in new line */
1866 real->any_segment = real->line->segments;
1867 real->segment = real->any_segment;
1868 while (real->segment->char_count == 0)
1869 real->segment = real->segment->next;
1875 /* There is no way to move backward; we were already
1876 at the first line. */
1878 /* We leave real->line as-is */
1880 /* Note that we didn't clamp to the start of the first line. */
1887 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1891 forward_char (GtkTextRealIter *real)
1893 GtkTextIter *iter = (GtkTextIter*)real;
1895 check_invariants ((GtkTextIter*)real);
1897 ensure_char_offsets (real);
1899 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1901 /* Need to move to the next segment; if no next segment,
1902 need to move to next line. */
1903 return _gtk_text_iter_forward_indexable_segment (iter);
1907 /* Just moving within a segment. Keep byte count
1908 up-to-date, if it was already up-to-date. */
1910 g_assert (real->segment->type == >k_text_char_type);
1912 if (real->line_byte_offset >= 0)
1915 const char * start =
1916 real->segment->body.chars + real->segment_byte_offset;
1918 bytes = g_utf8_next_char (start) - start;
1920 real->line_byte_offset += bytes;
1921 real->segment_byte_offset += bytes;
1923 g_assert (real->segment_byte_offset < real->segment->byte_count);
1926 real->line_char_offset += 1;
1927 real->segment_char_offset += 1;
1929 adjust_char_index (real, 1);
1931 g_assert (real->segment_char_offset < real->segment->char_count);
1933 /* We moved into the middle of a segment, so the any_segment
1934 must now be the segment we're in the middle of. */
1935 real->any_segment = real->segment;
1937 check_invariants ((GtkTextIter*)real);
1939 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1947 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1949 /* Need to move to the next segment; if no next segment,
1950 need to move to next line. */
1951 GtkTextLineSegment *seg;
1952 GtkTextLineSegment *any_seg;
1953 GtkTextRealIter *real;
1957 g_return_val_if_fail (iter != NULL, FALSE);
1959 real = gtk_text_iter_make_real (iter);
1964 check_invariants (iter);
1966 if (real->line_char_offset >= 0)
1968 chars_skipped = real->segment->char_count - real->segment_char_offset;
1969 g_assert (chars_skipped > 0);
1974 if (real->line_byte_offset >= 0)
1976 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1977 g_assert (bytes_skipped > 0);
1982 /* Get first segment of any kind */
1983 any_seg = real->segment->next;
1984 /* skip non-indexable segments, if any */
1986 while (seg != NULL && seg->char_count == 0)
1991 real->any_segment = any_seg;
1992 real->segment = seg;
1994 if (real->line_byte_offset >= 0)
1996 g_assert (bytes_skipped > 0);
1997 real->segment_byte_offset = 0;
1998 real->line_byte_offset += bytes_skipped;
2001 if (real->line_char_offset >= 0)
2003 g_assert (chars_skipped > 0);
2004 real->segment_char_offset = 0;
2005 real->line_char_offset += chars_skipped;
2006 adjust_char_index (real, chars_skipped);
2009 check_invariants (iter);
2011 return !gtk_text_iter_is_end (iter);
2015 /* End of the line */
2016 if (forward_line_leaving_caches_unmodified (real))
2018 adjust_line_number (real, 1);
2019 if (real->line_char_offset >= 0)
2020 adjust_char_index (real, chars_skipped);
2022 g_assert (real->line_byte_offset == 0);
2023 g_assert (real->line_char_offset == 0);
2024 g_assert (real->segment_byte_offset == 0);
2025 g_assert (real->segment_char_offset == 0);
2026 g_assert (gtk_text_iter_starts_line (iter));
2028 check_invariants (iter);
2030 return !gtk_text_iter_is_end (iter);
2034 /* End of buffer, but iter is still at start of last segment,
2035 * not at the end iterator. We put it on the end iterator.
2038 check_invariants (iter);
2040 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2041 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2043 gtk_text_iter_forward_to_line_end (iter);
2045 g_assert (gtk_text_iter_is_end (iter));
2053 at_last_indexable_segment (GtkTextRealIter *real)
2055 GtkTextLineSegment *seg;
2057 /* Return TRUE if there are no indexable segments after
2061 seg = real->segment->next;
2064 if (seg->char_count > 0)
2071 /* Goes back to the start of the next segment, even if
2072 * we're not at the start of the current segment (always
2073 * ends up on a different segment if it returns TRUE)
2076 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2078 /* Move to the start of the previous segment; if no previous
2079 * segment, to the last segment in the previous line. This is
2080 * inherently a bit inefficient due to the singly-linked list and
2081 * tree nodes, but we can't afford the RAM for doubly-linked.
2083 GtkTextRealIter *real;
2084 GtkTextLineSegment *seg;
2085 GtkTextLineSegment *any_seg;
2086 GtkTextLineSegment *prev_seg;
2087 GtkTextLineSegment *prev_any_seg;
2091 g_return_val_if_fail (iter != NULL, FALSE);
2093 real = gtk_text_iter_make_real (iter);
2098 check_invariants (iter);
2100 /* Find first segments in line */
2101 any_seg = real->line->segments;
2103 while (seg->char_count == 0)
2106 if (seg == real->segment)
2108 /* Could probably do this case faster by hand-coding the
2112 /* We were already at the start of a line;
2113 * go back to the previous line.
2115 if (gtk_text_iter_backward_line (iter))
2117 /* Go forward to last indexable segment in line. */
2118 while (!at_last_indexable_segment (real))
2119 _gtk_text_iter_forward_indexable_segment (iter);
2121 check_invariants (iter);
2126 return FALSE; /* We were at the start of the first line. */
2129 /* We must be in the middle of a line; so find the indexable
2130 * segment just before our current segment.
2132 g_assert (seg != real->segment);
2136 prev_any_seg = any_seg;
2138 any_seg = seg->next;
2140 while (seg->char_count == 0)
2143 while (seg != real->segment);
2145 g_assert (prev_seg != NULL);
2146 g_assert (prev_any_seg != NULL);
2147 g_assert (prev_seg->char_count > 0);
2149 /* We skipped the entire previous segment, plus any
2150 * chars we were into the current segment.
2152 if (real->segment_byte_offset >= 0)
2153 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2157 if (real->segment_char_offset >= 0)
2158 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2162 real->segment = prev_seg;
2163 real->any_segment = prev_any_seg;
2164 real->segment_byte_offset = 0;
2165 real->segment_char_offset = 0;
2167 if (bytes_skipped >= 0)
2169 if (real->line_byte_offset >= 0)
2171 real->line_byte_offset -= bytes_skipped;
2172 g_assert (real->line_byte_offset >= 0);
2176 real->line_byte_offset = -1;
2178 if (chars_skipped >= 0)
2180 if (real->line_char_offset >= 0)
2182 real->line_char_offset -= chars_skipped;
2183 g_assert (real->line_char_offset >= 0);
2186 if (real->cached_char_index >= 0)
2188 real->cached_char_index -= chars_skipped;
2189 g_assert (real->cached_char_index >= 0);
2194 real->line_char_offset = -1;
2195 real->cached_char_index = -1;
2198 /* line number is unchanged. */
2200 check_invariants (iter);
2206 * gtk_text_iter_forward_char:
2207 * @iter: an iterator
2209 * Moves @iter forward by one character offset. Note that images
2210 * embedded in the buffer occupy 1 character slot, so
2211 * gtk_text_iter_forward_char () may actually move onto an image instead
2212 * of a character, if you have images in your buffer. If @iter is the
2213 * end iterator or one character before it, @iter will now point at
2214 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2215 * convenience when writing loops.
2217 * Return value: whether @iter moved and is dereferenceable
2220 gtk_text_iter_forward_char (GtkTextIter *iter)
2222 GtkTextRealIter *real;
2224 g_return_val_if_fail (iter != NULL, FALSE);
2226 real = gtk_text_iter_make_real (iter);
2232 check_invariants (iter);
2233 return forward_char (real);
2238 * gtk_text_iter_backward_char:
2239 * @iter: an iterator
2241 * Moves backward by one character offset. Returns %TRUE if movement
2242 * was possible; if @iter was the first in the buffer (character
2243 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2246 * Return value: whether movement was possible
2249 gtk_text_iter_backward_char (GtkTextIter *iter)
2251 g_return_val_if_fail (iter != NULL, FALSE);
2253 check_invariants (iter);
2255 return gtk_text_iter_backward_chars (iter, 1);
2259 Definitely we should try to linear scan as often as possible for
2260 movement within a single line, because we can't use the BTree to
2261 speed within-line searches up; for movement between lines, we would
2262 like to avoid the linear scan probably.
2264 Instead of using this constant, it might be nice to cache the line
2265 length in the iterator and linear scan if motion is within a single
2268 I guess you'd have to profile the various approaches.
2270 #define MAX_LINEAR_SCAN 150
2274 * gtk_text_iter_forward_chars:
2275 * @iter: an iterator
2276 * @count: number of characters to move, may be negative
2278 * Moves @count characters if possible (if @count would move past the
2279 * start or end of the buffer, moves to the start or end of the
2280 * buffer). The return value indicates whether the new position of
2281 * @iter is different from its original position, and dereferenceable
2282 * (the last iterator in the buffer is not dereferenceable). If @count
2283 * is 0, the function does nothing and returns %FALSE.
2285 * Return value: whether @iter moved and is dereferenceable
2288 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2290 GtkTextRealIter *real;
2292 g_return_val_if_fail (iter != NULL, FALSE);
2294 FIX_OVERFLOWS (count);
2296 real = gtk_text_iter_make_real (iter);
2300 else if (count == 0)
2303 return gtk_text_iter_backward_chars (iter, 0 - count);
2304 else if (count < MAX_LINEAR_SCAN)
2306 check_invariants (iter);
2310 if (!forward_char (real))
2315 return forward_char (real);
2319 gint current_char_index;
2320 gint new_char_index;
2322 check_invariants (iter);
2324 current_char_index = gtk_text_iter_get_offset (iter);
2326 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2327 return FALSE; /* can't move forward */
2329 new_char_index = current_char_index + count;
2330 gtk_text_iter_set_offset (iter, new_char_index);
2332 check_invariants (iter);
2334 /* Return FALSE if we're on the non-dereferenceable end
2337 if (gtk_text_iter_is_end (iter))
2345 * gtk_text_iter_backward_chars:
2346 * @iter: an iterator
2347 * @count: number of characters to move
2349 * Moves @count characters backward, if possible (if @count would move
2350 * past the start or end of the buffer, moves to the start or end of
2351 * the buffer). The return value indicates whether the iterator moved
2352 * onto a dereferenceable position; if the iterator didn't move, or
2353 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2354 * the function does nothing and returns %FALSE.
2356 * Return value: whether @iter moved and is dereferenceable
2360 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2362 GtkTextRealIter *real;
2364 g_return_val_if_fail (iter != NULL, FALSE);
2366 FIX_OVERFLOWS (count);
2368 real = gtk_text_iter_make_real (iter);
2372 else if (count == 0)
2375 return gtk_text_iter_forward_chars (iter, 0 - count);
2377 ensure_char_offsets (real);
2378 check_invariants (iter);
2380 /* <, not <=, because if count == segment_char_offset
2381 * we're going to the front of the segment and the any_segment
2384 if (count < real->segment_char_offset)
2386 /* Optimize the within-segment case */
2387 g_assert (real->segment->char_count > 0);
2388 g_assert (real->segment->type == >k_text_char_type);
2390 real->segment_char_offset -= count;
2391 g_assert (real->segment_char_offset >= 0);
2393 if (real->line_byte_offset >= 0)
2395 gint new_byte_offset;
2398 new_byte_offset = 0;
2400 while (i < real->segment_char_offset)
2402 const char * start = real->segment->body.chars + new_byte_offset;
2403 new_byte_offset += g_utf8_next_char (start) - start;
2408 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2409 real->segment_byte_offset = new_byte_offset;
2412 real->line_char_offset -= count;
2414 adjust_char_index (real, 0 - count);
2416 check_invariants (iter);
2422 /* We need to go back into previous segments. For now,
2423 * just keep this really simple. FIXME
2424 * use backward_indexable_segment.
2426 if (TRUE || count > MAX_LINEAR_SCAN)
2428 gint current_char_index;
2429 gint new_char_index;
2431 current_char_index = gtk_text_iter_get_offset (iter);
2433 if (current_char_index == 0)
2434 return FALSE; /* can't move backward */
2436 new_char_index = current_char_index - count;
2437 if (new_char_index < 0)
2440 gtk_text_iter_set_offset (iter, new_char_index);
2442 check_invariants (iter);
2448 /* FIXME backward_indexable_segment here */
2457 /* These two can't be implemented efficiently (always have to use
2458 * a linear scan, since that's the only way to find all the non-text
2463 * gtk_text_iter_forward_text_chars:
2464 * @iter: a #GtkTextIter
2465 * @count: number of chars to move
2467 * Moves forward by @count text characters (pixbufs, widgets,
2468 * etc. do not count as characters for this). Equivalent to moving
2469 * through the results of gtk_text_iter_get_text (), rather than
2470 * gtk_text_iter_get_slice ().
2472 * Return value: whether @iter moved and is dereferenceable
2475 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2484 * gtk_text_iter_forward_text_chars:
2485 * @iter: a #GtkTextIter
2486 * @count: number of chars to move
2488 * Moves backward by @count text characters (pixbufs, widgets,
2489 * etc. do not count as characters for this). Equivalent to moving
2490 * through the results of gtk_text_iter_get_text (), rather than
2491 * gtk_text_iter_get_slice ().
2493 * Return value: whether @iter moved and is dereferenceable
2496 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2505 * gtk_text_iter_forward_line:
2506 * @iter: an iterator
2508 * Moves @iter to the start of the next line. Returns %TRUE if there
2509 * was a next line to move to, and %FALSE if @iter was simply moved to
2510 * the end of the buffer and is now not dereferenceable, or if @iter was
2511 * already at the end of the buffer.
2513 * Return value: whether @iter can be dereferenced
2516 gtk_text_iter_forward_line (GtkTextIter *iter)
2518 GtkTextRealIter *real;
2520 g_return_val_if_fail (iter != NULL, FALSE);
2522 real = gtk_text_iter_make_real (iter);
2527 check_invariants (iter);
2529 if (forward_line_leaving_caches_unmodified (real))
2531 invalidate_char_index (real);
2532 adjust_line_number (real, 1);
2534 check_invariants (iter);
2536 if (gtk_text_iter_is_end (iter))
2543 /* On the last line, move to end of it */
2545 if (!gtk_text_iter_is_end (iter))
2546 gtk_text_iter_forward_to_end (iter);
2548 check_invariants (iter);
2554 * gtk_text_iter_backward_line:
2555 * @iter: an iterator
2557 * Moves @iter to the start of the previous line. Returns %TRUE if
2558 * @iter could be moved; i.e. if @iter was at character offset 0, this
2559 * function returns %FALSE. Therefore if @iter was already on line 0,
2560 * but not at the start of the line, @iter is snapped to the start of
2561 * the line and the function returns %TRUE. (Note that this implies that
2562 * in a loop calling this function, the line number may not change on
2563 * every iteration, if your first iteration is on line 0.)
2565 * Return value: whether @iter moved
2568 gtk_text_iter_backward_line (GtkTextIter *iter)
2570 GtkTextLine *new_line;
2571 GtkTextRealIter *real;
2572 gboolean offset_will_change;
2575 g_return_val_if_fail (iter != NULL, FALSE);
2577 real = gtk_text_iter_make_real (iter);
2582 check_invariants (iter);
2584 new_line = _gtk_text_line_previous (real->line);
2586 offset_will_change = FALSE;
2587 if (real->line_char_offset > 0)
2588 offset_will_change = TRUE;
2590 if (new_line != NULL)
2592 real->line = new_line;
2594 adjust_line_number (real, -1);
2598 if (!offset_will_change)
2602 invalidate_char_index (real);
2604 real->line_byte_offset = 0;
2605 real->line_char_offset = 0;
2607 real->segment_byte_offset = 0;
2608 real->segment_char_offset = 0;
2610 /* Find first segment in line */
2611 real->any_segment = real->line->segments;
2612 real->segment = _gtk_text_line_byte_to_segment (real->line,
2615 g_assert (offset == 0);
2617 /* Note that if we are on the first line, we snap to the start of
2618 * the first line and return TRUE, so TRUE means the iterator
2619 * changed, not that the line changed; this is maybe a bit
2620 * weird. I'm not sure there's an obvious right thing to do though.
2623 check_invariants (iter);
2630 * gtk_text_iter_forward_lines:
2631 * @iter: a #GtkTextIter
2632 * @count: number of lines to move forward
2634 * Moves @count lines forward, if possible (if @count would move
2635 * past the start or end of the buffer, moves to the start or end of
2636 * the buffer). The return value indicates whether the iterator moved
2637 * onto a dereferenceable position; if the iterator didn't move, or
2638 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2639 * the function does nothing and returns %FALSE. If @count is negative,
2640 * moves backward by 0 - @count lines.
2642 * Return value: whether @iter moved and is dereferenceable
2645 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2647 FIX_OVERFLOWS (count);
2650 return gtk_text_iter_backward_lines (iter, 0 - count);
2651 else if (count == 0)
2653 else if (count == 1)
2655 check_invariants (iter);
2656 return gtk_text_iter_forward_line (iter);
2662 if (gtk_text_iter_is_end (iter))
2665 old_line = gtk_text_iter_get_line (iter);
2667 gtk_text_iter_set_line (iter, old_line + count);
2669 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2671 /* count went past the last line, so move to end of last line */
2672 if (!gtk_text_iter_is_end (iter))
2673 gtk_text_iter_forward_to_end (iter);
2676 return !gtk_text_iter_is_end (iter);
2681 * gtk_text_iter_backward_lines:
2682 * @iter: a #GtkTextIter
2683 * @count: number of lines to move backward
2685 * Moves @count lines backward, if possible (if @count would move
2686 * past the start or end of the buffer, moves to the start or end of
2687 * the buffer). The return value indicates whether the iterator moved
2688 * onto a dereferenceable position; if the iterator didn't move, or
2689 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2690 * the function does nothing and returns %FALSE. If @count is negative,
2691 * moves forward by 0 - @count lines.
2693 * Return value: whether @iter moved and is dereferenceable
2696 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2698 FIX_OVERFLOWS (count);
2701 return gtk_text_iter_forward_lines (iter, 0 - count);
2702 else if (count == 0)
2704 else if (count == 1)
2706 return gtk_text_iter_backward_line (iter);
2712 old_line = gtk_text_iter_get_line (iter);
2714 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2716 return (gtk_text_iter_get_line (iter) != old_line);
2720 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2725 gboolean already_moved_initially);
2727 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2735 find_word_end_func (const PangoLogAttr *attrs,
2740 gboolean already_moved_initially)
2742 if (!already_moved_initially)
2745 /* Find end of next word */
2746 while (offset < min_offset + len &&
2747 !attrs[offset].is_word_end)
2750 *found_offset = offset;
2752 return offset < min_offset + len;
2756 is_word_end_func (const PangoLogAttr *attrs,
2761 return attrs[offset].is_word_end;
2765 find_word_start_func (const PangoLogAttr *attrs,
2770 gboolean already_moved_initially)
2772 if (!already_moved_initially)
2775 /* Find start of prev word */
2776 while (offset >= min_offset &&
2777 !attrs[offset].is_word_start)
2780 *found_offset = offset;
2782 return offset >= min_offset;
2786 is_word_start_func (const PangoLogAttr *attrs,
2791 return attrs[offset].is_word_start;
2795 inside_word_func (const PangoLogAttr *attrs,
2800 /* Find next word start or end */
2801 while (offset >= min_offset &&
2802 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2805 return attrs[offset].is_word_start;
2808 /* Sentence funcs */
2811 find_sentence_end_func (const PangoLogAttr *attrs,
2816 gboolean already_moved_initially)
2818 if (!already_moved_initially)
2821 /* Find end of next sentence */
2822 while (offset < min_offset + len &&
2823 !attrs[offset].is_sentence_end)
2826 *found_offset = offset;
2828 return offset < min_offset + len;
2832 is_sentence_end_func (const PangoLogAttr *attrs,
2837 return attrs[offset].is_sentence_end;
2841 find_sentence_start_func (const PangoLogAttr *attrs,
2846 gboolean already_moved_initially)
2848 if (!already_moved_initially)
2851 /* Find start of prev sentence */
2852 while (offset >= min_offset &&
2853 !attrs[offset].is_sentence_start)
2856 *found_offset = offset;
2858 return offset >= min_offset;
2862 is_sentence_start_func (const PangoLogAttr *attrs,
2867 return attrs[offset].is_sentence_start;
2871 inside_sentence_func (const PangoLogAttr *attrs,
2876 /* Find next sentence start or end */
2877 while (offset >= min_offset &&
2878 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2881 return attrs[offset].is_sentence_start;
2885 test_log_attrs (const GtkTextIter *iter,
2886 TestLogAttrFunc func)
2889 const PangoLogAttr *attrs;
2891 gboolean result = FALSE;
2893 g_return_val_if_fail (iter != NULL, FALSE);
2895 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2898 offset = gtk_text_iter_get_line_offset (iter);
2900 /* char_len may be 0 and attrs will be NULL if so, if
2901 * iter is the end iter and the last line is empty.
2903 * offset may be equal to char_len, since attrs contains an entry
2904 * for one past the end
2907 if (attrs && offset <= char_len)
2908 result = (* func) (attrs, offset, 0, char_len);
2914 find_line_log_attrs (const GtkTextIter *iter,
2915 FindLogAttrFunc func,
2917 gboolean already_moved_initially)
2920 const PangoLogAttr *attrs;
2922 gboolean result = FALSE;
2924 g_return_val_if_fail (iter != NULL, FALSE);
2926 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2929 offset = gtk_text_iter_get_line_offset (iter);
2931 /* char_len may be 0 and attrs will be NULL if so, if
2932 * iter is the end iter and the last line is empty
2936 result = (* func) (attrs, offset, 0, char_len, found_offset,
2937 already_moved_initially);
2942 /* FIXME this function is very, very gratuitously slow */
2944 find_by_log_attrs (GtkTextIter *iter,
2945 FindLogAttrFunc func,
2947 gboolean already_moved_initially)
2951 gboolean found = FALSE;
2953 g_return_val_if_fail (iter != NULL, FALSE);
2957 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2963 if (gtk_text_iter_forward_line (iter))
2964 return find_by_log_attrs (iter, func, forward,
2971 /* go to end of previous line. need to check that
2972 * line is > 0 because backward_line snaps to start of
2973 * line 0 if it's on line 0
2975 if (gtk_text_iter_get_line (iter) > 0 &&
2976 gtk_text_iter_backward_line (iter))
2978 if (!gtk_text_iter_ends_line (iter))
2979 gtk_text_iter_forward_to_line_end (iter);
2981 return find_by_log_attrs (iter, func, forward,
2990 gtk_text_iter_set_line_offset (iter, offset);
2993 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2994 !gtk_text_iter_is_end (iter);
2999 find_visible_by_log_attrs (GtkTextIter *iter,
3000 FindLogAttrFunc func,
3002 gboolean already_moved_initially)
3006 g_return_val_if_fail (iter != NULL, FALSE);
3010 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3012 if (!_gtk_text_btree_char_is_invisible (&pos))
3022 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3023 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3026 move_multiple_steps (GtkTextIter *iter,
3028 OneStepFunc step_forward,
3029 MultipleStepFunc n_steps_backward)
3031 g_return_val_if_fail (iter != NULL, FALSE);
3033 FIX_OVERFLOWS (count);
3039 return n_steps_backward (iter, -count);
3041 if (!step_forward (iter))
3047 if (!step_forward (iter))
3052 return !gtk_text_iter_is_end (iter);
3057 * gtk_text_iter_forward_word_end:
3058 * @iter: a #GtkTextIter
3060 * Moves forward to the next word end. (If @iter is currently on a
3061 * word end, moves forward to the next one after that.) Word breaks
3062 * are determined by Pango and should be correct for nearly any
3063 * language (if not, the correct fix would be to the Pango word break
3066 * Return value: %TRUE if @iter moved and is not the end iterator
3069 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3071 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3075 * gtk_text_iter_backward_word_start:
3076 * @iter: a #GtkTextIter
3078 * Moves backward to the previous word start. (If @iter is currently on a
3079 * word start, moves backward to the next one after that.) Word breaks
3080 * are determined by Pango and should be correct for nearly any
3081 * language (if not, the correct fix would be to the Pango word break
3084 * Return value: %TRUE if @iter moved and is not the end iterator
3087 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3089 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3092 /* FIXME a loop around a truly slow function means
3093 * a truly spectacularly slow function.
3097 * gtk_text_iter_forward_word_ends:
3098 * @iter: a #GtkTextIter
3099 * @count: number of times to move
3101 * Calls gtk_text_iter_forward_word_end() up to @count times.
3103 * Return value: %TRUE if @iter moved and is not the end iterator
3106 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3109 return move_multiple_steps (iter, count,
3110 gtk_text_iter_forward_word_end,
3111 gtk_text_iter_backward_word_starts);
3115 * gtk_text_iter_backward_word_starts
3116 * @iter: a #GtkTextIter
3117 * @count: number of times to move
3119 * Calls gtk_text_iter_backward_word_start() up to @count times.
3121 * Return value: %TRUE if @iter moved and is not the end iterator
3124 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3127 return move_multiple_steps (iter, count,
3128 gtk_text_iter_backward_word_start,
3129 gtk_text_iter_forward_word_ends);
3133 * gtk_text_iter_forward_visible_word_end:
3134 * @iter: a #GtkTextIter
3136 * Moves forward to the next visible word end. (If @iter is currently on a
3137 * word end, moves forward to the next one after that.) Word breaks
3138 * are determined by Pango and should be correct for nearly any
3139 * language (if not, the correct fix would be to the Pango word break
3142 * Return value: %TRUE if @iter moved and is not the end iterator
3147 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3149 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3153 * gtk_text_iter_backward_visible_word_start:
3154 * @iter: a #GtkTextIter
3156 * Moves backward to the previous visible word start. (If @iter is currently
3157 * on a word start, moves backward to the next one after that.) Word breaks
3158 * are determined by Pango and should be correct for nearly any
3159 * language (if not, the correct fix would be to the Pango word break
3162 * Return value: %TRUE if @iter moved and is not the end iterator
3167 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3169 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3173 * gtk_text_iter_forward_visible_word_ends:
3174 * @iter: a #GtkTextIter
3175 * @count: number of times to move
3177 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3179 * Return value: %TRUE if @iter moved and is not the end iterator
3184 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3187 return move_multiple_steps (iter, count,
3188 gtk_text_iter_forward_visible_word_end,
3189 gtk_text_iter_backward_visible_word_starts);
3193 * gtk_text_iter_backward_visible_word_starts
3194 * @iter: a #GtkTextIter
3195 * @count: number of times to move
3197 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3199 * Return value: %TRUE if @iter moved and is not the end iterator
3204 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3207 return move_multiple_steps (iter, count,
3208 gtk_text_iter_backward_visible_word_start,
3209 gtk_text_iter_forward_visible_word_ends);
3213 * gtk_text_iter_starts_word:
3214 * @iter: a #GtkTextIter
3216 * Determines whether @iter begins a natural-language word. Word
3217 * breaks are determined by Pango and should be correct for nearly any
3218 * language (if not, the correct fix would be to the Pango word break
3221 * Return value: %TRUE if @iter is at the start of a word
3224 gtk_text_iter_starts_word (const GtkTextIter *iter)
3226 return test_log_attrs (iter, is_word_start_func);
3230 * gtk_text_iter_ends_word:
3231 * @iter: a #GtkTextIter
3233 * Determines whether @iter ends a natural-language word. Word breaks
3234 * are determined by Pango and should be correct for nearly any
3235 * language (if not, the correct fix would be to the Pango word break
3238 * Return value: %TRUE if @iter is at the end of a word
3241 gtk_text_iter_ends_word (const GtkTextIter *iter)
3243 return test_log_attrs (iter, is_word_end_func);
3247 * gtk_text_iter_inside_word:
3248 * @iter: a #GtkTextIter
3250 * Determines whether @iter is inside a natural-language word (as
3251 * opposed to say inside some whitespace). Word breaks are determined
3252 * by Pango and should be correct for nearly any language (if not, the
3253 * correct fix would be to the Pango word break algorithms).
3255 * Return value: %TRUE if @iter is inside a word
3258 gtk_text_iter_inside_word (const GtkTextIter *iter)
3260 return test_log_attrs (iter, inside_word_func);
3264 * gtk_text_iter_starts_sentence:
3265 * @iter: a #GtkTextIter
3267 * Determines whether @iter begins a sentence. Sentence boundaries are
3268 * determined by Pango and should be correct for nearly any language
3269 * (if not, the correct fix would be to the Pango text boundary
3272 * Return value: %TRUE if @iter is at the start of a sentence.
3275 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3277 return test_log_attrs (iter, is_sentence_start_func);
3281 * gtk_text_iter_ends_sentence:
3282 * @iter: a #GtkTextIter
3284 * Determines whether @iter ends a sentence. Sentence boundaries are
3285 * determined by Pango and should be correct for nearly any language
3286 * (if not, the correct fix would be to the Pango text boundary
3289 * Return value: %TRUE if @iter is at the end of a sentence.
3292 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3294 return test_log_attrs (iter, is_sentence_end_func);
3298 * gtk_text_iter_inside_sentence:
3299 * @iter: a #GtkTextIter
3301 * Determines whether @iter is inside a sentence (as opposed to in
3302 * between two sentences, e.g. after a period and before the first
3303 * letter of the next sentence). Sentence boundaries are determined
3304 * by Pango and should be correct for nearly any language (if not, the
3305 * correct fix would be to the Pango text boundary algorithms).
3307 * Return value: %TRUE if @iter is inside a sentence.
3310 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3312 return test_log_attrs (iter, inside_sentence_func);
3316 * gtk_text_iter_forward_sentence_end:
3317 * @iter: a #GtkTextIter
3319 * Moves forward to the next sentence end. (If @iter is at the end of
3320 * a sentence, moves to the next end of sentence.) Sentence
3321 * boundaries are determined by Pango and should be correct for nearly
3322 * any language (if not, the correct fix would be to the Pango text
3323 * boundary algorithms).
3325 * Return value: %TRUE if @iter moved and is not the end iterator
3328 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3330 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3334 * gtk_text_iter_backward_sentence_start:
3335 * @iter: a #GtkTextIter
3337 * Moves backward to the previous sentence start; if @iter is already at
3338 * the start of a sentence, moves backward to the next one. Sentence
3339 * boundaries are determined by Pango and should be correct for nearly
3340 * any language (if not, the correct fix would be to the Pango text
3341 * boundary algorithms).
3343 * Return value: %TRUE if @iter moved and is not the end iterator
3346 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3348 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3351 /* FIXME a loop around a truly slow function means
3352 * a truly spectacularly slow function.
3355 * gtk_text_iter_forward_sentence_ends:
3356 * @iter: a #GtkTextIter
3357 * @count: number of sentences to move
3359 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3360 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3361 * negative, moves backward instead of forward.
3363 * Return value: %TRUE if @iter moved and is not the end iterator
3366 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3369 return move_multiple_steps (iter, count,
3370 gtk_text_iter_forward_sentence_end,
3371 gtk_text_iter_backward_sentence_starts);
3375 * gtk_text_iter_backward_sentence_starts:
3376 * @iter: a #GtkTextIter
3377 * @count: number of sentences to move
3379 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3380 * or until it returns %FALSE. If @count is negative, moves forward
3381 * instead of backward.
3383 * Return value: %TRUE if @iter moved and is not the end iterator
3386 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3389 return move_multiple_steps (iter, count,
3390 gtk_text_iter_backward_sentence_start,
3391 gtk_text_iter_forward_sentence_ends);
3395 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3400 gboolean already_moved_initially)
3402 if (!already_moved_initially)
3405 while (offset < (min_offset + len) &&
3406 !attrs[offset].is_cursor_position)
3409 *found_offset = offset;
3411 return offset < (min_offset + len);
3415 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3420 gboolean already_moved_initially)
3422 if (!already_moved_initially)
3425 while (offset > min_offset &&
3426 !attrs[offset].is_cursor_position)
3429 *found_offset = offset;
3431 return offset >= min_offset;
3435 is_cursor_pos_func (const PangoLogAttr *attrs,
3440 return attrs[offset].is_cursor_position;
3444 * gtk_text_iter_forward_cursor_position:
3445 * @iter: a #GtkTextIter
3447 * Moves @iter forward by a single cursor position. Cursor positions
3448 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3449 * surprisingly, there may not be a cursor position between all
3450 * characters. The most common example for European languages would be
3451 * a carriage return/newline sequence. For some Unicode characters,
3452 * the equivalent of say the letter "a" with an accent mark will be
3453 * represented as two characters, first the letter then a "combining
3454 * mark" that causes the accent to be rendered; so the cursor can't go
3455 * between those two characters. See also the #PangoLogAttr structure and
3456 * pango_break() function.
3458 * Return value: %TRUE if we moved and the new position is dereferenceable
3461 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3463 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3467 * gtk_text_iter_backward_cursor_position:
3468 * @iter: a #GtkTextIter
3470 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3472 * Return value: %TRUE if we moved
3475 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3477 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3481 * gtk_text_iter_forward_cursor_positions:
3482 * @iter: a #GtkTextIter
3483 * @count: number of positions to move
3485 * Moves up to @count cursor positions. See
3486 * gtk_text_iter_forward_cursor_position() for details.
3488 * Return value: %TRUE if we moved and the new position is dereferenceable
3491 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3494 return move_multiple_steps (iter, count,
3495 gtk_text_iter_forward_cursor_position,
3496 gtk_text_iter_backward_cursor_positions);
3500 * gtk_text_iter_backward_cursor_positions:
3501 * @iter: a #GtkTextIter
3502 * @count: number of positions to move
3504 * Moves up to @count cursor positions. See
3505 * gtk_text_iter_forward_cursor_position() for details.
3507 * Return value: %TRUE if we moved and the new position is dereferenceable
3510 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3513 return move_multiple_steps (iter, count,
3514 gtk_text_iter_backward_cursor_position,
3515 gtk_text_iter_forward_cursor_positions);
3519 * gtk_text_iter_forward_visible_cursor_position:
3520 * @iter: a #GtkTextIter
3522 * Moves @iter forward to the next visible cursor position. See
3523 * gtk_text_iter_forward_cursor_position() for details.
3525 * Return value: %TRUE if we moved and the new position is dereferenceable
3530 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3532 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3536 * gtk_text_iter_backward_visible_cursor_position:
3537 * @iter: a #GtkTextIter
3539 * Moves @iter forward to the previous visible cursor position. See
3540 * gtk_text_iter_backward_cursor_position() for details.
3542 * Return value: %TRUE if we moved and the new position is dereferenceable
3547 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3549 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3553 * gtk_text_iter_forward_visible_cursor_positions:
3554 * @iter: a #GtkTextIter
3555 * @count: number of positions to move
3557 * Moves up to @count visible cursor positions. See
3558 * gtk_text_iter_forward_cursor_position() for details.
3560 * Return value: %TRUE if we moved and the new position is dereferenceable
3565 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3568 return move_multiple_steps (iter, count,
3569 gtk_text_iter_forward_visible_cursor_position,
3570 gtk_text_iter_backward_visible_cursor_positions);
3574 * gtk_text_iter_backward_visible_cursor_positions:
3575 * @iter: a #GtkTextIter
3576 * @count: number of positions to move
3578 * Moves up to @count visible cursor positions. See
3579 * gtk_text_iter_forward_cursor_position() for details.
3581 * Return value: %TRUE if we moved and the new position is dereferenceable
3586 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3589 return move_multiple_steps (iter, count,
3590 gtk_text_iter_backward_visible_cursor_position,
3591 gtk_text_iter_forward_visible_cursor_positions);
3595 * gtk_text_iter_is_cursor_position:
3596 * @iter: a #GtkTextIter
3598 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3599 * pango_break() for details on what a cursor position is.
3601 * Return value: %TRUE if the cursor can be placed at @iter
3604 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3606 return test_log_attrs (iter, is_cursor_pos_func);
3610 * gtk_text_iter_set_line_offset:
3611 * @iter: a #GtkTextIter
3612 * @char_on_line: a character offset relative to the start of @iter's current line
3614 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3615 * (not byte) offset. The given character offset must be less than or
3616 * equal to the number of characters in the line; if equal, @iter
3617 * moves to the start of the next line. See
3618 * gtk_text_iter_set_line_index() if you have a byte index rather than
3619 * a character offset.
3623 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3626 GtkTextRealIter *real;
3629 g_return_if_fail (iter != NULL);
3631 real = gtk_text_iter_make_surreal (iter);
3636 check_invariants (iter);
3638 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3640 g_return_if_fail (char_on_line <= chars_in_line);
3642 if (char_on_line < chars_in_line)
3643 iter_set_from_char_offset (real, real->line, char_on_line);
3645 gtk_text_iter_forward_line (iter); /* set to start of next line */
3647 check_invariants (iter);
3651 * gtk_text_iter_set_line_index:
3652 * @iter: a #GtkTextIter
3653 * @byte_on_line: a byte index relative to the start of @iter's current line
3655 * Same as gtk_text_iter_set_line_offset(), but works with a
3656 * <emphasis>byte</emphasis> index. The given byte index must be at
3657 * the start of a character, it can't be in the middle of a UTF-8
3658 * encoded character.
3662 gtk_text_iter_set_line_index (GtkTextIter *iter,
3665 GtkTextRealIter *real;
3668 g_return_if_fail (iter != NULL);
3670 real = gtk_text_iter_make_surreal (iter);
3675 check_invariants (iter);
3677 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3679 g_return_if_fail (byte_on_line <= bytes_in_line);
3681 if (byte_on_line < bytes_in_line)
3682 iter_set_from_byte_offset (real, real->line, byte_on_line);
3684 gtk_text_iter_forward_line (iter);
3686 if (real->segment->type == >k_text_char_type &&
3687 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3688 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3689 "character; this will crash the text buffer. "
3690 "Byte indexes must refer to the start of a character.",
3691 G_STRLOC, byte_on_line);
3693 check_invariants (iter);
3698 * gtk_text_iter_set_visible_line_offset:
3699 * @iter: a #GtkTextIter
3700 * @char_on_line: a character offset
3702 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3703 * characters, i.e. text with a tag making it invisible is not
3704 * counted in the offset.
3707 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3710 gint chars_seen = 0;
3713 g_return_if_fail (iter != NULL);
3717 /* For now we use a ludicrously slow implementation */
3718 while (chars_seen < char_on_line)
3720 if (!_gtk_text_btree_char_is_invisible (&pos))
3723 if (!gtk_text_iter_forward_char (&pos))
3726 if (chars_seen == char_on_line)
3730 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3733 gtk_text_iter_forward_line (iter);
3737 bytes_in_char (GtkTextIter *iter)
3739 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3743 * gtk_text_iter_set_visible_line_index:
3744 * @iter: a #GtkTextIter
3745 * @byte_on_line: a byte index
3747 * Like gtk_text_iter_set_line_index(), but the index is in visible
3748 * bytes, i.e. text with a tag making it invisible is not counted
3752 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3755 gint bytes_seen = 0;
3759 g_return_if_fail (iter != NULL);
3763 /* For now we use a ludicrously slow implementation */
3764 while (bytes_seen < byte_on_line)
3766 if (!_gtk_text_btree_char_is_invisible (&pos))
3767 bytes_seen += bytes_in_char (&pos);
3770 if (!gtk_text_iter_forward_char (&pos))
3773 if (bytes_seen >= byte_on_line)
3777 if (bytes_seen > byte_on_line)
3778 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3779 "character; this will crash the text buffer. "
3780 "Byte indexes must refer to the start of a character.",
3781 G_STRLOC, byte_on_line);
3783 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3786 gtk_text_iter_forward_line (iter);
3790 * gtk_text_iter_set_line:
3791 * @iter: a #GtkTextIter
3792 * @line_number: line number (counted from 0)
3794 * Moves iterator @iter to the start of the line @line_number. If
3795 * @line_number is negative or larger than the number of lines in the
3796 * buffer, moves @iter to the start of the last line in the buffer.
3800 gtk_text_iter_set_line (GtkTextIter *iter,
3805 GtkTextRealIter *real;
3807 g_return_if_fail (iter != NULL);
3809 real = gtk_text_iter_make_surreal (iter);
3814 check_invariants (iter);
3816 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3818 iter_set_from_char_offset (real, line, 0);
3820 /* We might as well cache this, since we know it. */
3821 real->cached_line_number = real_line;
3823 check_invariants (iter);
3827 * gtk_text_iter_set_offset:
3828 * @iter: a #GtkTextIter
3829 * @char_offset: a character number
3831 * Sets @iter to point to @char_offset. @char_offset counts from the start
3832 * of the entire text buffer, starting with 0.
3835 gtk_text_iter_set_offset (GtkTextIter *iter,
3839 GtkTextRealIter *real;
3841 gint real_char_index;
3843 g_return_if_fail (iter != NULL);
3845 real = gtk_text_iter_make_surreal (iter);
3850 check_invariants (iter);
3852 if (real->cached_char_index >= 0 &&
3853 real->cached_char_index == char_offset)
3856 line = _gtk_text_btree_get_line_at_char (real->tree,
3861 iter_set_from_char_offset (real, line, real_char_index - line_start);
3863 /* Go ahead and cache this since we have it. */
3864 real->cached_char_index = real_char_index;
3866 check_invariants (iter);
3870 * gtk_text_iter_forward_to_end:
3871 * @iter: a #GtkTextIter
3873 * Moves @iter forward to the "end iterator," which points one past the last
3874 * valid character in the buffer. gtk_text_iter_get_char() called on the
3875 * end iterator returns 0, which is convenient for writing loops.
3878 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3880 GtkTextBuffer *buffer;
3881 GtkTextRealIter *real;
3883 g_return_if_fail (iter != NULL);
3885 real = gtk_text_iter_make_surreal (iter);
3890 buffer = _gtk_text_btree_get_buffer (real->tree);
3892 gtk_text_buffer_get_end_iter (buffer, iter);
3895 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3896 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3897 * If all else fails we could cache the para delimiter pos in the iter.
3898 * I think forward_to_line_end() actually gets called fairly often.
3901 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3906 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3907 _gtk_text_iter_get_btree (&end)))
3909 gtk_text_iter_forward_to_end (&end);
3913 /* if we aren't on the last line, go forward to start of next line, then scan
3914 * back for the delimiters on the previous line
3916 gtk_text_iter_forward_line (&end);
3917 gtk_text_iter_backward_char (&end);
3918 while (!gtk_text_iter_ends_line (&end))
3919 gtk_text_iter_backward_char (&end);
3922 return gtk_text_iter_get_line_offset (&end);
3926 * gtk_text_iter_forward_to_line_end:
3927 * @iter: a #GtkTextIter
3929 * Moves the iterator to point to the paragraph delimiter characters,
3930 * which will be either a newline, a carriage return, a carriage
3931 * return/newline in sequence, or the Unicode paragraph separator
3932 * character. If the iterator is already at the paragraph delimiter
3933 * characters, moves to the paragraph delimiter characters for the
3934 * next line. If @iter is on the last line in the buffer, which does
3935 * not end in paragraph delimiters, moves to the end iterator (end of
3936 * the last line), and returns %FALSE.
3938 * Return value: %TRUE if we moved and the new location is not the end iterator
3941 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3943 gint current_offset;
3947 g_return_val_if_fail (iter != NULL, FALSE);
3949 current_offset = gtk_text_iter_get_line_offset (iter);
3950 new_offset = find_paragraph_delimiter_for_line (iter);
3952 if (current_offset < new_offset)
3954 /* Move to end of this line. */
3955 gtk_text_iter_set_line_offset (iter, new_offset);
3956 return !gtk_text_iter_is_end (iter);
3960 /* Move to end of next line. */
3961 if (gtk_text_iter_forward_line (iter))
3963 /* We don't want to move past all
3966 if (!gtk_text_iter_ends_line (iter))
3967 gtk_text_iter_forward_to_line_end (iter);
3968 return !gtk_text_iter_is_end (iter);
3976 * gtk_text_iter_forward_to_tag_toggle:
3977 * @iter: a #GtkTextIter
3978 * @tag: a #GtkTextTag, or %NULL
3980 * Moves forward to the next toggle (on or off) of the
3981 * #GtkTextTag @tag, or to the next toggle of any tag if
3982 * @tag is %NULL. If no matching tag toggles are found,
3983 * returns %FALSE, otherwise %TRUE. Does not return toggles
3984 * located at @iter, only toggles after @iter. Sets @iter to
3985 * the location of the toggle, or to the end of the buffer
3986 * if no toggle is found.
3988 * Return value: whether we found a tag toggle after @iter
3991 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3994 GtkTextLine *next_line;
3995 GtkTextLine *current_line;
3996 GtkTextRealIter *real;
3998 g_return_val_if_fail (iter != NULL, FALSE);
4000 real = gtk_text_iter_make_real (iter);
4005 check_invariants (iter);
4007 current_line = real->line;
4008 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4011 while (_gtk_text_iter_forward_indexable_segment (iter))
4013 /* If we went forward to a line that couldn't contain a toggle
4014 for the tag, then skip forward to a line that could contain
4015 it. This potentially skips huge hunks of the tree, so we
4016 aren't a purely linear search. */
4017 if (real->line != current_line)
4019 if (next_line == NULL)
4021 /* End of search. Set to end of buffer. */
4022 _gtk_text_btree_get_end_iter (real->tree, iter);
4026 if (real->line != next_line)
4027 iter_set_from_byte_offset (real, next_line, 0);
4029 current_line = real->line;
4030 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4035 if (gtk_text_iter_toggles_tag (iter, tag))
4037 /* If there's a toggle here, it isn't indexable so
4038 any_segment can't be the indexable segment. */
4039 g_assert (real->any_segment != real->segment);
4044 /* Check end iterator for tags */
4045 if (gtk_text_iter_toggles_tag (iter, tag))
4047 /* If there's a toggle here, it isn't indexable so
4048 any_segment can't be the indexable segment. */
4049 g_assert (real->any_segment != real->segment);
4053 /* Reached end of buffer */
4058 * gtk_text_iter_backward_to_tag_toggle:
4059 * @iter: a #GtkTextIter
4060 * @tag: a #GtkTextTag, or %NULL
4062 * Moves backward to the next toggle (on or off) of the
4063 * #GtkTextTag @tag, or to the next toggle of any tag if
4064 * @tag is %NULL. If no matching tag toggles are found,
4065 * returns %FALSE, otherwise %TRUE. Does not return toggles
4066 * located at @iter, only toggles before @iter. Sets @iter
4067 * to the location of the toggle, or the start of the buffer
4068 * if no toggle is found.
4070 * Return value: whether we found a tag toggle before @iter
4073 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4076 GtkTextLine *prev_line;
4077 GtkTextLine *current_line;
4078 GtkTextRealIter *real;
4080 g_return_val_if_fail (iter != NULL, FALSE);
4082 real = gtk_text_iter_make_real (iter);
4087 check_invariants (iter);
4089 current_line = real->line;
4090 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4094 /* If we're at segment start, go to the previous segment;
4095 * if mid-segment, snap to start of current segment.
4097 if (is_segment_start (real))
4099 if (!_gtk_text_iter_backward_indexable_segment (iter))
4104 ensure_char_offsets (real);
4106 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4112 /* If we went backward to a line that couldn't contain a toggle
4113 * for the tag, then skip backward further to a line that
4114 * could contain it. This potentially skips huge hunks of the
4115 * tree, so we aren't a purely linear search.
4117 if (real->line != current_line)
4119 if (prev_line == NULL)
4121 /* End of search. Set to start of buffer. */
4122 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4126 if (real->line != prev_line)
4128 /* Set to last segment in prev_line (could do this
4131 iter_set_from_byte_offset (real, prev_line, 0);
4133 while (!at_last_indexable_segment (real))
4134 _gtk_text_iter_forward_indexable_segment (iter);
4137 current_line = real->line;
4138 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4143 if (gtk_text_iter_toggles_tag (iter, tag))
4145 /* If there's a toggle here, it isn't indexable so
4146 * any_segment can't be the indexable segment.
4148 g_assert (real->any_segment != real->segment);
4152 while (_gtk_text_iter_backward_indexable_segment (iter));
4154 /* Reached front of buffer */
4159 matches_pred (GtkTextIter *iter,
4160 GtkTextCharPredicate pred,
4165 ch = gtk_text_iter_get_char (iter);
4167 return (*pred) (ch, user_data);
4171 * gtk_text_iter_forward_find_char:
4172 * @iter: a #GtkTextIter
4173 * @pred: a function to be called on each character
4174 * @user_data: user data for @pred
4175 * @limit: search limit, or %NULL for none
4177 * Advances @iter, calling @pred on each character. If
4178 * @pred returns %TRUE, returns %TRUE and stops scanning.
4179 * If @pred never returns %TRUE, @iter is set to @limit if
4180 * @limit is non-%NULL, otherwise to the end iterator.
4182 * Return value: whether a match was found
4185 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4186 GtkTextCharPredicate pred,
4188 const GtkTextIter *limit)
4190 g_return_val_if_fail (iter != NULL, FALSE);
4191 g_return_val_if_fail (pred != NULL, FALSE);
4194 gtk_text_iter_compare (iter, limit) >= 0)
4197 while ((limit == NULL ||
4198 !gtk_text_iter_equal (limit, iter)) &&
4199 gtk_text_iter_forward_char (iter))
4201 if (matches_pred (iter, pred, user_data))
4209 * gtk_text_iter_backward_find_char:
4210 * @iter: a #GtkTextIter
4211 * @pred: function to be called on each character
4212 * @user_data: user data for @pred
4213 * @limit: search limit, or %NULL for none
4215 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4217 * Return value: whether a match was found
4220 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4221 GtkTextCharPredicate pred,
4223 const GtkTextIter *limit)
4225 g_return_val_if_fail (iter != NULL, FALSE);
4226 g_return_val_if_fail (pred != NULL, FALSE);
4229 gtk_text_iter_compare (iter, limit) <= 0)
4232 while ((limit == NULL ||
4233 !gtk_text_iter_equal (limit, iter)) &&
4234 gtk_text_iter_backward_char (iter))
4236 if (matches_pred (iter, pred, user_data))
4244 forward_chars_with_skipping (GtkTextIter *iter,
4246 gboolean skip_invisible,
4247 gboolean skip_nontext)
4252 g_return_if_fail (count >= 0);
4258 gboolean ignored = FALSE;
4261 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4266 _gtk_text_btree_char_is_invisible (iter))
4269 gtk_text_iter_forward_char (iter);
4277 lines_match (const GtkTextIter *start,
4278 const gchar **lines,
4279 gboolean visible_only,
4281 GtkTextIter *match_start,
4282 GtkTextIter *match_end)
4289 if (*lines == NULL || **lines == '\0')
4292 *match_start = *start;
4295 *match_end = *start;
4300 gtk_text_iter_forward_line (&next);
4302 /* No more text in buffer, but *lines is nonempty */
4303 if (gtk_text_iter_equal (start, &next))
4311 line_text = gtk_text_iter_get_visible_slice (start, &next);
4313 line_text = gtk_text_iter_get_slice (start, &next);
4318 line_text = gtk_text_iter_get_visible_text (start, &next);
4320 line_text = gtk_text_iter_get_text (start, &next);
4323 if (match_start) /* if this is the first line we're matching */
4324 found = strstr (line_text, *lines);
4327 /* If it's not the first line, we have to match from the
4328 * start of the line.
4330 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4342 /* Get offset to start of search string */
4343 offset = g_utf8_strlen (line_text, found - line_text);
4347 /* If match start needs to be returned, set it to the
4348 * start of the search string.
4352 *match_start = next;
4354 forward_chars_with_skipping (match_start, offset,
4355 visible_only, !slice);
4358 /* Go to end of search string */
4359 offset += g_utf8_strlen (*lines, -1);
4361 forward_chars_with_skipping (&next, offset,
4362 visible_only, !slice);
4371 /* pass NULL for match_start, since we don't need to find the
4374 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4377 /* strsplit () that retains the delimiter as part of the string. */
4379 strbreakup (const char *string,
4380 const char *delimiter,
4383 GSList *string_list = NULL, *slist;
4384 gchar **str_array, *s;
4387 g_return_val_if_fail (string != NULL, NULL);
4388 g_return_val_if_fail (delimiter != NULL, NULL);
4391 max_tokens = G_MAXINT;
4393 s = strstr (string, delimiter);
4396 guint delimiter_len = strlen (delimiter);
4403 len = s - string + delimiter_len;
4404 new_string = g_new (gchar, len + 1);
4405 strncpy (new_string, string, len);
4406 new_string[len] = 0;
4407 string_list = g_slist_prepend (string_list, new_string);
4409 string = s + delimiter_len;
4410 s = strstr (string, delimiter);
4412 while (--max_tokens && s);
4417 string_list = g_slist_prepend (string_list, g_strdup (string));
4420 str_array = g_new (gchar*, n);
4424 str_array[i--] = NULL;
4425 for (slist = string_list; slist; slist = slist->next)
4426 str_array[i--] = slist->data;
4428 g_slist_free (string_list);
4434 * gtk_text_iter_forward_search:
4435 * @iter: start of search
4436 * @str: a search string
4437 * @flags: flags affecting how the search is done
4438 * @match_start: return location for start of match, or %NULL
4439 * @match_end: return location for end of match, or %NULL
4440 * @limit: bound for the search, or %NULL for the end of the buffer
4442 * Searches forward for @str. Any match is returned by setting
4443 * @match_start to the first character of the match and @match_end to the
4444 * first character after the match. The search will not continue past
4445 * @limit. Note that a search is a linear or O(n) operation, so you
4446 * may wish to use @limit to avoid locking up your UI on large
4449 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4450 * have invisible text interspersed in @str. i.e. @str will be a
4451 * possibly-noncontiguous subsequence of the matched range. similarly,
4452 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4453 * pixbufs or child widgets mixed inside the matched range. If these
4454 * flags are not given, the match must be exact; the special 0xFFFC
4455 * character in @str will match embedded pixbufs or child widgets.
4457 * Return value: whether a match was found
4460 gtk_text_iter_forward_search (const GtkTextIter *iter,
4462 GtkTextSearchFlags flags,
4463 GtkTextIter *match_start,
4464 GtkTextIter *match_end,
4465 const GtkTextIter *limit)
4467 gchar **lines = NULL;
4469 gboolean retval = FALSE;
4471 gboolean visible_only;
4474 g_return_val_if_fail (iter != NULL, FALSE);
4475 g_return_val_if_fail (str != NULL, FALSE);
4478 gtk_text_iter_compare (iter, limit) >= 0)
4483 /* If we can move one char, return the empty string there */
4486 if (gtk_text_iter_forward_char (&match))
4489 gtk_text_iter_equal (&match, limit))
4493 *match_start = match;
4502 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4503 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4505 /* locate all lines */
4507 lines = strbreakup (str, "\n", -1);
4513 /* This loop has an inefficient worst-case, where
4514 * gtk_text_iter_get_text () is called repeatedly on
4520 gtk_text_iter_compare (&search, limit) >= 0)
4523 if (lines_match (&search, (const gchar**)lines,
4524 visible_only, slice, &match, &end))
4526 if (limit == NULL ||
4528 gtk_text_iter_compare (&end, limit) < 0))
4533 *match_start = match;
4542 while (gtk_text_iter_forward_line (&search));
4544 g_strfreev ((gchar**)lines);
4550 vectors_equal_ignoring_trailing (gchar **vec1,
4553 /* Ignores trailing chars in vec2's last line */
4562 if (strcmp (*i1, *i2) != 0)
4564 if (*(i2 + 1) == NULL) /* if this is the last line */
4566 gint len1 = strlen (*i1);
4567 gint len2 = strlen (*i2);
4570 strncmp (*i1, *i2, len1) == 0)
4572 /* We matched ignoring the trailing stuff in vec2 */
4597 typedef struct _LinesWindow LinesWindow;
4603 GtkTextIter first_line_start;
4604 GtkTextIter first_line_end;
4606 gboolean visible_only;
4610 lines_window_init (LinesWindow *win,
4611 const GtkTextIter *start)
4614 GtkTextIter line_start;
4615 GtkTextIter line_end;
4617 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4620 if (gtk_text_iter_is_start (start) ||
4621 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4623 /* Already at the end, or not enough lines to match */
4624 win->lines = g_new0 (gchar*, 1);
4629 line_start = *start;
4632 /* Move to start iter to start of line */
4633 gtk_text_iter_set_line_offset (&line_start, 0);
4635 if (gtk_text_iter_equal (&line_start, &line_end))
4637 /* we were already at the start; so go back one line */
4638 gtk_text_iter_backward_line (&line_start);
4641 win->first_line_start = line_start;
4642 win->first_line_end = line_end;
4644 win->lines = g_new0 (gchar*, win->n_lines + 1);
4646 i = win->n_lines - 1;
4653 if (win->visible_only)
4654 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4656 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4660 if (win->visible_only)
4661 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4663 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4666 win->lines[i] = line_text;
4668 line_end = line_start;
4669 gtk_text_iter_backward_line (&line_start);
4676 lines_window_back (LinesWindow *win)
4678 GtkTextIter new_start;
4681 new_start = win->first_line_start;
4683 if (!gtk_text_iter_backward_line (&new_start))
4687 win->first_line_start = new_start;
4688 win->first_line_end = new_start;
4690 gtk_text_iter_forward_line (&win->first_line_end);
4695 if (win->visible_only)
4696 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4697 &win->first_line_end);
4699 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4700 &win->first_line_end);
4704 if (win->visible_only)
4705 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4706 &win->first_line_end);
4708 line_text = gtk_text_iter_get_text (&win->first_line_start,
4709 &win->first_line_end);
4712 /* Move lines to make room for first line. */
4713 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4715 *win->lines = line_text;
4717 /* Free old last line and NULL-terminate */
4718 g_free (win->lines[win->n_lines]);
4719 win->lines[win->n_lines] = NULL;
4725 lines_window_free (LinesWindow *win)
4727 g_strfreev (win->lines);
4731 * gtk_text_iter_backward_search:
4732 * @iter: a #GtkTextIter where the search begins
4733 * @str: search string
4734 * @flags: bitmask of flags affecting the search
4735 * @match_start: return location for start of match, or %NULL
4736 * @match_end: return location for end of match, or %NULL
4737 * @limit: location of last possible @match_start, or %NULL for start of buffer
4739 * Same as gtk_text_iter_forward_search(), but moves backward.
4741 * Return value: whether a match was found
4744 gtk_text_iter_backward_search (const GtkTextIter *iter,
4746 GtkTextSearchFlags flags,
4747 GtkTextIter *match_start,
4748 GtkTextIter *match_end,
4749 const GtkTextIter *limit)
4751 gchar **lines = NULL;
4755 gboolean retval = FALSE;
4756 gboolean visible_only;
4759 g_return_val_if_fail (iter != NULL, FALSE);
4760 g_return_val_if_fail (str != NULL, FALSE);
4763 gtk_text_iter_compare (limit, iter) > 0)
4768 /* If we can move one char, return the empty string there */
4769 GtkTextIter match = *iter;
4771 if (limit && gtk_text_iter_equal (limit, &match))
4774 if (gtk_text_iter_backward_char (&match))
4777 *match_start = match;
4786 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4787 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4789 /* locate all lines */
4791 lines = strbreakup (str, "\n", -1);
4801 win.n_lines = n_lines;
4803 win.visible_only = visible_only;
4805 lines_window_init (&win, iter);
4807 if (*win.lines == NULL)
4812 gchar *first_line_match;
4815 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4817 /* We're now before the search limit, abort. */
4821 /* If there are multiple lines, the first line will
4822 * end in '\n', so this will only match at the
4823 * end of the first line, which is correct.
4825 first_line_match = g_strrstr (*win.lines, *lines);
4827 if (first_line_match &&
4828 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4833 GtkTextIter start_tmp;
4835 /* Offset to start of search string */
4836 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4838 next = win.first_line_start;
4840 forward_chars_with_skipping (&start_tmp, offset,
4841 visible_only, !slice);
4844 gtk_text_iter_compare (limit, &start_tmp) > 0)
4845 goto out; /* match was bogus */
4848 *match_start = start_tmp;
4850 /* Go to end of search string */
4854 offset += g_utf8_strlen (*l, -1);
4858 forward_chars_with_skipping (&next, offset,
4859 visible_only, !slice);
4868 while (lines_window_back (&win));
4871 lines_window_free (&win);
4882 * gtk_text_iter_equal:
4883 * @lhs: a #GtkTextIter
4884 * @rhs: another #GtkTextIter
4886 * Tests whether two iterators are equal, using the fastest possible
4887 * mechanism. This function is very fast; you can expect it to perform
4888 * better than e.g. getting the character offset for each iterator and
4889 * comparing the offsets yourself. Also, it's a bit faster than
4890 * gtk_text_iter_compare().
4892 * Return value: %TRUE if the iterators point to the same place in the buffer
4895 gtk_text_iter_equal (const GtkTextIter *lhs,
4896 const GtkTextIter *rhs)
4898 GtkTextRealIter *real_lhs;
4899 GtkTextRealIter *real_rhs;
4901 real_lhs = (GtkTextRealIter*)lhs;
4902 real_rhs = (GtkTextRealIter*)rhs;
4904 check_invariants (lhs);
4905 check_invariants (rhs);
4907 if (real_lhs->line != real_rhs->line)
4909 else if (real_lhs->line_byte_offset >= 0 &&
4910 real_rhs->line_byte_offset >= 0)
4911 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4914 /* the ensure_char_offsets () calls do nothing if the char offsets
4915 are already up-to-date. */
4916 ensure_char_offsets (real_lhs);
4917 ensure_char_offsets (real_rhs);
4918 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4923 * gtk_text_iter_compare:
4924 * @lhs: a #GtkTextIter
4925 * @rhs: another #GtkTextIter
4927 * A qsort()-style function that returns negative if @lhs is less than
4928 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4929 * Ordering is in character offset order, i.e. the first character in the buffer
4930 * is less than the second character in the buffer.
4932 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4935 gtk_text_iter_compare (const GtkTextIter *lhs,
4936 const GtkTextIter *rhs)
4938 GtkTextRealIter *real_lhs;
4939 GtkTextRealIter *real_rhs;
4941 real_lhs = gtk_text_iter_make_surreal (lhs);
4942 real_rhs = gtk_text_iter_make_surreal (rhs);
4944 if (real_lhs == NULL ||
4946 return -1; /* why not */
4948 check_invariants (lhs);
4949 check_invariants (rhs);
4951 if (real_lhs->line == real_rhs->line)
4953 gint left_index, right_index;
4955 if (real_lhs->line_byte_offset >= 0 &&
4956 real_rhs->line_byte_offset >= 0)
4958 left_index = real_lhs->line_byte_offset;
4959 right_index = real_rhs->line_byte_offset;
4963 /* the ensure_char_offsets () calls do nothing if
4964 the offsets are already up-to-date. */
4965 ensure_char_offsets (real_lhs);
4966 ensure_char_offsets (real_rhs);
4967 left_index = real_lhs->line_char_offset;
4968 right_index = real_rhs->line_char_offset;
4971 if (left_index < right_index)
4973 else if (left_index > right_index)
4982 line1 = gtk_text_iter_get_line (lhs);
4983 line2 = gtk_text_iter_get_line (rhs);
4986 else if (line1 > line2)
4994 * gtk_text_iter_in_range:
4995 * @iter: a #GtkTextIter
4996 * @start: start of range
4997 * @end: end of range
4999 * Checks whether @iter falls in the range [@start, @end).
5000 * @start and @end must be in ascending order.
5002 * Return value: %TRUE if @iter is in the range
5005 gtk_text_iter_in_range (const GtkTextIter *iter,
5006 const GtkTextIter *start,
5007 const GtkTextIter *end)
5009 g_return_val_if_fail (iter != NULL, FALSE);
5010 g_return_val_if_fail (start != NULL, FALSE);
5011 g_return_val_if_fail (end != NULL, FALSE);
5012 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5014 return gtk_text_iter_compare (iter, start) >= 0 &&
5015 gtk_text_iter_compare (iter, end) < 0;
5019 * gtk_text_iter_order:
5020 * @first: a #GtkTextIter
5021 * @second: another #GtkTextIter
5023 * Swaps the value of @first and @second if @second comes before
5024 * @first in the buffer. That is, ensures that @first and @second are
5025 * in sequence. Most text buffer functions that take a range call this
5026 * automatically on your behalf, so there's no real reason to call it yourself
5027 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5028 * that expect a pre-sorted range.
5032 gtk_text_iter_order (GtkTextIter *first,
5033 GtkTextIter *second)
5035 g_return_if_fail (first != NULL);
5036 g_return_if_fail (second != NULL);
5038 if (gtk_text_iter_compare (first, second) > 0)
5049 * Init iterators from the BTree
5053 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5057 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5058 gint real_char_index;
5062 g_return_if_fail (iter != NULL);
5063 g_return_if_fail (tree != NULL);
5065 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5066 &line_start, &real_char_index);
5068 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5070 real->cached_char_index = real_char_index;
5072 check_invariants (iter);
5076 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5081 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5085 g_return_if_fail (iter != NULL);
5086 g_return_if_fail (tree != NULL);
5088 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5090 iter_init_from_char_offset (iter, tree, line, char_on_line);
5092 /* We might as well cache this, since we know it. */
5093 real->cached_line_number = real_line;
5095 check_invariants (iter);
5099 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5104 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5108 g_return_if_fail (iter != NULL);
5109 g_return_if_fail (tree != NULL);
5111 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5113 iter_init_from_byte_offset (iter, tree, line, byte_index);
5115 /* We might as well cache this, since we know it. */
5116 real->cached_line_number = real_line;
5118 check_invariants (iter);
5122 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5127 g_return_if_fail (iter != NULL);
5128 g_return_if_fail (tree != NULL);
5129 g_return_if_fail (line != NULL);
5131 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5133 check_invariants (iter);
5137 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5143 g_return_val_if_fail (iter != NULL, FALSE);
5144 g_return_val_if_fail (tree != NULL, FALSE);
5146 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5150 /* Set iter to last in tree */
5151 _gtk_text_btree_get_end_iter (tree, iter);
5152 check_invariants (iter);
5157 iter_init_from_byte_offset (iter, tree, line, 0);
5159 if (!gtk_text_iter_toggles_tag (iter, tag))
5160 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5162 check_invariants (iter);
5168 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5172 g_return_val_if_fail (iter != NULL, FALSE);
5173 g_return_val_if_fail (tree != NULL, FALSE);
5175 _gtk_text_btree_get_end_iter (tree, iter);
5176 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5177 check_invariants (iter);
5183 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5185 const gchar *mark_name)
5189 g_return_val_if_fail (iter != NULL, FALSE);
5190 g_return_val_if_fail (tree != NULL, FALSE);
5192 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5198 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5199 check_invariants (iter);
5205 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5209 GtkTextLineSegment *seg;
5211 g_return_if_fail (iter != NULL);
5212 g_return_if_fail (tree != NULL);
5213 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5215 seg = mark->segment;
5217 iter_init_from_segment (iter, tree,
5218 seg->body.mark.line, seg);
5219 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5220 check_invariants (iter);
5224 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5226 GtkTextChildAnchor *anchor)
5228 GtkTextLineSegment *seg;
5230 g_return_if_fail (iter != NULL);
5231 g_return_if_fail (tree != NULL);
5232 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5234 seg = anchor->segment;
5236 g_assert (seg->body.child.line != NULL);
5238 iter_init_from_segment (iter, tree,
5239 seg->body.child.line, seg);
5240 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5241 check_invariants (iter);
5245 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5248 g_return_if_fail (iter != NULL);
5249 g_return_if_fail (tree != NULL);
5251 _gtk_text_btree_get_iter_at_char (tree,
5253 _gtk_text_btree_char_count (tree));
5254 check_invariants (iter);
5258 _gtk_text_iter_check (const GtkTextIter *iter)
5260 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5261 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5262 GtkTextLineSegment *byte_segment = NULL;
5263 GtkTextLineSegment *byte_any_segment = NULL;
5264 GtkTextLineSegment *char_segment = NULL;
5265 GtkTextLineSegment *char_any_segment = NULL;
5266 gboolean segments_updated;
5268 /* This function checks our class invariants for the Iter class. */
5270 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5272 if (real->chars_changed_stamp !=
5273 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5274 g_error ("iterator check failed: invalid iterator");
5276 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5277 g_error ("iterator check failed: both char and byte offsets are invalid");
5279 segments_updated = (real->segments_changed_stamp ==
5280 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5283 printf ("checking iter, segments %s updated, byte %d char %d\n",
5284 segments_updated ? "are" : "aren't",
5285 real->line_byte_offset,
5286 real->line_char_offset);
5289 if (segments_updated)
5291 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5292 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5294 if (real->segment->char_count == 0)
5295 g_error ("iterator check failed: segment is not indexable.");
5297 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5298 g_error ("segment char offset is not properly up-to-date");
5300 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5301 g_error ("segment byte offset is not properly up-to-date");
5303 if (real->segment_byte_offset >= 0 &&
5304 real->segment_byte_offset >= real->segment->byte_count)
5305 g_error ("segment byte offset is too large.");
5307 if (real->segment_char_offset >= 0 &&
5308 real->segment_char_offset >= real->segment->char_count)
5309 g_error ("segment char offset is too large.");
5312 if (real->line_byte_offset >= 0)
5314 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5315 &byte_segment, &byte_any_segment,
5316 &seg_byte_offset, &line_byte_offset);
5318 if (line_byte_offset != real->line_byte_offset)
5319 g_error ("wrong byte offset was stored in iterator");
5321 if (segments_updated)
5323 if (real->segment != byte_segment)
5324 g_error ("wrong segment was stored in iterator");
5326 if (real->any_segment != byte_any_segment)
5327 g_error ("wrong any_segment was stored in iterator");
5329 if (seg_byte_offset != real->segment_byte_offset)
5330 g_error ("wrong segment byte offset was stored in iterator");
5332 if (byte_segment->type == >k_text_char_type)
5335 p = byte_segment->body.chars + seg_byte_offset;
5337 if (!gtk_text_byte_begins_utf8_char (p))
5338 g_error ("broken iterator byte index pointed into the middle of a character");
5343 if (real->line_char_offset >= 0)
5345 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5346 &char_segment, &char_any_segment,
5347 &seg_char_offset, &line_char_offset);
5349 if (line_char_offset != real->line_char_offset)
5350 g_error ("wrong char offset was stored in iterator");
5352 if (segments_updated)
5354 if (real->segment != char_segment)
5355 g_error ("wrong segment was stored in iterator");
5357 if (real->any_segment != char_any_segment)
5358 g_error ("wrong any_segment was stored in iterator");
5360 if (seg_char_offset != real->segment_char_offset)
5361 g_error ("wrong segment char offset was stored in iterator");
5363 if (char_segment->type == >k_text_char_type)
5366 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5369 /* hmm, not likely to happen eh */
5370 if (!gtk_text_byte_begins_utf8_char (p))
5371 g_error ("broken iterator char offset pointed into the middle of a character");
5376 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5378 if (byte_segment != char_segment)
5379 g_error ("char and byte offsets did not point to the same segment");
5381 if (byte_any_segment != char_any_segment)
5382 g_error ("char and byte offsets did not point to the same any segment");
5384 /* Make sure the segment offsets are equivalent, if it's a char
5386 if (char_segment->type == >k_text_char_type)
5388 gint byte_offset = 0;
5389 gint char_offset = 0;
5390 while (char_offset < seg_char_offset)
5392 const char * start = char_segment->body.chars + byte_offset;
5393 byte_offset += g_utf8_next_char (start) - start;
5397 if (byte_offset != seg_byte_offset)
5398 g_error ("byte offset did not correspond to char offset");
5401 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5403 if (char_offset != seg_char_offset)
5404 g_error ("char offset did not correspond to byte offset");
5406 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5407 g_error ("byte index for iterator does not index the start of a character");
5411 if (real->cached_line_number >= 0)
5415 should_be = _gtk_text_line_get_number (real->line);
5416 if (real->cached_line_number != should_be)
5417 g_error ("wrong line number was cached");
5420 if (real->cached_char_index >= 0)
5422 if (real->line_char_offset >= 0) /* only way we can check it
5423 efficiently, not a real
5428 char_index = _gtk_text_line_char_index (real->line);
5429 char_index += real->line_char_offset;
5431 if (real->cached_char_index != char_index)
5432 g_error ("wrong char index was cached");
5436 if (_gtk_text_line_is_last (real->line, real->tree))
5437 g_error ("Iterator was on last line (past the end iterator)");