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);
3306 return gtk_text_iter_forward_sentence_ends (iter, -count);
3308 if (!gtk_text_iter_backward_sentence_start (iter))
3314 if (!gtk_text_iter_backward_sentence_start (iter))
3319 return !gtk_text_iter_is_end (iter);
3323 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3328 gboolean already_moved_initially)
3330 if (!already_moved_initially)
3333 while (offset < (min_offset + len) &&
3334 !attrs[offset].is_cursor_position)
3337 *found_offset = offset;
3339 return offset < (min_offset + len);
3343 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3348 gboolean already_moved_initially)
3350 if (!already_moved_initially)
3353 while (offset > min_offset &&
3354 !attrs[offset].is_cursor_position)
3357 *found_offset = offset;
3359 return offset >= min_offset;
3363 is_cursor_pos_func (const PangoLogAttr *attrs,
3368 return attrs[offset].is_cursor_position;
3372 * gtk_text_iter_forward_cursor_position:
3373 * @iter: a #GtkTextIter
3375 * Moves @iter forward by a single cursor position. Cursor positions
3376 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3377 * surprisingly, there may not be a cursor position between all
3378 * characters. The most common example for European languages would be
3379 * a carriage return/newline sequence. For some Unicode characters,
3380 * the equivalent of say the letter "a" with an accent mark will be
3381 * represented as two characters, first the letter then a "combining
3382 * mark" that causes the accent to be rendered; so the cursor can't go
3383 * between those two characters. See also the #PangoLogAttr structure and
3384 * pango_break() function.
3386 * Return value: %TRUE if we moved and the new position is dereferenceable
3389 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3391 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3395 * gtk_text_iter_backward_cursor_position:
3396 * @iter: a #GtkTextIter
3398 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3400 * Return value: %TRUE if we moved
3403 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3405 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3409 * gtk_text_iter_forward_cursor_positions:
3410 * @iter: a #GtkTextIter
3411 * @count: number of positions to move
3413 * Moves up to @count cursor positions. See
3414 * gtk_text_iter_forward_cursor_position() for details.
3416 * Return value: %TRUE if we moved and the new position is dereferenceable
3419 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3422 g_return_val_if_fail (iter != NULL, FALSE);
3424 FIX_OVERFLOWS (count);
3430 return gtk_text_iter_backward_cursor_positions (iter, -count);
3432 if (!gtk_text_iter_forward_cursor_position (iter))
3438 if (!gtk_text_iter_forward_cursor_position (iter))
3443 return !gtk_text_iter_is_end (iter);
3447 * gtk_text_iter_backward_cursor_positions:
3448 * @iter: a #GtkTextIter
3449 * @count: number of positions to move
3451 * Moves up to @count cursor positions. See
3452 * gtk_text_iter_forward_cursor_position() for details.
3454 * Return value: %TRUE if we moved and the new position is dereferenceable
3457 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3460 g_return_val_if_fail (iter != NULL, FALSE);
3462 FIX_OVERFLOWS (count);
3468 return gtk_text_iter_forward_cursor_positions (iter, -count);
3470 if (!gtk_text_iter_backward_cursor_position (iter))
3476 if (!gtk_text_iter_backward_cursor_position (iter))
3481 return !gtk_text_iter_is_end (iter);
3485 * gtk_text_iter_is_cursor_position:
3486 * @iter: a #GtkTextIter
3488 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3489 * pango_break() for details on what a cursor position is.
3491 * Return value: %TRUE if the cursor can be placed at @iter
3494 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3496 return test_log_attrs (iter, is_cursor_pos_func);
3500 * gtk_text_iter_set_line_offset:
3501 * @iter: a #GtkTextIter
3502 * @char_on_line: a character offset relative to the start of @iter's current line
3504 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3505 * (not byte) offset. The given character offset must be less than or
3506 * equal to the number of characters in the line; if equal, @iter
3507 * moves to the start of the next line. See
3508 * gtk_text_iter_set_line_index() if you have a byte index rather than
3509 * a character offset.
3513 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3516 GtkTextRealIter *real;
3519 g_return_if_fail (iter != NULL);
3521 real = gtk_text_iter_make_surreal (iter);
3526 check_invariants (iter);
3528 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3530 g_return_if_fail (char_on_line <= chars_in_line);
3532 if (char_on_line < chars_in_line)
3533 iter_set_from_char_offset (real, real->line, char_on_line);
3535 gtk_text_iter_forward_line (iter); /* set to start of next line */
3537 check_invariants (iter);
3541 * gtk_text_iter_set_line_index:
3542 * @iter: a #GtkTextIter
3543 * @byte_on_line: a byte index relative to the start of @iter's current line
3545 * Same as gtk_text_iter_set_line_offset(), but works with a
3546 * <emphasis>byte</emphasis> index. The given byte index must be at
3547 * the start of a character, it can't be in the middle of a UTF-8
3548 * encoded character.
3552 gtk_text_iter_set_line_index (GtkTextIter *iter,
3555 GtkTextRealIter *real;
3558 g_return_if_fail (iter != NULL);
3560 real = gtk_text_iter_make_surreal (iter);
3565 check_invariants (iter);
3567 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3569 g_return_if_fail (byte_on_line <= bytes_in_line);
3571 if (byte_on_line < bytes_in_line)
3572 iter_set_from_byte_offset (real, real->line, byte_on_line);
3574 gtk_text_iter_forward_line (iter);
3576 if (real->segment->type == >k_text_char_type &&
3577 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3578 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3579 "character; this will crash the text buffer. "
3580 "Byte indexes must refer to the start of a character.",
3581 G_STRLOC, byte_on_line);
3583 check_invariants (iter);
3588 * gtk_text_iter_set_visible_line_offset:
3589 * @iter: a #GtkTextIter
3590 * @char_on_line: a character offset
3592 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3593 * characters, i.e. text with a tag making it invisible is not
3594 * counted in the offset.
3597 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3600 gint chars_seen = 0;
3603 g_return_if_fail (iter != NULL);
3607 /* For now we use a ludicrously slow implementation */
3608 while (chars_seen < char_on_line)
3610 if (!_gtk_text_btree_char_is_invisible (&pos))
3613 if (!gtk_text_iter_forward_char (&pos))
3616 if (chars_seen == char_on_line)
3620 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3623 gtk_text_iter_forward_line (iter);
3627 bytes_in_char (GtkTextIter *iter)
3629 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3633 * gtk_text_iter_set_visible_line_index:
3634 * @iter: a #GtkTextIter
3635 * @byte_on_line: a byte index
3637 * Like gtk_text_iter_set_line_index(), but the index is in visible
3638 * bytes, i.e. text with a tag making it invisible is not counted
3642 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3645 gint bytes_seen = 0;
3648 g_return_if_fail (iter != NULL);
3652 /* For now we use a ludicrously slow implementation */
3653 while (bytes_seen < byte_on_line)
3655 if (!_gtk_text_btree_char_is_invisible (&pos))
3656 bytes_seen += bytes_in_char (&pos);
3658 if (!gtk_text_iter_forward_char (&pos))
3661 if (bytes_seen >= byte_on_line)
3665 if (bytes_seen > byte_on_line)
3666 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3667 "character; this will crash the text buffer. "
3668 "Byte indexes must refer to the start of a character.",
3669 G_STRLOC, byte_on_line);
3671 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3674 gtk_text_iter_forward_line (iter);
3678 * gtk_text_iter_set_line:
3679 * @iter: a #GtkTextIter
3680 * @line_number: line number (counted from 0)
3682 * Moves iterator @iter to the start of the line @line_number. If
3683 * @line_number is negative or larger than the number of lines in the
3684 * buffer, moves @iter to the start of the last line in the buffer.
3688 gtk_text_iter_set_line (GtkTextIter *iter,
3693 GtkTextRealIter *real;
3695 g_return_if_fail (iter != NULL);
3697 real = gtk_text_iter_make_surreal (iter);
3702 check_invariants (iter);
3704 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3706 iter_set_from_char_offset (real, line, 0);
3708 /* We might as well cache this, since we know it. */
3709 real->cached_line_number = real_line;
3711 check_invariants (iter);
3715 * gtk_text_iter_set_offset:
3716 * @iter: a #GtkTextIter
3717 * @char_offset: a character number
3719 * Sets @iter to point to @char_offset. @char_offset counts from the start
3720 * of the entire text buffer, starting with 0.
3723 gtk_text_iter_set_offset (GtkTextIter *iter,
3727 GtkTextRealIter *real;
3729 gint real_char_index;
3731 g_return_if_fail (iter != NULL);
3733 real = gtk_text_iter_make_surreal (iter);
3738 check_invariants (iter);
3740 if (real->cached_char_index >= 0 &&
3741 real->cached_char_index == char_offset)
3744 line = _gtk_text_btree_get_line_at_char (real->tree,
3749 iter_set_from_char_offset (real, line, real_char_index - line_start);
3751 /* Go ahead and cache this since we have it. */
3752 real->cached_char_index = real_char_index;
3754 check_invariants (iter);
3758 * gtk_text_iter_forward_to_end:
3759 * @iter: a #GtkTextIter
3761 * Moves @iter forward to the "end iterator," which points one past the last
3762 * valid character in the buffer. gtk_text_iter_get_char() called on the
3763 * end iterator returns 0, which is convenient for writing loops.
3766 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3768 GtkTextBuffer *buffer;
3769 GtkTextRealIter *real;
3771 g_return_if_fail (iter != NULL);
3773 real = gtk_text_iter_make_surreal (iter);
3778 buffer = _gtk_text_btree_get_buffer (real->tree);
3780 gtk_text_buffer_get_end_iter (buffer, iter);
3783 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3784 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3785 * If all else fails we could cache the para delimiter pos in the iter.
3786 * I think forward_to_line_end() actually gets called fairly often.
3789 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3794 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3795 _gtk_text_iter_get_btree (&end)))
3797 gtk_text_iter_forward_to_end (&end);
3801 /* if we aren't on the last line, go forward to start of next line, then scan
3802 * back for the delimiters on the previous line
3804 gtk_text_iter_forward_line (&end);
3805 gtk_text_iter_backward_char (&end);
3806 while (!gtk_text_iter_ends_line (&end))
3807 gtk_text_iter_backward_char (&end);
3810 return gtk_text_iter_get_line_offset (&end);
3814 * gtk_text_iter_forward_to_line_end:
3815 * @iter: a #GtkTextIter
3817 * Moves the iterator to point to the paragraph delimiter characters,
3818 * which will be either a newline, a carriage return, a carriage
3819 * return/newline in sequence, or the Unicode paragraph separator
3820 * character. If the iterator is already at the paragraph delimiter
3821 * characters, moves to the paragraph delimiter characters for the
3822 * next line. If @iter is on the last line in the buffer, which does
3823 * not end in paragraph delimiters, moves to the end iterator (end of
3824 * the last line), and returns %FALSE.
3826 * Return value: %TRUE if we moved and the new location is not the end iterator
3829 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3831 gint current_offset;
3835 g_return_val_if_fail (iter != NULL, FALSE);
3837 current_offset = gtk_text_iter_get_line_offset (iter);
3838 new_offset = find_paragraph_delimiter_for_line (iter);
3840 if (current_offset < new_offset)
3842 /* Move to end of this line. */
3843 gtk_text_iter_set_line_offset (iter, new_offset);
3844 return !gtk_text_iter_is_end (iter);
3848 /* Move to end of next line. */
3849 if (gtk_text_iter_forward_line (iter))
3851 /* We don't want to move past all
3854 if (!gtk_text_iter_ends_line (iter))
3855 gtk_text_iter_forward_to_line_end (iter);
3856 return !gtk_text_iter_is_end (iter);
3864 * gtk_text_iter_forward_to_tag_toggle:
3865 * @iter: a #GtkTextIter
3866 * @tag: a #GtkTextTag, or %NULL
3868 * Moves forward to the next toggle (on or off) of the
3869 * #GtkTextTag @tag, or to the next toggle of any tag if
3870 * @tag is %NULL. If no matching tag toggles are found,
3871 * returns %FALSE, otherwise %TRUE. Does not return toggles
3872 * located at @iter, only toggles after @iter. Sets @iter to
3873 * the location of the toggle, or to the end of the buffer
3874 * if no toggle is found.
3876 * Return value: whether we found a tag toggle after @iter
3879 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3882 GtkTextLine *next_line;
3883 GtkTextLine *current_line;
3884 GtkTextRealIter *real;
3886 g_return_val_if_fail (iter != NULL, FALSE);
3888 real = gtk_text_iter_make_real (iter);
3893 check_invariants (iter);
3895 current_line = real->line;
3896 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3899 while (_gtk_text_iter_forward_indexable_segment (iter))
3901 /* If we went forward to a line that couldn't contain a toggle
3902 for the tag, then skip forward to a line that could contain
3903 it. This potentially skips huge hunks of the tree, so we
3904 aren't a purely linear search. */
3905 if (real->line != current_line)
3907 if (next_line == NULL)
3909 /* End of search. Set to end of buffer. */
3910 _gtk_text_btree_get_end_iter (real->tree, iter);
3914 if (real->line != next_line)
3915 iter_set_from_byte_offset (real, next_line, 0);
3917 current_line = real->line;
3918 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3923 if (gtk_text_iter_toggles_tag (iter, tag))
3925 /* If there's a toggle here, it isn't indexable so
3926 any_segment can't be the indexable segment. */
3927 g_assert (real->any_segment != real->segment);
3932 /* Check end iterator for tags */
3933 if (gtk_text_iter_toggles_tag (iter, tag))
3935 /* If there's a toggle here, it isn't indexable so
3936 any_segment can't be the indexable segment. */
3937 g_assert (real->any_segment != real->segment);
3941 /* Reached end of buffer */
3946 * gtk_text_iter_backward_to_tag_toggle:
3947 * @iter: a #GtkTextIter
3948 * @tag: a #GtkTextTag, or %NULL
3950 * Moves backward to the next toggle (on or off) of the
3951 * #GtkTextTag @tag, or to the next toggle of any tag if
3952 * @tag is %NULL. If no matching tag toggles are found,
3953 * returns %FALSE, otherwise %TRUE. Does not return toggles
3954 * located at @iter, only toggles before @iter. Sets @iter
3955 * to the location of the toggle, or the start of the buffer
3956 * if no toggle is found.
3958 * Return value: whether we found a tag toggle before @iter
3961 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3964 GtkTextLine *prev_line;
3965 GtkTextLine *current_line;
3966 GtkTextRealIter *real;
3968 g_return_val_if_fail (iter != NULL, FALSE);
3970 real = gtk_text_iter_make_real (iter);
3975 check_invariants (iter);
3977 current_line = real->line;
3978 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3982 /* If we're at segment start, go to the previous segment;
3983 * if mid-segment, snap to start of current segment.
3985 if (is_segment_start (real))
3987 if (!_gtk_text_iter_backward_indexable_segment (iter))
3992 ensure_char_offsets (real);
3994 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4000 /* If we went backward to a line that couldn't contain a toggle
4001 * for the tag, then skip backward further to a line that
4002 * could contain it. This potentially skips huge hunks of the
4003 * tree, so we aren't a purely linear search.
4005 if (real->line != current_line)
4007 if (prev_line == NULL)
4009 /* End of search. Set to start of buffer. */
4010 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4014 if (real->line != prev_line)
4016 /* Set to last segment in prev_line (could do this
4019 iter_set_from_byte_offset (real, prev_line, 0);
4021 while (!at_last_indexable_segment (real))
4022 _gtk_text_iter_forward_indexable_segment (iter);
4025 current_line = real->line;
4026 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4031 if (gtk_text_iter_toggles_tag (iter, tag))
4033 /* If there's a toggle here, it isn't indexable so
4034 * any_segment can't be the indexable segment.
4036 g_assert (real->any_segment != real->segment);
4040 while (_gtk_text_iter_backward_indexable_segment (iter));
4042 /* Reached front of buffer */
4047 matches_pred (GtkTextIter *iter,
4048 GtkTextCharPredicate pred,
4053 ch = gtk_text_iter_get_char (iter);
4055 return (*pred) (ch, user_data);
4059 * gtk_text_iter_forward_find_char:
4060 * @iter: a #GtkTextIter
4061 * @pred: a function to be called on each character
4062 * @user_data: user data for @pred
4063 * @limit: search limit, or %NULL for none
4065 * Advances @iter, calling @pred on each character. If
4066 * @pred returns %TRUE, returns %TRUE and stops scanning.
4067 * If @pred never returns %TRUE, @iter is set to @limit if
4068 * @limit is non-%NULL, otherwise to the end iterator.
4070 * Return value: whether a match was found
4073 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4074 GtkTextCharPredicate pred,
4076 const GtkTextIter *limit)
4078 g_return_val_if_fail (iter != NULL, FALSE);
4079 g_return_val_if_fail (pred != NULL, FALSE);
4082 gtk_text_iter_compare (iter, limit) >= 0)
4085 while ((limit == NULL ||
4086 !gtk_text_iter_equal (limit, iter)) &&
4087 gtk_text_iter_forward_char (iter))
4089 if (matches_pred (iter, pred, user_data))
4097 * gtk_text_iter_backward_find_char:
4098 * @iter: a #GtkTextIter
4099 * @pred: function to be called on each character
4100 * @user_data: user data for @pred
4101 * @limit: search limit, or %NULL for none
4103 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4105 * Return value: whether a match was found
4108 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4109 GtkTextCharPredicate pred,
4111 const GtkTextIter *limit)
4113 g_return_val_if_fail (iter != NULL, FALSE);
4114 g_return_val_if_fail (pred != NULL, FALSE);
4117 gtk_text_iter_compare (iter, limit) <= 0)
4120 while ((limit == NULL ||
4121 !gtk_text_iter_equal (limit, iter)) &&
4122 gtk_text_iter_backward_char (iter))
4124 if (matches_pred (iter, pred, user_data))
4132 forward_chars_with_skipping (GtkTextIter *iter,
4134 gboolean skip_invisible,
4135 gboolean skip_nontext)
4140 g_return_if_fail (count >= 0);
4146 gboolean ignored = FALSE;
4149 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4154 _gtk_text_btree_char_is_invisible (iter))
4157 gtk_text_iter_forward_char (iter);
4165 lines_match (const GtkTextIter *start,
4166 const gchar **lines,
4167 gboolean visible_only,
4169 GtkTextIter *match_start,
4170 GtkTextIter *match_end)
4177 if (*lines == NULL || **lines == '\0')
4180 *match_start = *start;
4183 *match_end = *start;
4188 gtk_text_iter_forward_line (&next);
4190 /* No more text in buffer, but *lines is nonempty */
4191 if (gtk_text_iter_equal (start, &next))
4199 line_text = gtk_text_iter_get_visible_slice (start, &next);
4201 line_text = gtk_text_iter_get_slice (start, &next);
4206 line_text = gtk_text_iter_get_visible_text (start, &next);
4208 line_text = gtk_text_iter_get_text (start, &next);
4211 if (match_start) /* if this is the first line we're matching */
4212 found = strstr (line_text, *lines);
4215 /* If it's not the first line, we have to match from the
4216 * start of the line.
4218 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4230 /* Get offset to start of search string */
4231 offset = g_utf8_strlen (line_text, found - line_text);
4235 /* If match start needs to be returned, set it to the
4236 * start of the search string.
4240 *match_start = next;
4242 forward_chars_with_skipping (match_start, offset,
4243 visible_only, !slice);
4246 /* Go to end of search string */
4247 offset += g_utf8_strlen (*lines, -1);
4249 forward_chars_with_skipping (&next, offset,
4250 visible_only, !slice);
4259 /* pass NULL for match_start, since we don't need to find the
4262 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4265 /* strsplit () that retains the delimiter as part of the string. */
4267 strbreakup (const char *string,
4268 const char *delimiter,
4271 GSList *string_list = NULL, *slist;
4272 gchar **str_array, *s;
4275 g_return_val_if_fail (string != NULL, NULL);
4276 g_return_val_if_fail (delimiter != NULL, NULL);
4279 max_tokens = G_MAXINT;
4281 s = strstr (string, delimiter);
4284 guint delimiter_len = strlen (delimiter);
4291 len = s - string + delimiter_len;
4292 new_string = g_new (gchar, len + 1);
4293 strncpy (new_string, string, len);
4294 new_string[len] = 0;
4295 string_list = g_slist_prepend (string_list, new_string);
4297 string = s + delimiter_len;
4298 s = strstr (string, delimiter);
4300 while (--max_tokens && s);
4305 string_list = g_slist_prepend (string_list, g_strdup (string));
4308 str_array = g_new (gchar*, n);
4312 str_array[i--] = NULL;
4313 for (slist = string_list; slist; slist = slist->next)
4314 str_array[i--] = slist->data;
4316 g_slist_free (string_list);
4322 * gtk_text_iter_forward_search:
4323 * @iter: start of search
4324 * @str: a search string
4325 * @flags: flags affecting how the search is done
4326 * @match_start: return location for start of match, or %NULL
4327 * @match_end: return location for end of match, or %NULL
4328 * @limit: bound for the search, or %NULL for the end of the buffer
4330 * Searches forward for @str. Any match is returned by setting
4331 * @match_start to the first character of the match and @match_end to the
4332 * first character after the match. The search will not continue past
4333 * @limit. Note that a search is a linear or O(n) operation, so you
4334 * may wish to use @limit to avoid locking up your UI on large
4337 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4338 * have invisible text interspersed in @str. i.e. @str will be a
4339 * possibly-noncontiguous subsequence of the matched range. similarly,
4340 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4341 * pixbufs or child widgets mixed inside the matched range. If these
4342 * flags are not given, the match must be exact; the special 0xFFFC
4343 * character in @str will match embedded pixbufs or child widgets.
4345 * Return value: whether a match was found
4348 gtk_text_iter_forward_search (const GtkTextIter *iter,
4350 GtkTextSearchFlags flags,
4351 GtkTextIter *match_start,
4352 GtkTextIter *match_end,
4353 const GtkTextIter *limit)
4355 gchar **lines = NULL;
4357 gboolean retval = FALSE;
4359 gboolean visible_only;
4362 g_return_val_if_fail (iter != NULL, FALSE);
4363 g_return_val_if_fail (str != NULL, FALSE);
4366 gtk_text_iter_compare (iter, limit) >= 0)
4371 /* If we can move one char, return the empty string there */
4374 if (gtk_text_iter_forward_char (&match))
4377 gtk_text_iter_equal (&match, limit))
4381 *match_start = match;
4390 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4391 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4393 /* locate all lines */
4395 lines = strbreakup (str, "\n", -1);
4401 /* This loop has an inefficient worst-case, where
4402 * gtk_text_iter_get_text () is called repeatedly on
4408 gtk_text_iter_compare (&search, limit) >= 0)
4411 if (lines_match (&search, (const gchar**)lines,
4412 visible_only, slice, &match, &end))
4414 if (limit == NULL ||
4416 gtk_text_iter_compare (&end, limit) < 0))
4421 *match_start = match;
4430 while (gtk_text_iter_forward_line (&search));
4432 g_strfreev ((gchar**)lines);
4438 vectors_equal_ignoring_trailing (gchar **vec1,
4441 /* Ignores trailing chars in vec2's last line */
4450 if (strcmp (*i1, *i2) != 0)
4452 if (*(i2 + 1) == NULL) /* if this is the last line */
4454 gint len1 = strlen (*i1);
4455 gint len2 = strlen (*i2);
4458 strncmp (*i1, *i2, len1) == 0)
4460 /* We matched ignoring the trailing stuff in vec2 */
4485 typedef struct _LinesWindow LinesWindow;
4491 GtkTextIter first_line_start;
4492 GtkTextIter first_line_end;
4494 gboolean visible_only;
4498 lines_window_init (LinesWindow *win,
4499 const GtkTextIter *start)
4502 GtkTextIter line_start;
4503 GtkTextIter line_end;
4505 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4508 if (gtk_text_iter_is_start (start) ||
4509 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4511 /* Already at the end, or not enough lines to match */
4512 win->lines = g_new0 (gchar*, 1);
4517 line_start = *start;
4520 /* Move to start iter to start of line */
4521 gtk_text_iter_set_line_offset (&line_start, 0);
4523 if (gtk_text_iter_equal (&line_start, &line_end))
4525 /* we were already at the start; so go back one line */
4526 gtk_text_iter_backward_line (&line_start);
4529 win->first_line_start = line_start;
4530 win->first_line_end = line_end;
4532 win->lines = g_new0 (gchar*, win->n_lines + 1);
4534 i = win->n_lines - 1;
4541 if (win->visible_only)
4542 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4544 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4548 if (win->visible_only)
4549 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4551 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4554 win->lines[i] = line_text;
4556 line_end = line_start;
4557 gtk_text_iter_backward_line (&line_start);
4564 lines_window_back (LinesWindow *win)
4566 GtkTextIter new_start;
4569 new_start = win->first_line_start;
4571 if (!gtk_text_iter_backward_line (&new_start))
4575 win->first_line_start = new_start;
4576 win->first_line_end = new_start;
4578 gtk_text_iter_forward_line (&win->first_line_end);
4583 if (win->visible_only)
4584 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4585 &win->first_line_end);
4587 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4588 &win->first_line_end);
4592 if (win->visible_only)
4593 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4594 &win->first_line_end);
4596 line_text = gtk_text_iter_get_text (&win->first_line_start,
4597 &win->first_line_end);
4600 /* Move lines to make room for first line. */
4601 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4603 *win->lines = line_text;
4605 /* Free old last line and NULL-terminate */
4606 g_free (win->lines[win->n_lines]);
4607 win->lines[win->n_lines] = NULL;
4613 lines_window_free (LinesWindow *win)
4615 g_strfreev (win->lines);
4619 my_strrstr (const gchar *haystack,
4620 const gchar *needle)
4622 /* FIXME GLib should have a nice implementation in it, this
4626 gint haystack_len = strlen (haystack);
4627 gint needle_len = strlen (needle);
4628 const gchar *needle_end = needle + needle_len;
4629 const gchar *haystack_rend = haystack - 1;
4630 const gchar *needle_rend = needle - 1;
4633 p = haystack + haystack_len;
4634 while (p != haystack)
4636 const gchar *n = needle_end - 1;
4637 const gchar *s = p - 1;
4638 while (s != haystack_rend &&
4646 if (n == needle_rend)
4656 * gtk_text_iter_backward_search:
4657 * @iter: a #GtkTextIter where the search begins
4658 * @str: search string
4659 * @flags: bitmask of flags affecting the search
4660 * @match_start: return location for start of match, or %NULL
4661 * @match_end: return location for end of match, or %NULL
4662 * @limit: location of last possible @match_start, or %NULL for start of buffer
4664 * Same as gtk_text_iter_forward_search(), but moves backward.
4666 * Return value: whether a match was found
4669 gtk_text_iter_backward_search (const GtkTextIter *iter,
4671 GtkTextSearchFlags flags,
4672 GtkTextIter *match_start,
4673 GtkTextIter *match_end,
4674 const GtkTextIter *limit)
4676 gchar **lines = NULL;
4680 gboolean retval = FALSE;
4681 gboolean visible_only;
4684 g_return_val_if_fail (iter != NULL, FALSE);
4685 g_return_val_if_fail (str != NULL, FALSE);
4688 gtk_text_iter_compare (limit, iter) > 0)
4693 /* If we can move one char, return the empty string there */
4694 GtkTextIter match = *iter;
4696 if (limit && gtk_text_iter_equal (limit, &match))
4699 if (gtk_text_iter_backward_char (&match))
4702 *match_start = match;
4711 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4712 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4714 /* locate all lines */
4716 lines = strbreakup (str, "\n", -1);
4726 win.n_lines = n_lines;
4728 win.visible_only = visible_only;
4730 lines_window_init (&win, iter);
4732 if (*win.lines == NULL)
4737 gchar *first_line_match;
4740 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4742 /* We're now before the search limit, abort. */
4746 /* If there are multiple lines, the first line will
4747 * end in '\n', so this will only match at the
4748 * end of the first line, which is correct.
4750 first_line_match = my_strrstr (*win.lines, *lines);
4752 if (first_line_match &&
4753 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4758 GtkTextIter start_tmp;
4760 /* Offset to start of search string */
4761 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4763 next = win.first_line_start;
4765 forward_chars_with_skipping (&start_tmp, offset,
4766 visible_only, !slice);
4769 gtk_text_iter_compare (limit, &start_tmp) > 0)
4770 goto out; /* match was bogus */
4773 *match_start = start_tmp;
4775 /* Go to end of search string */
4779 offset += g_utf8_strlen (*l, -1);
4783 forward_chars_with_skipping (&next, offset,
4784 visible_only, !slice);
4793 while (lines_window_back (&win));
4796 lines_window_free (&win);
4807 * gtk_text_iter_equal:
4808 * @lhs: a #GtkTextIter
4809 * @rhs: another #GtkTextIter
4811 * Tests whether two iterators are equal, using the fastest possible
4812 * mechanism. This function is very fast; you can expect it to perform
4813 * better than e.g. getting the character offset for each iterator and
4814 * comparing the offsets yourself. Also, it's a bit faster than
4815 * gtk_text_iter_compare().
4817 * Return value: %TRUE if the iterators point to the same place in the buffer
4820 gtk_text_iter_equal (const GtkTextIter *lhs,
4821 const GtkTextIter *rhs)
4823 GtkTextRealIter *real_lhs;
4824 GtkTextRealIter *real_rhs;
4826 real_lhs = (GtkTextRealIter*)lhs;
4827 real_rhs = (GtkTextRealIter*)rhs;
4829 check_invariants (lhs);
4830 check_invariants (rhs);
4832 if (real_lhs->line != real_rhs->line)
4834 else if (real_lhs->line_byte_offset >= 0 &&
4835 real_rhs->line_byte_offset >= 0)
4836 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4839 /* the ensure_char_offsets () calls do nothing if the char offsets
4840 are already up-to-date. */
4841 ensure_char_offsets (real_lhs);
4842 ensure_char_offsets (real_rhs);
4843 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4848 * gtk_text_iter_compare:
4849 * @lhs: a #GtkTextIter
4850 * @rhs: another #GtkTextIter
4852 * A qsort()-style function that returns negative if @lhs is less than
4853 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4854 * Ordering is in character offset order, i.e. the first character in the buffer
4855 * is less than the second character in the buffer.
4857 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4860 gtk_text_iter_compare (const GtkTextIter *lhs,
4861 const GtkTextIter *rhs)
4863 GtkTextRealIter *real_lhs;
4864 GtkTextRealIter *real_rhs;
4866 real_lhs = gtk_text_iter_make_surreal (lhs);
4867 real_rhs = gtk_text_iter_make_surreal (rhs);
4869 if (real_lhs == NULL ||
4871 return -1; /* why not */
4873 check_invariants (lhs);
4874 check_invariants (rhs);
4876 if (real_lhs->line == real_rhs->line)
4878 gint left_index, right_index;
4880 if (real_lhs->line_byte_offset >= 0 &&
4881 real_rhs->line_byte_offset >= 0)
4883 left_index = real_lhs->line_byte_offset;
4884 right_index = real_rhs->line_byte_offset;
4888 /* the ensure_char_offsets () calls do nothing if
4889 the offsets are already up-to-date. */
4890 ensure_char_offsets (real_lhs);
4891 ensure_char_offsets (real_rhs);
4892 left_index = real_lhs->line_char_offset;
4893 right_index = real_rhs->line_char_offset;
4896 if (left_index < right_index)
4898 else if (left_index > right_index)
4907 line1 = gtk_text_iter_get_line (lhs);
4908 line2 = gtk_text_iter_get_line (rhs);
4911 else if (line1 > line2)
4919 * gtk_text_iter_in_range:
4920 * @iter: a #GtkTextIter
4921 * @start: start of range
4922 * @end: end of range
4924 * Checks whether @iter falls in the range [@start, @end).
4925 * @start and @end must be in ascending order.
4927 * Return value: %TRUE if @iter is in the range
4930 gtk_text_iter_in_range (const GtkTextIter *iter,
4931 const GtkTextIter *start,
4932 const GtkTextIter *end)
4934 g_return_val_if_fail (iter != NULL, FALSE);
4935 g_return_val_if_fail (start != NULL, FALSE);
4936 g_return_val_if_fail (end != NULL, FALSE);
4937 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4939 return gtk_text_iter_compare (iter, start) >= 0 &&
4940 gtk_text_iter_compare (iter, end) < 0;
4944 * gtk_text_iter_order:
4945 * @first: a #GtkTextIter
4946 * @second: another #GtkTextIter
4948 * Swaps the value of @first and @second if @second comes before
4949 * @first in the buffer. That is, ensures that @first and @second are
4950 * in sequence. Most text buffer functions that take a range call this
4951 * automatically on your behalf, so there's no real reason to call it yourself
4952 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4953 * that expect a pre-sorted range.
4957 gtk_text_iter_order (GtkTextIter *first,
4958 GtkTextIter *second)
4960 g_return_if_fail (first != NULL);
4961 g_return_if_fail (second != NULL);
4963 if (gtk_text_iter_compare (first, second) > 0)
4974 * Init iterators from the BTree
4978 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4982 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4983 gint real_char_index;
4987 g_return_if_fail (iter != NULL);
4988 g_return_if_fail (tree != NULL);
4990 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4991 &line_start, &real_char_index);
4993 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4995 real->cached_char_index = real_char_index;
4997 check_invariants (iter);
5001 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5006 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5010 g_return_if_fail (iter != NULL);
5011 g_return_if_fail (tree != NULL);
5013 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5015 iter_init_from_char_offset (iter, tree, line, char_on_line);
5017 /* We might as well cache this, since we know it. */
5018 real->cached_line_number = real_line;
5020 check_invariants (iter);
5024 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5029 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5033 g_return_if_fail (iter != NULL);
5034 g_return_if_fail (tree != NULL);
5036 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5038 iter_init_from_byte_offset (iter, tree, line, byte_index);
5040 /* We might as well cache this, since we know it. */
5041 real->cached_line_number = real_line;
5043 check_invariants (iter);
5047 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5052 g_return_if_fail (iter != NULL);
5053 g_return_if_fail (tree != NULL);
5054 g_return_if_fail (line != NULL);
5056 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5058 check_invariants (iter);
5062 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5068 g_return_val_if_fail (iter != NULL, FALSE);
5069 g_return_val_if_fail (tree != NULL, FALSE);
5071 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5075 /* Set iter to last in tree */
5076 _gtk_text_btree_get_end_iter (tree, iter);
5077 check_invariants (iter);
5082 iter_init_from_byte_offset (iter, tree, line, 0);
5083 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5084 check_invariants (iter);
5090 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5094 g_return_val_if_fail (iter != NULL, FALSE);
5095 g_return_val_if_fail (tree != NULL, FALSE);
5097 _gtk_text_btree_get_end_iter (tree, iter);
5098 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5099 check_invariants (iter);
5105 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5107 const gchar *mark_name)
5111 g_return_val_if_fail (iter != NULL, FALSE);
5112 g_return_val_if_fail (tree != NULL, FALSE);
5114 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5120 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5121 check_invariants (iter);
5127 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5131 GtkTextLineSegment *seg;
5133 g_return_if_fail (iter != NULL);
5134 g_return_if_fail (tree != NULL);
5135 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5137 seg = mark->segment;
5139 iter_init_from_segment (iter, tree,
5140 seg->body.mark.line, seg);
5141 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5142 check_invariants (iter);
5146 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5148 GtkTextChildAnchor *anchor)
5150 GtkTextLineSegment *seg;
5152 g_return_if_fail (iter != NULL);
5153 g_return_if_fail (tree != NULL);
5154 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5156 seg = anchor->segment;
5158 g_assert (seg->body.child.line != NULL);
5160 iter_init_from_segment (iter, tree,
5161 seg->body.child.line, seg);
5162 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5163 check_invariants (iter);
5167 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5170 g_return_if_fail (iter != NULL);
5171 g_return_if_fail (tree != NULL);
5173 _gtk_text_btree_get_iter_at_char (tree,
5175 _gtk_text_btree_char_count (tree));
5176 check_invariants (iter);
5180 _gtk_text_iter_check (const GtkTextIter *iter)
5182 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5183 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5184 GtkTextLineSegment *byte_segment = NULL;
5185 GtkTextLineSegment *byte_any_segment = NULL;
5186 GtkTextLineSegment *char_segment = NULL;
5187 GtkTextLineSegment *char_any_segment = NULL;
5188 gboolean segments_updated;
5190 /* This function checks our class invariants for the Iter class. */
5192 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5194 if (real->chars_changed_stamp !=
5195 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5196 g_error ("iterator check failed: invalid iterator");
5198 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5199 g_error ("iterator check failed: both char and byte offsets are invalid");
5201 segments_updated = (real->segments_changed_stamp ==
5202 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5205 printf ("checking iter, segments %s updated, byte %d char %d\n",
5206 segments_updated ? "are" : "aren't",
5207 real->line_byte_offset,
5208 real->line_char_offset);
5211 if (segments_updated)
5213 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5214 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5216 if (real->segment->char_count == 0)
5217 g_error ("iterator check failed: segment is not indexable.");
5219 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5220 g_error ("segment char offset is not properly up-to-date");
5222 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5223 g_error ("segment byte offset is not properly up-to-date");
5225 if (real->segment_byte_offset >= 0 &&
5226 real->segment_byte_offset >= real->segment->byte_count)
5227 g_error ("segment byte offset is too large.");
5229 if (real->segment_char_offset >= 0 &&
5230 real->segment_char_offset >= real->segment->char_count)
5231 g_error ("segment char offset is too large.");
5234 if (real->line_byte_offset >= 0)
5236 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5237 &byte_segment, &byte_any_segment,
5238 &seg_byte_offset, &line_byte_offset);
5240 if (line_byte_offset != real->line_byte_offset)
5241 g_error ("wrong byte offset was stored in iterator");
5243 if (segments_updated)
5245 if (real->segment != byte_segment)
5246 g_error ("wrong segment was stored in iterator");
5248 if (real->any_segment != byte_any_segment)
5249 g_error ("wrong any_segment was stored in iterator");
5251 if (seg_byte_offset != real->segment_byte_offset)
5252 g_error ("wrong segment byte offset was stored in iterator");
5254 if (byte_segment->type == >k_text_char_type)
5257 p = byte_segment->body.chars + seg_byte_offset;
5259 if (!gtk_text_byte_begins_utf8_char (p))
5260 g_error ("broken iterator byte index pointed into the middle of a character");
5265 if (real->line_char_offset >= 0)
5267 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5268 &char_segment, &char_any_segment,
5269 &seg_char_offset, &line_char_offset);
5271 if (line_char_offset != real->line_char_offset)
5272 g_error ("wrong char offset was stored in iterator");
5274 if (segments_updated)
5276 if (real->segment != char_segment)
5277 g_error ("wrong segment was stored in iterator");
5279 if (real->any_segment != char_any_segment)
5280 g_error ("wrong any_segment was stored in iterator");
5282 if (seg_char_offset != real->segment_char_offset)
5283 g_error ("wrong segment char offset was stored in iterator");
5285 if (char_segment->type == >k_text_char_type)
5288 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5291 /* hmm, not likely to happen eh */
5292 if (!gtk_text_byte_begins_utf8_char (p))
5293 g_error ("broken iterator char offset pointed into the middle of a character");
5298 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5300 if (byte_segment != char_segment)
5301 g_error ("char and byte offsets did not point to the same segment");
5303 if (byte_any_segment != char_any_segment)
5304 g_error ("char and byte offsets did not point to the same any segment");
5306 /* Make sure the segment offsets are equivalent, if it's a char
5308 if (char_segment->type == >k_text_char_type)
5310 gint byte_offset = 0;
5311 gint char_offset = 0;
5312 while (char_offset < seg_char_offset)
5314 const char * start = char_segment->body.chars + byte_offset;
5315 byte_offset += g_utf8_next_char (start) - start;
5319 if (byte_offset != seg_byte_offset)
5320 g_error ("byte offset did not correspond to char offset");
5323 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5325 if (char_offset != seg_char_offset)
5326 g_error ("char offset did not correspond to byte offset");
5328 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5329 g_error ("byte index for iterator does not index the start of a character");
5333 if (real->cached_line_number >= 0)
5337 should_be = _gtk_text_line_get_number (real->line);
5338 if (real->cached_line_number != should_be)
5339 g_error ("wrong line number was cached");
5342 if (real->cached_char_index >= 0)
5344 if (real->line_char_offset >= 0) /* only way we can check it
5345 efficiently, not a real
5350 char_index = _gtk_text_line_char_index (real->line);
5351 char_index += real->line_char_offset;
5353 if (real->cached_char_index != char_index)
5354 g_error ("wrong char index was cached");
5358 if (_gtk_text_line_is_last (real->line, real->tree))
5359 g_error ("Iterator was on last line (past the end iterator)");