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 * gtk_text_iter_forward_word_end:
3000 * @iter: a #GtkTextIter
3002 * Moves forward to the next word end. (If @iter is currently on a
3003 * word end, moves forward to the next one after that.) Word breaks
3004 * are determined by Pango and should be correct for nearly any
3005 * language (if not, the correct fix would be to the Pango word break
3008 * Return value: %TRUE if @iter moved and is not the end iterator
3011 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3013 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3017 * gtk_text_iter_backward_word_start:
3018 * @iter: a #GtkTextIter
3020 * Moves backward to the previous word start. (If @iter is currently on a
3021 * word start, moves backward to the next one after that.) Word breaks
3022 * are determined by Pango and should be correct for nearly any
3023 * language (if not, the correct fix would be to the Pango word break
3026 * Return value: %TRUE if @iter moved and is not the end iterator
3029 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3031 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3034 /* FIXME a loop around a truly slow function means
3035 * a truly spectacularly slow function.
3039 * gtk_text_iter_forward_word_ends:
3040 * @iter: a #GtkTextIter
3041 * @count: number of times to move
3043 * Calls gtk_text_iter_forward_word_end() up to @count times.
3045 * Return value: %TRUE if @iter moved and is not the end iterator
3048 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3051 g_return_val_if_fail (iter != NULL, FALSE);
3053 FIX_OVERFLOWS (count);
3059 return gtk_text_iter_backward_word_starts (iter, -count);
3061 if (!gtk_text_iter_forward_word_end (iter))
3067 if (!gtk_text_iter_forward_word_end (iter))
3072 return !gtk_text_iter_is_end (iter);
3076 * gtk_text_iter_backward_word_starts
3077 * @iter: a #GtkTextIter
3078 * @count: number of times to move
3080 * Calls gtk_text_iter_backward_word_start() up to @count times.
3082 * Return value: %TRUE if @iter moved and is not the end iterator
3085 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3088 g_return_val_if_fail (iter != NULL, FALSE);
3090 FIX_OVERFLOWS (count);
3093 return gtk_text_iter_forward_word_ends (iter, -count);
3095 if (!gtk_text_iter_backward_word_start (iter))
3101 if (!gtk_text_iter_backward_word_start (iter))
3106 return !gtk_text_iter_is_end (iter);
3110 * gtk_text_iter_starts_word:
3111 * @iter: a #GtkTextIter
3113 * Determines whether @iter begins a natural-language word. Word
3114 * breaks are determined by Pango and should be correct for nearly any
3115 * language (if not, the correct fix would be to the Pango word break
3118 * Return value: %TRUE if @iter is at the start of a word
3121 gtk_text_iter_starts_word (const GtkTextIter *iter)
3123 return test_log_attrs (iter, is_word_start_func);
3127 * gtk_text_iter_ends_word:
3128 * @iter: a #GtkTextIter
3130 * Determines whether @iter ends a natural-language word. Word breaks
3131 * are determined by Pango and should be correct for nearly any
3132 * language (if not, the correct fix would be to the Pango word break
3135 * Return value: %TRUE if @iter is at the end of a word
3138 gtk_text_iter_ends_word (const GtkTextIter *iter)
3140 return test_log_attrs (iter, is_word_end_func);
3144 * gtk_text_iter_inside_word:
3145 * @iter: a #GtkTextIter
3147 * Determines whether @iter is inside a natural-language word (as
3148 * opposed to say inside some whitespace). Word breaks are determined
3149 * by Pango and should be correct for nearly any language (if not, the
3150 * correct fix would be to the Pango word break algorithms).
3152 * Return value: %TRUE if @iter is inside a word
3155 gtk_text_iter_inside_word (const GtkTextIter *iter)
3157 return test_log_attrs (iter, inside_word_func);
3161 * gtk_text_iter_starts_sentence:
3162 * @iter: a #GtkTextIter
3164 * Determines whether @iter begins a sentence. Sentence boundaries are
3165 * determined by Pango and should be correct for nearly any language
3166 * (if not, the correct fix would be to the Pango text boundary
3169 * Return value: %TRUE if @iter is at the start of a sentence.
3172 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3174 return test_log_attrs (iter, is_sentence_start_func);
3178 * gtk_text_iter_ends_sentence:
3179 * @iter: a #GtkTextIter
3181 * Determines whether @iter ends a sentence. Sentence boundaries are
3182 * determined by Pango and should be correct for nearly any language
3183 * (if not, the correct fix would be to the Pango text boundary
3186 * Return value: %TRUE if @iter is at the end of a sentence.
3189 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3191 return test_log_attrs (iter, is_sentence_end_func);
3195 * gtk_text_iter_inside_sentence:
3196 * @iter: a #GtkTextIter
3198 * Determines whether @iter is inside a sentence (as opposed to in
3199 * between two sentences, e.g. after a period and before the first
3200 * letter of the next sentence). Sentence boundaries are determined
3201 * by Pango and should be correct for nearly any language (if not, the
3202 * correct fix would be to the Pango text boundary algorithms).
3204 * Return value: %TRUE if @iter is inside a sentence.
3207 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3209 return test_log_attrs (iter, inside_sentence_func);
3213 * gtk_text_iter_forward_sentence_end:
3214 * @iter: a #GtkTextIter
3216 * Moves forward to the next sentence end. (If @iter is at the end of
3217 * a sentence, moves to the next end of sentence.) Sentence
3218 * boundaries are determined by Pango and should be correct for nearly
3219 * any language (if not, the correct fix would be to the Pango text
3220 * boundary algorithms).
3222 * Return value: %TRUE if @iter moved and is not the end iterator
3225 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3227 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3231 * gtk_text_iter_backward_sentence_start:
3232 * @iter: a #GtkTextIter
3234 * Moves backward to the previous sentence start; if @iter is already at
3235 * the start of a sentence, moves backward to the next one. Sentence
3236 * boundaries are determined by Pango and should be correct for nearly
3237 * any language (if not, the correct fix would be to the Pango text
3238 * boundary algorithms).
3240 * Return value: %TRUE if @iter moved and is not the end iterator
3243 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3245 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3248 /* FIXME a loop around a truly slow function means
3249 * a truly spectacularly slow function.
3252 * gtk_text_iter_forward_sentence_ends:
3253 * @iter: a #GtkTextIter
3254 * @count: number of sentences to move
3256 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3257 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3258 * negative, moves backward instead of forward.
3260 * Return value: %TRUE if @iter moved and is not the end iterator
3263 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3266 g_return_val_if_fail (iter != NULL, FALSE);
3272 return gtk_text_iter_backward_sentence_starts (iter, -count);
3274 if (!gtk_text_iter_forward_sentence_end (iter))
3280 if (!gtk_text_iter_forward_sentence_end (iter))
3285 return !gtk_text_iter_is_end (iter);
3289 * gtk_text_iter_backward_sentence_starts:
3290 * @iter: a #GtkTextIter
3291 * @count: number of sentences to move
3293 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3294 * or until it returns %FALSE. If @count is negative, moves forward
3295 * instead of backward.
3297 * Return value: %TRUE if @iter moved and is not the end iterator
3300 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3303 g_return_val_if_fail (iter != NULL, FALSE);
3309 return gtk_text_iter_forward_sentence_ends (iter, -count);
3311 if (!gtk_text_iter_backward_sentence_start (iter))
3317 if (!gtk_text_iter_backward_sentence_start (iter))
3322 return !gtk_text_iter_is_end (iter);
3326 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3331 gboolean already_moved_initially)
3333 if (!already_moved_initially)
3336 while (offset < (min_offset + len) &&
3337 !attrs[offset].is_cursor_position)
3340 *found_offset = offset;
3342 return offset < (min_offset + len);
3346 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3351 gboolean already_moved_initially)
3353 if (!already_moved_initially)
3356 while (offset > min_offset &&
3357 !attrs[offset].is_cursor_position)
3360 *found_offset = offset;
3362 return offset >= min_offset;
3366 is_cursor_pos_func (const PangoLogAttr *attrs,
3371 return attrs[offset].is_cursor_position;
3375 * gtk_text_iter_forward_cursor_position:
3376 * @iter: a #GtkTextIter
3378 * Moves @iter forward by a single cursor position. Cursor positions
3379 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3380 * surprisingly, there may not be a cursor position between all
3381 * characters. The most common example for European languages would be
3382 * a carriage return/newline sequence. For some Unicode characters,
3383 * the equivalent of say the letter "a" with an accent mark will be
3384 * represented as two characters, first the letter then a "combining
3385 * mark" that causes the accent to be rendered; so the cursor can't go
3386 * between those two characters. See also the #PangoLogAttr structure and
3387 * pango_break() function.
3389 * Return value: %TRUE if we moved and the new position is dereferenceable
3392 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3394 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3398 * gtk_text_iter_backward_cursor_position:
3399 * @iter: a #GtkTextIter
3401 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3403 * Return value: %TRUE if we moved
3406 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3408 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3412 * gtk_text_iter_forward_cursor_positions:
3413 * @iter: a #GtkTextIter
3414 * @count: number of positions to move
3416 * Moves up to @count cursor positions. See
3417 * gtk_text_iter_forward_cursor_position() for details.
3419 * Return value: %TRUE if we moved and the new position is dereferenceable
3422 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3425 g_return_val_if_fail (iter != NULL, FALSE);
3427 FIX_OVERFLOWS (count);
3433 return gtk_text_iter_backward_cursor_positions (iter, -count);
3435 if (!gtk_text_iter_forward_cursor_position (iter))
3441 if (!gtk_text_iter_forward_cursor_position (iter))
3446 return !gtk_text_iter_is_end (iter);
3450 * gtk_text_iter_backward_cursor_positions:
3451 * @iter: a #GtkTextIter
3452 * @count: number of positions to move
3454 * Moves up to @count cursor positions. See
3455 * gtk_text_iter_forward_cursor_position() for details.
3457 * Return value: %TRUE if we moved and the new position is dereferenceable
3460 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3463 g_return_val_if_fail (iter != NULL, FALSE);
3465 FIX_OVERFLOWS (count);
3471 return gtk_text_iter_forward_cursor_positions (iter, -count);
3473 if (!gtk_text_iter_backward_cursor_position (iter))
3479 if (!gtk_text_iter_backward_cursor_position (iter))
3484 return !gtk_text_iter_is_end (iter);
3488 * gtk_text_iter_is_cursor_position:
3489 * @iter: a #GtkTextIter
3491 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3492 * pango_break() for details on what a cursor position is.
3494 * Return value: %TRUE if the cursor can be placed at @iter
3497 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3499 return test_log_attrs (iter, is_cursor_pos_func);
3503 * gtk_text_iter_set_line_offset:
3504 * @iter: a #GtkTextIter
3505 * @char_on_line: a character offset relative to the start of @iter's current line
3507 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3508 * (not byte) offset. The given character offset must be less than or
3509 * equal to the number of characters in the line; if equal, @iter
3510 * moves to the start of the next line. See
3511 * gtk_text_iter_set_line_index() if you have a byte index rather than
3512 * a character offset.
3516 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3519 GtkTextRealIter *real;
3522 g_return_if_fail (iter != NULL);
3524 real = gtk_text_iter_make_surreal (iter);
3529 check_invariants (iter);
3531 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3533 g_return_if_fail (char_on_line <= chars_in_line);
3535 if (char_on_line < chars_in_line)
3536 iter_set_from_char_offset (real, real->line, char_on_line);
3538 gtk_text_iter_forward_line (iter); /* set to start of next line */
3540 check_invariants (iter);
3544 * gtk_text_iter_set_line_index:
3545 * @iter: a #GtkTextIter
3546 * @byte_on_line: a byte index relative to the start of @iter's current line
3548 * Same as gtk_text_iter_set_line_offset(), but works with a
3549 * <emphasis>byte</emphasis> index. The given byte index must be at
3550 * the start of a character, it can't be in the middle of a UTF-8
3551 * encoded character.
3555 gtk_text_iter_set_line_index (GtkTextIter *iter,
3558 GtkTextRealIter *real;
3561 g_return_if_fail (iter != NULL);
3563 real = gtk_text_iter_make_surreal (iter);
3568 check_invariants (iter);
3570 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3572 g_return_if_fail (byte_on_line <= bytes_in_line);
3574 if (byte_on_line < bytes_in_line)
3575 iter_set_from_byte_offset (real, real->line, byte_on_line);
3577 gtk_text_iter_forward_line (iter);
3579 if (real->segment->type == >k_text_char_type &&
3580 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3581 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3582 "character; this will crash the text buffer. "
3583 "Byte indexes must refer to the start of a character.",
3584 G_STRLOC, byte_on_line);
3586 check_invariants (iter);
3591 * gtk_text_iter_set_visible_line_offset:
3592 * @iter: a #GtkTextIter
3593 * @char_on_line: a character offset
3595 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3596 * characters, i.e. text with a tag making it invisible is not
3597 * counted in the offset.
3600 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3603 gint chars_seen = 0;
3606 g_return_if_fail (iter != NULL);
3610 /* For now we use a ludicrously slow implementation */
3611 while (chars_seen < char_on_line)
3613 if (!_gtk_text_btree_char_is_invisible (&pos))
3616 if (!gtk_text_iter_forward_char (&pos))
3619 if (chars_seen == char_on_line)
3623 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3626 gtk_text_iter_forward_line (iter);
3630 bytes_in_char (GtkTextIter *iter)
3632 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3636 * gtk_text_iter_set_visible_line_index:
3637 * @iter: a #GtkTextIter
3638 * @byte_on_line: a byte index
3640 * Like gtk_text_iter_set_line_index(), but the index is in visible
3641 * bytes, i.e. text with a tag making it invisible is not counted
3645 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3648 gint bytes_seen = 0;
3651 g_return_if_fail (iter != NULL);
3655 /* For now we use a ludicrously slow implementation */
3656 while (bytes_seen < byte_on_line)
3658 if (!_gtk_text_btree_char_is_invisible (&pos))
3659 bytes_seen += bytes_in_char (&pos);
3661 if (!gtk_text_iter_forward_char (&pos))
3664 if (bytes_seen >= byte_on_line)
3668 if (bytes_seen > byte_on_line)
3669 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3670 "character; this will crash the text buffer. "
3671 "Byte indexes must refer to the start of a character.",
3672 G_STRLOC, byte_on_line);
3674 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3677 gtk_text_iter_forward_line (iter);
3681 * gtk_text_iter_set_line:
3682 * @iter: a #GtkTextIter
3683 * @line_number: line number (counted from 0)
3685 * Moves iterator @iter to the start of the line @line_number. If
3686 * @line_number is negative or larger than the number of lines in the
3687 * buffer, moves @iter to the start of the last line in the buffer.
3691 gtk_text_iter_set_line (GtkTextIter *iter,
3696 GtkTextRealIter *real;
3698 g_return_if_fail (iter != NULL);
3700 real = gtk_text_iter_make_surreal (iter);
3705 check_invariants (iter);
3707 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3709 iter_set_from_char_offset (real, line, 0);
3711 /* We might as well cache this, since we know it. */
3712 real->cached_line_number = real_line;
3714 check_invariants (iter);
3718 * gtk_text_iter_set_offset:
3719 * @iter: a #GtkTextIter
3720 * @char_offset: a character number
3722 * Sets @iter to point to @char_offset. @char_offset counts from the start
3723 * of the entire text buffer, starting with 0.
3726 gtk_text_iter_set_offset (GtkTextIter *iter,
3730 GtkTextRealIter *real;
3732 gint real_char_index;
3734 g_return_if_fail (iter != NULL);
3736 real = gtk_text_iter_make_surreal (iter);
3741 check_invariants (iter);
3743 if (real->cached_char_index >= 0 &&
3744 real->cached_char_index == char_offset)
3747 line = _gtk_text_btree_get_line_at_char (real->tree,
3752 iter_set_from_char_offset (real, line, real_char_index - line_start);
3754 /* Go ahead and cache this since we have it. */
3755 real->cached_char_index = real_char_index;
3757 check_invariants (iter);
3761 * gtk_text_iter_forward_to_end:
3762 * @iter: a #GtkTextIter
3764 * Moves @iter forward to the "end iterator," which points one past the last
3765 * valid character in the buffer. gtk_text_iter_get_char() called on the
3766 * end iterator returns 0, which is convenient for writing loops.
3769 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3771 GtkTextBuffer *buffer;
3772 GtkTextRealIter *real;
3774 g_return_if_fail (iter != NULL);
3776 real = gtk_text_iter_make_surreal (iter);
3781 buffer = _gtk_text_btree_get_buffer (real->tree);
3783 gtk_text_buffer_get_end_iter (buffer, iter);
3786 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3787 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3788 * If all else fails we could cache the para delimiter pos in the iter.
3789 * I think forward_to_line_end() actually gets called fairly often.
3792 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3797 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3798 _gtk_text_iter_get_btree (&end)))
3800 gtk_text_iter_forward_to_end (&end);
3804 /* if we aren't on the last line, go forward to start of next line, then scan
3805 * back for the delimiters on the previous line
3807 gtk_text_iter_forward_line (&end);
3808 gtk_text_iter_backward_char (&end);
3809 while (!gtk_text_iter_ends_line (&end))
3810 gtk_text_iter_backward_char (&end);
3813 return gtk_text_iter_get_line_offset (&end);
3817 * gtk_text_iter_forward_to_line_end:
3818 * @iter: a #GtkTextIter
3820 * Moves the iterator to point to the paragraph delimiter characters,
3821 * which will be either a newline, a carriage return, a carriage
3822 * return/newline in sequence, or the Unicode paragraph separator
3823 * character. If the iterator is already at the paragraph delimiter
3824 * characters, moves to the paragraph delimiter characters for the
3825 * next line. If @iter is on the last line in the buffer, which does
3826 * not end in paragraph delimiters, moves to the end iterator (end of
3827 * the last line), and returns %FALSE.
3829 * Return value: %TRUE if we moved and the new location is not the end iterator
3832 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3834 gint current_offset;
3838 g_return_val_if_fail (iter != NULL, FALSE);
3840 current_offset = gtk_text_iter_get_line_offset (iter);
3841 new_offset = find_paragraph_delimiter_for_line (iter);
3843 if (current_offset < new_offset)
3845 /* Move to end of this line. */
3846 gtk_text_iter_set_line_offset (iter, new_offset);
3847 return !gtk_text_iter_is_end (iter);
3851 /* Move to end of next line. */
3852 if (gtk_text_iter_forward_line (iter))
3854 /* We don't want to move past all
3857 if (!gtk_text_iter_ends_line (iter))
3858 gtk_text_iter_forward_to_line_end (iter);
3859 return !gtk_text_iter_is_end (iter);
3867 * gtk_text_iter_forward_to_tag_toggle:
3868 * @iter: a #GtkTextIter
3869 * @tag: a #GtkTextTag, or %NULL
3871 * Moves forward to the next toggle (on or off) of the
3872 * #GtkTextTag @tag, or to the next toggle of any tag if
3873 * @tag is %NULL. If no matching tag toggles are found,
3874 * returns %FALSE, otherwise %TRUE. Does not return toggles
3875 * located at @iter, only toggles after @iter. Sets @iter to
3876 * the location of the toggle, or to the end of the buffer
3877 * if no toggle is found.
3879 * Return value: whether we found a tag toggle after @iter
3882 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3885 GtkTextLine *next_line;
3886 GtkTextLine *current_line;
3887 GtkTextRealIter *real;
3889 g_return_val_if_fail (iter != NULL, FALSE);
3891 real = gtk_text_iter_make_real (iter);
3896 check_invariants (iter);
3898 current_line = real->line;
3899 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3902 while (_gtk_text_iter_forward_indexable_segment (iter))
3904 /* If we went forward to a line that couldn't contain a toggle
3905 for the tag, then skip forward to a line that could contain
3906 it. This potentially skips huge hunks of the tree, so we
3907 aren't a purely linear search. */
3908 if (real->line != current_line)
3910 if (next_line == NULL)
3912 /* End of search. Set to end of buffer. */
3913 _gtk_text_btree_get_end_iter (real->tree, iter);
3917 if (real->line != next_line)
3918 iter_set_from_byte_offset (real, next_line, 0);
3920 current_line = real->line;
3921 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3926 if (gtk_text_iter_toggles_tag (iter, tag))
3928 /* If there's a toggle here, it isn't indexable so
3929 any_segment can't be the indexable segment. */
3930 g_assert (real->any_segment != real->segment);
3935 /* Check end iterator for tags */
3936 if (gtk_text_iter_toggles_tag (iter, tag))
3938 /* If there's a toggle here, it isn't indexable so
3939 any_segment can't be the indexable segment. */
3940 g_assert (real->any_segment != real->segment);
3944 /* Reached end of buffer */
3949 * gtk_text_iter_backward_to_tag_toggle:
3950 * @iter: a #GtkTextIter
3951 * @tag: a #GtkTextTag, or %NULL
3953 * Moves backward to the next toggle (on or off) of the
3954 * #GtkTextTag @tag, or to the next toggle of any tag if
3955 * @tag is %NULL. If no matching tag toggles are found,
3956 * returns %FALSE, otherwise %TRUE. Does not return toggles
3957 * located at @iter, only toggles before @iter. Sets @iter
3958 * to the location of the toggle, or the start of the buffer
3959 * if no toggle is found.
3961 * Return value: whether we found a tag toggle before @iter
3964 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3967 GtkTextLine *prev_line;
3968 GtkTextLine *current_line;
3969 GtkTextRealIter *real;
3971 g_return_val_if_fail (iter != NULL, FALSE);
3973 real = gtk_text_iter_make_real (iter);
3978 check_invariants (iter);
3980 current_line = real->line;
3981 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3985 /* If we're at segment start, go to the previous segment;
3986 * if mid-segment, snap to start of current segment.
3988 if (is_segment_start (real))
3990 if (!_gtk_text_iter_backward_indexable_segment (iter))
3995 ensure_char_offsets (real);
3997 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4003 /* If we went backward to a line that couldn't contain a toggle
4004 * for the tag, then skip backward further to a line that
4005 * could contain it. This potentially skips huge hunks of the
4006 * tree, so we aren't a purely linear search.
4008 if (real->line != current_line)
4010 if (prev_line == NULL)
4012 /* End of search. Set to start of buffer. */
4013 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4017 if (real->line != prev_line)
4019 /* Set to last segment in prev_line (could do this
4022 iter_set_from_byte_offset (real, prev_line, 0);
4024 while (!at_last_indexable_segment (real))
4025 _gtk_text_iter_forward_indexable_segment (iter);
4028 current_line = real->line;
4029 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4034 if (gtk_text_iter_toggles_tag (iter, tag))
4036 /* If there's a toggle here, it isn't indexable so
4037 * any_segment can't be the indexable segment.
4039 g_assert (real->any_segment != real->segment);
4043 while (_gtk_text_iter_backward_indexable_segment (iter));
4045 /* Reached front of buffer */
4050 matches_pred (GtkTextIter *iter,
4051 GtkTextCharPredicate pred,
4056 ch = gtk_text_iter_get_char (iter);
4058 return (*pred) (ch, user_data);
4062 * gtk_text_iter_forward_find_char:
4063 * @iter: a #GtkTextIter
4064 * @pred: a function to be called on each character
4065 * @user_data: user data for @pred
4066 * @limit: search limit, or %NULL for none
4068 * Advances @iter, calling @pred on each character. If
4069 * @pred returns %TRUE, returns %TRUE and stops scanning.
4070 * If @pred never returns %TRUE, @iter is set to @limit if
4071 * @limit is non-%NULL, otherwise to the end iterator.
4073 * Return value: whether a match was found
4076 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4077 GtkTextCharPredicate pred,
4079 const GtkTextIter *limit)
4081 g_return_val_if_fail (iter != NULL, FALSE);
4082 g_return_val_if_fail (pred != NULL, FALSE);
4085 gtk_text_iter_compare (iter, limit) >= 0)
4088 while ((limit == NULL ||
4089 !gtk_text_iter_equal (limit, iter)) &&
4090 gtk_text_iter_forward_char (iter))
4092 if (matches_pred (iter, pred, user_data))
4100 * gtk_text_iter_backward_find_char:
4101 * @iter: a #GtkTextIter
4102 * @pred: function to be called on each character
4103 * @user_data: user data for @pred
4104 * @limit: search limit, or %NULL for none
4106 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4108 * Return value: whether a match was found
4111 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4112 GtkTextCharPredicate pred,
4114 const GtkTextIter *limit)
4116 g_return_val_if_fail (iter != NULL, FALSE);
4117 g_return_val_if_fail (pred != NULL, FALSE);
4120 gtk_text_iter_compare (iter, limit) <= 0)
4123 while ((limit == NULL ||
4124 !gtk_text_iter_equal (limit, iter)) &&
4125 gtk_text_iter_backward_char (iter))
4127 if (matches_pred (iter, pred, user_data))
4135 forward_chars_with_skipping (GtkTextIter *iter,
4137 gboolean skip_invisible,
4138 gboolean skip_nontext)
4143 g_return_if_fail (count >= 0);
4149 gboolean ignored = FALSE;
4152 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4157 _gtk_text_btree_char_is_invisible (iter))
4160 gtk_text_iter_forward_char (iter);
4168 lines_match (const GtkTextIter *start,
4169 const gchar **lines,
4170 gboolean visible_only,
4172 GtkTextIter *match_start,
4173 GtkTextIter *match_end)
4180 if (*lines == NULL || **lines == '\0')
4183 *match_start = *start;
4186 *match_end = *start;
4191 gtk_text_iter_forward_line (&next);
4193 /* No more text in buffer, but *lines is nonempty */
4194 if (gtk_text_iter_equal (start, &next))
4202 line_text = gtk_text_iter_get_visible_slice (start, &next);
4204 line_text = gtk_text_iter_get_slice (start, &next);
4209 line_text = gtk_text_iter_get_visible_text (start, &next);
4211 line_text = gtk_text_iter_get_text (start, &next);
4214 if (match_start) /* if this is the first line we're matching */
4215 found = strstr (line_text, *lines);
4218 /* If it's not the first line, we have to match from the
4219 * start of the line.
4221 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4233 /* Get offset to start of search string */
4234 offset = g_utf8_strlen (line_text, found - line_text);
4238 /* If match start needs to be returned, set it to the
4239 * start of the search string.
4243 *match_start = next;
4245 forward_chars_with_skipping (match_start, offset,
4246 visible_only, !slice);
4249 /* Go to end of search string */
4250 offset += g_utf8_strlen (*lines, -1);
4252 forward_chars_with_skipping (&next, offset,
4253 visible_only, !slice);
4262 /* pass NULL for match_start, since we don't need to find the
4265 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4268 /* strsplit () that retains the delimiter as part of the string. */
4270 strbreakup (const char *string,
4271 const char *delimiter,
4274 GSList *string_list = NULL, *slist;
4275 gchar **str_array, *s;
4278 g_return_val_if_fail (string != NULL, NULL);
4279 g_return_val_if_fail (delimiter != NULL, NULL);
4282 max_tokens = G_MAXINT;
4284 s = strstr (string, delimiter);
4287 guint delimiter_len = strlen (delimiter);
4294 len = s - string + delimiter_len;
4295 new_string = g_new (gchar, len + 1);
4296 strncpy (new_string, string, len);
4297 new_string[len] = 0;
4298 string_list = g_slist_prepend (string_list, new_string);
4300 string = s + delimiter_len;
4301 s = strstr (string, delimiter);
4303 while (--max_tokens && s);
4308 string_list = g_slist_prepend (string_list, g_strdup (string));
4311 str_array = g_new (gchar*, n);
4315 str_array[i--] = NULL;
4316 for (slist = string_list; slist; slist = slist->next)
4317 str_array[i--] = slist->data;
4319 g_slist_free (string_list);
4325 * gtk_text_iter_forward_search:
4326 * @iter: start of search
4327 * @str: a search string
4328 * @flags: flags affecting how the search is done
4329 * @match_start: return location for start of match, or %NULL
4330 * @match_end: return location for end of match, or %NULL
4331 * @limit: bound for the search, or %NULL for the end of the buffer
4333 * Searches forward for @str. Any match is returned by setting
4334 * @match_start to the first character of the match and @match_end to the
4335 * first character after the match. The search will not continue past
4336 * @limit. Note that a search is a linear or O(n) operation, so you
4337 * may wish to use @limit to avoid locking up your UI on large
4340 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4341 * have invisible text interspersed in @str. i.e. @str will be a
4342 * possibly-noncontiguous subsequence of the matched range. similarly,
4343 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4344 * pixbufs or child widgets mixed inside the matched range. If these
4345 * flags are not given, the match must be exact; the special 0xFFFC
4346 * character in @str will match embedded pixbufs or child widgets.
4348 * Return value: whether a match was found
4351 gtk_text_iter_forward_search (const GtkTextIter *iter,
4353 GtkTextSearchFlags flags,
4354 GtkTextIter *match_start,
4355 GtkTextIter *match_end,
4356 const GtkTextIter *limit)
4358 gchar **lines = NULL;
4360 gboolean retval = FALSE;
4362 gboolean visible_only;
4365 g_return_val_if_fail (iter != NULL, FALSE);
4366 g_return_val_if_fail (str != NULL, FALSE);
4369 gtk_text_iter_compare (iter, limit) >= 0)
4374 /* If we can move one char, return the empty string there */
4377 if (gtk_text_iter_forward_char (&match))
4380 gtk_text_iter_equal (&match, limit))
4384 *match_start = match;
4393 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4394 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4396 /* locate all lines */
4398 lines = strbreakup (str, "\n", -1);
4404 /* This loop has an inefficient worst-case, where
4405 * gtk_text_iter_get_text () is called repeatedly on
4411 gtk_text_iter_compare (&search, limit) >= 0)
4414 if (lines_match (&search, (const gchar**)lines,
4415 visible_only, slice, &match, &end))
4417 if (limit == NULL ||
4419 gtk_text_iter_compare (&end, limit) < 0))
4424 *match_start = match;
4433 while (gtk_text_iter_forward_line (&search));
4435 g_strfreev ((gchar**)lines);
4441 vectors_equal_ignoring_trailing (gchar **vec1,
4444 /* Ignores trailing chars in vec2's last line */
4453 if (strcmp (*i1, *i2) != 0)
4455 if (*(i2 + 1) == NULL) /* if this is the last line */
4457 gint len1 = strlen (*i1);
4458 gint len2 = strlen (*i2);
4461 strncmp (*i1, *i2, len1) == 0)
4463 /* We matched ignoring the trailing stuff in vec2 */
4488 typedef struct _LinesWindow LinesWindow;
4494 GtkTextIter first_line_start;
4495 GtkTextIter first_line_end;
4497 gboolean visible_only;
4501 lines_window_init (LinesWindow *win,
4502 const GtkTextIter *start)
4505 GtkTextIter line_start;
4506 GtkTextIter line_end;
4508 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4511 if (gtk_text_iter_is_start (start) ||
4512 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4514 /* Already at the end, or not enough lines to match */
4515 win->lines = g_new0 (gchar*, 1);
4520 line_start = *start;
4523 /* Move to start iter to start of line */
4524 gtk_text_iter_set_line_offset (&line_start, 0);
4526 if (gtk_text_iter_equal (&line_start, &line_end))
4528 /* we were already at the start; so go back one line */
4529 gtk_text_iter_backward_line (&line_start);
4532 win->first_line_start = line_start;
4533 win->first_line_end = line_end;
4535 win->lines = g_new0 (gchar*, win->n_lines + 1);
4537 i = win->n_lines - 1;
4544 if (win->visible_only)
4545 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4547 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4551 if (win->visible_only)
4552 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4554 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4557 win->lines[i] = line_text;
4559 line_end = line_start;
4560 gtk_text_iter_backward_line (&line_start);
4567 lines_window_back (LinesWindow *win)
4569 GtkTextIter new_start;
4572 new_start = win->first_line_start;
4574 if (!gtk_text_iter_backward_line (&new_start))
4578 win->first_line_start = new_start;
4579 win->first_line_end = new_start;
4581 gtk_text_iter_forward_line (&win->first_line_end);
4586 if (win->visible_only)
4587 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4588 &win->first_line_end);
4590 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4591 &win->first_line_end);
4595 if (win->visible_only)
4596 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4597 &win->first_line_end);
4599 line_text = gtk_text_iter_get_text (&win->first_line_start,
4600 &win->first_line_end);
4603 /* Move lines to make room for first line. */
4604 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4606 *win->lines = line_text;
4608 /* Free old last line and NULL-terminate */
4609 g_free (win->lines[win->n_lines]);
4610 win->lines[win->n_lines] = NULL;
4616 lines_window_free (LinesWindow *win)
4618 g_strfreev (win->lines);
4622 my_strrstr (const gchar *haystack,
4623 const gchar *needle)
4625 /* FIXME GLib should have a nice implementation in it, this
4629 gint haystack_len = strlen (haystack);
4630 gint needle_len = strlen (needle);
4631 const gchar *needle_end = needle + needle_len;
4632 const gchar *haystack_rend = haystack - 1;
4633 const gchar *needle_rend = needle - 1;
4636 p = haystack + haystack_len;
4637 while (p != haystack)
4639 const gchar *n = needle_end - 1;
4640 const gchar *s = p - 1;
4641 while (s != haystack_rend &&
4649 if (n == needle_rend)
4659 * gtk_text_iter_backward_search:
4660 * @iter: a #GtkTextIter where the search begins
4661 * @str: search string
4662 * @flags: bitmask of flags affecting the search
4663 * @match_start: return location for start of match, or %NULL
4664 * @match_end: return location for end of match, or %NULL
4665 * @limit: location of last possible @match_start, or %NULL for start of buffer
4667 * Same as gtk_text_iter_forward_search(), but moves backward.
4669 * Return value: whether a match was found
4672 gtk_text_iter_backward_search (const GtkTextIter *iter,
4674 GtkTextSearchFlags flags,
4675 GtkTextIter *match_start,
4676 GtkTextIter *match_end,
4677 const GtkTextIter *limit)
4679 gchar **lines = NULL;
4683 gboolean retval = FALSE;
4684 gboolean visible_only;
4687 g_return_val_if_fail (iter != NULL, FALSE);
4688 g_return_val_if_fail (str != NULL, FALSE);
4691 gtk_text_iter_compare (limit, iter) > 0)
4696 /* If we can move one char, return the empty string there */
4697 GtkTextIter match = *iter;
4699 if (limit && gtk_text_iter_equal (limit, &match))
4702 if (gtk_text_iter_backward_char (&match))
4705 *match_start = match;
4714 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4715 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4717 /* locate all lines */
4719 lines = strbreakup (str, "\n", -1);
4729 win.n_lines = n_lines;
4731 win.visible_only = visible_only;
4733 lines_window_init (&win, iter);
4735 if (*win.lines == NULL)
4740 gchar *first_line_match;
4743 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4745 /* We're now before the search limit, abort. */
4749 /* If there are multiple lines, the first line will
4750 * end in '\n', so this will only match at the
4751 * end of the first line, which is correct.
4753 first_line_match = my_strrstr (*win.lines, *lines);
4755 if (first_line_match &&
4756 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4761 GtkTextIter start_tmp;
4763 /* Offset to start of search string */
4764 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4766 next = win.first_line_start;
4768 forward_chars_with_skipping (&start_tmp, offset,
4769 visible_only, !slice);
4772 gtk_text_iter_compare (limit, &start_tmp) > 0)
4773 goto out; /* match was bogus */
4776 *match_start = start_tmp;
4778 /* Go to end of search string */
4782 offset += g_utf8_strlen (*l, -1);
4786 forward_chars_with_skipping (&next, offset,
4787 visible_only, !slice);
4796 while (lines_window_back (&win));
4799 lines_window_free (&win);
4810 * gtk_text_iter_equal:
4811 * @lhs: a #GtkTextIter
4812 * @rhs: another #GtkTextIter
4814 * Tests whether two iterators are equal, using the fastest possible
4815 * mechanism. This function is very fast; you can expect it to perform
4816 * better than e.g. getting the character offset for each iterator and
4817 * comparing the offsets yourself. Also, it's a bit faster than
4818 * gtk_text_iter_compare().
4820 * Return value: %TRUE if the iterators point to the same place in the buffer
4823 gtk_text_iter_equal (const GtkTextIter *lhs,
4824 const GtkTextIter *rhs)
4826 GtkTextRealIter *real_lhs;
4827 GtkTextRealIter *real_rhs;
4829 real_lhs = (GtkTextRealIter*)lhs;
4830 real_rhs = (GtkTextRealIter*)rhs;
4832 check_invariants (lhs);
4833 check_invariants (rhs);
4835 if (real_lhs->line != real_rhs->line)
4837 else if (real_lhs->line_byte_offset >= 0 &&
4838 real_rhs->line_byte_offset >= 0)
4839 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4842 /* the ensure_char_offsets () calls do nothing if the char offsets
4843 are already up-to-date. */
4844 ensure_char_offsets (real_lhs);
4845 ensure_char_offsets (real_rhs);
4846 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4851 * gtk_text_iter_compare:
4852 * @lhs: a #GtkTextIter
4853 * @rhs: another #GtkTextIter
4855 * A qsort()-style function that returns negative if @lhs is less than
4856 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4857 * Ordering is in character offset order, i.e. the first character in the buffer
4858 * is less than the second character in the buffer.
4860 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4863 gtk_text_iter_compare (const GtkTextIter *lhs,
4864 const GtkTextIter *rhs)
4866 GtkTextRealIter *real_lhs;
4867 GtkTextRealIter *real_rhs;
4869 real_lhs = gtk_text_iter_make_surreal (lhs);
4870 real_rhs = gtk_text_iter_make_surreal (rhs);
4872 if (real_lhs == NULL ||
4874 return -1; /* why not */
4876 check_invariants (lhs);
4877 check_invariants (rhs);
4879 if (real_lhs->line == real_rhs->line)
4881 gint left_index, right_index;
4883 if (real_lhs->line_byte_offset >= 0 &&
4884 real_rhs->line_byte_offset >= 0)
4886 left_index = real_lhs->line_byte_offset;
4887 right_index = real_rhs->line_byte_offset;
4891 /* the ensure_char_offsets () calls do nothing if
4892 the offsets are already up-to-date. */
4893 ensure_char_offsets (real_lhs);
4894 ensure_char_offsets (real_rhs);
4895 left_index = real_lhs->line_char_offset;
4896 right_index = real_rhs->line_char_offset;
4899 if (left_index < right_index)
4901 else if (left_index > right_index)
4910 line1 = gtk_text_iter_get_line (lhs);
4911 line2 = gtk_text_iter_get_line (rhs);
4914 else if (line1 > line2)
4922 * gtk_text_iter_in_range:
4923 * @iter: a #GtkTextIter
4924 * @start: start of range
4925 * @end: end of range
4927 * Checks whether @iter falls in the range [@start, @end).
4928 * @start and @end must be in ascending order.
4930 * Return value: %TRUE if @iter is in the range
4933 gtk_text_iter_in_range (const GtkTextIter *iter,
4934 const GtkTextIter *start,
4935 const GtkTextIter *end)
4937 g_return_val_if_fail (iter != NULL, FALSE);
4938 g_return_val_if_fail (start != NULL, FALSE);
4939 g_return_val_if_fail (end != NULL, FALSE);
4940 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4942 return gtk_text_iter_compare (iter, start) >= 0 &&
4943 gtk_text_iter_compare (iter, end) < 0;
4947 * gtk_text_iter_order:
4948 * @first: a #GtkTextIter
4949 * @second: another #GtkTextIter
4951 * Swaps the value of @first and @second if @second comes before
4952 * @first in the buffer. That is, ensures that @first and @second are
4953 * in sequence. Most text buffer functions that take a range call this
4954 * automatically on your behalf, so there's no real reason to call it yourself
4955 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4956 * that expect a pre-sorted range.
4960 gtk_text_iter_order (GtkTextIter *first,
4961 GtkTextIter *second)
4963 g_return_if_fail (first != NULL);
4964 g_return_if_fail (second != NULL);
4966 if (gtk_text_iter_compare (first, second) > 0)
4977 * Init iterators from the BTree
4981 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4985 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4986 gint real_char_index;
4990 g_return_if_fail (iter != NULL);
4991 g_return_if_fail (tree != NULL);
4993 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4994 &line_start, &real_char_index);
4996 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4998 real->cached_char_index = real_char_index;
5000 check_invariants (iter);
5004 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5009 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5013 g_return_if_fail (iter != NULL);
5014 g_return_if_fail (tree != NULL);
5016 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5018 iter_init_from_char_offset (iter, tree, line, char_on_line);
5020 /* We might as well cache this, since we know it. */
5021 real->cached_line_number = real_line;
5023 check_invariants (iter);
5027 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5032 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5036 g_return_if_fail (iter != NULL);
5037 g_return_if_fail (tree != NULL);
5039 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5041 iter_init_from_byte_offset (iter, tree, line, byte_index);
5043 /* We might as well cache this, since we know it. */
5044 real->cached_line_number = real_line;
5046 check_invariants (iter);
5050 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5055 g_return_if_fail (iter != NULL);
5056 g_return_if_fail (tree != NULL);
5057 g_return_if_fail (line != NULL);
5059 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5061 check_invariants (iter);
5065 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5071 g_return_val_if_fail (iter != NULL, FALSE);
5072 g_return_val_if_fail (tree != NULL, FALSE);
5074 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5078 /* Set iter to last in tree */
5079 _gtk_text_btree_get_end_iter (tree, iter);
5080 check_invariants (iter);
5085 iter_init_from_byte_offset (iter, tree, line, 0);
5087 if (!gtk_text_iter_toggles_tag (iter, tag))
5088 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5090 check_invariants (iter);
5096 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5100 g_return_val_if_fail (iter != NULL, FALSE);
5101 g_return_val_if_fail (tree != NULL, FALSE);
5103 _gtk_text_btree_get_end_iter (tree, iter);
5104 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5105 check_invariants (iter);
5111 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5113 const gchar *mark_name)
5117 g_return_val_if_fail (iter != NULL, FALSE);
5118 g_return_val_if_fail (tree != NULL, FALSE);
5120 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5126 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5127 check_invariants (iter);
5133 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5137 GtkTextLineSegment *seg;
5139 g_return_if_fail (iter != NULL);
5140 g_return_if_fail (tree != NULL);
5141 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5143 seg = mark->segment;
5145 iter_init_from_segment (iter, tree,
5146 seg->body.mark.line, seg);
5147 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5148 check_invariants (iter);
5152 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5154 GtkTextChildAnchor *anchor)
5156 GtkTextLineSegment *seg;
5158 g_return_if_fail (iter != NULL);
5159 g_return_if_fail (tree != NULL);
5160 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5162 seg = anchor->segment;
5164 g_assert (seg->body.child.line != NULL);
5166 iter_init_from_segment (iter, tree,
5167 seg->body.child.line, seg);
5168 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5169 check_invariants (iter);
5173 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5176 g_return_if_fail (iter != NULL);
5177 g_return_if_fail (tree != NULL);
5179 _gtk_text_btree_get_iter_at_char (tree,
5181 _gtk_text_btree_char_count (tree));
5182 check_invariants (iter);
5186 _gtk_text_iter_check (const GtkTextIter *iter)
5188 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5189 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5190 GtkTextLineSegment *byte_segment = NULL;
5191 GtkTextLineSegment *byte_any_segment = NULL;
5192 GtkTextLineSegment *char_segment = NULL;
5193 GtkTextLineSegment *char_any_segment = NULL;
5194 gboolean segments_updated;
5196 /* This function checks our class invariants for the Iter class. */
5198 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5200 if (real->chars_changed_stamp !=
5201 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5202 g_error ("iterator check failed: invalid iterator");
5204 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5205 g_error ("iterator check failed: both char and byte offsets are invalid");
5207 segments_updated = (real->segments_changed_stamp ==
5208 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5211 printf ("checking iter, segments %s updated, byte %d char %d\n",
5212 segments_updated ? "are" : "aren't",
5213 real->line_byte_offset,
5214 real->line_char_offset);
5217 if (segments_updated)
5219 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5220 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5222 if (real->segment->char_count == 0)
5223 g_error ("iterator check failed: segment is not indexable.");
5225 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5226 g_error ("segment char offset is not properly up-to-date");
5228 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5229 g_error ("segment byte offset is not properly up-to-date");
5231 if (real->segment_byte_offset >= 0 &&
5232 real->segment_byte_offset >= real->segment->byte_count)
5233 g_error ("segment byte offset is too large.");
5235 if (real->segment_char_offset >= 0 &&
5236 real->segment_char_offset >= real->segment->char_count)
5237 g_error ("segment char offset is too large.");
5240 if (real->line_byte_offset >= 0)
5242 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5243 &byte_segment, &byte_any_segment,
5244 &seg_byte_offset, &line_byte_offset);
5246 if (line_byte_offset != real->line_byte_offset)
5247 g_error ("wrong byte offset was stored in iterator");
5249 if (segments_updated)
5251 if (real->segment != byte_segment)
5252 g_error ("wrong segment was stored in iterator");
5254 if (real->any_segment != byte_any_segment)
5255 g_error ("wrong any_segment was stored in iterator");
5257 if (seg_byte_offset != real->segment_byte_offset)
5258 g_error ("wrong segment byte offset was stored in iterator");
5260 if (byte_segment->type == >k_text_char_type)
5263 p = byte_segment->body.chars + seg_byte_offset;
5265 if (!gtk_text_byte_begins_utf8_char (p))
5266 g_error ("broken iterator byte index pointed into the middle of a character");
5271 if (real->line_char_offset >= 0)
5273 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5274 &char_segment, &char_any_segment,
5275 &seg_char_offset, &line_char_offset);
5277 if (line_char_offset != real->line_char_offset)
5278 g_error ("wrong char offset was stored in iterator");
5280 if (segments_updated)
5282 if (real->segment != char_segment)
5283 g_error ("wrong segment was stored in iterator");
5285 if (real->any_segment != char_any_segment)
5286 g_error ("wrong any_segment was stored in iterator");
5288 if (seg_char_offset != real->segment_char_offset)
5289 g_error ("wrong segment char offset was stored in iterator");
5291 if (char_segment->type == >k_text_char_type)
5294 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5297 /* hmm, not likely to happen eh */
5298 if (!gtk_text_byte_begins_utf8_char (p))
5299 g_error ("broken iterator char offset pointed into the middle of a character");
5304 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5306 if (byte_segment != char_segment)
5307 g_error ("char and byte offsets did not point to the same segment");
5309 if (byte_any_segment != char_any_segment)
5310 g_error ("char and byte offsets did not point to the same any segment");
5312 /* Make sure the segment offsets are equivalent, if it's a char
5314 if (char_segment->type == >k_text_char_type)
5316 gint byte_offset = 0;
5317 gint char_offset = 0;
5318 while (char_offset < seg_char_offset)
5320 const char * start = char_segment->body.chars + byte_offset;
5321 byte_offset += g_utf8_next_char (start) - start;
5325 if (byte_offset != seg_byte_offset)
5326 g_error ("byte offset did not correspond to char offset");
5329 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5331 if (char_offset != seg_char_offset)
5332 g_error ("char offset did not correspond to byte offset");
5334 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5335 g_error ("byte index for iterator does not index the start of a character");
5339 if (real->cached_line_number >= 0)
5343 should_be = _gtk_text_line_get_number (real->line);
5344 if (real->cached_line_number != should_be)
5345 g_error ("wrong line number was cached");
5348 if (real->cached_char_index >= 0)
5350 if (real->line_char_offset >= 0) /* only way we can check it
5351 efficiently, not a real
5356 char_index = _gtk_text_line_char_index (real->line);
5357 char_index += real->line_char_offset;
5359 if (real->cached_char_index != char_index)
5360 g_error ("wrong char index was cached");
5364 if (_gtk_text_line_is_last (real->line, real->tree))
5365 g_error ("Iterator was on last line (past the end iterator)");