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_indexable_segment (const GtkTextIter *iter)
469 GtkTextRealIter *real;
471 g_return_val_if_fail (iter != NULL, 0);
473 real = gtk_text_iter_make_real (iter);
478 check_invariants (iter);
480 g_assert (real->segment != NULL);
482 return real->segment;
486 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
488 GtkTextRealIter *real;
490 g_return_val_if_fail (iter != NULL, 0);
492 real = gtk_text_iter_make_real (iter);
497 check_invariants (iter);
499 g_assert (real->any_segment != NULL);
501 return real->any_segment;
505 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
507 GtkTextRealIter *real;
509 g_return_val_if_fail (iter != NULL, 0);
511 real = gtk_text_iter_make_real (iter);
516 ensure_byte_offsets (real);
518 check_invariants (iter);
520 return real->segment_byte_offset;
524 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
526 GtkTextRealIter *real;
528 g_return_val_if_fail (iter != NULL, 0);
530 real = gtk_text_iter_make_real (iter);
535 ensure_char_offsets (real);
537 check_invariants (iter);
539 return real->segment_char_offset;
542 /* This function does not require a still-valid
545 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
547 const GtkTextRealIter *real;
549 g_return_val_if_fail (iter != NULL, 0);
551 real = (const GtkTextRealIter*)iter;
556 /* This function does not require a still-valid
559 _gtk_text_iter_get_btree (const GtkTextIter *iter)
561 const GtkTextRealIter *real;
563 g_return_val_if_fail (iter != NULL, 0);
565 real = (const GtkTextRealIter*)iter;
575 * gtk_text_iter_get_offset:
578 * Returns the character offset of an iterator.
579 * Each character in a #GtkTextBuffer has an offset,
580 * starting with 0 for the first character in the buffer.
581 * Use gtk_text_buffer_get_iter_at_offset () to convert an
582 * offset back into an iterator.
584 * Return value: a character offset
587 gtk_text_iter_get_offset (const GtkTextIter *iter)
589 GtkTextRealIter *real;
591 g_return_val_if_fail (iter != NULL, 0);
593 real = gtk_text_iter_make_surreal (iter);
598 check_invariants (iter);
600 if (real->cached_char_index < 0)
602 ensure_char_offsets (real);
604 real->cached_char_index =
605 _gtk_text_line_char_index (real->line);
606 real->cached_char_index += real->line_char_offset;
609 check_invariants (iter);
611 return real->cached_char_index;
615 * gtk_text_iter_get_line:
618 * Returns the line number containing the iterator. Lines in
619 * a #GtkTextBuffer are numbered beginning with 0 for the first
620 * line in the buffer.
622 * Return value: a line number
625 gtk_text_iter_get_line (const GtkTextIter *iter)
627 GtkTextRealIter *real;
629 g_return_val_if_fail (iter != NULL, 0);
631 real = gtk_text_iter_make_surreal (iter);
636 if (real->cached_line_number < 0)
637 real->cached_line_number =
638 _gtk_text_line_get_number (real->line);
640 check_invariants (iter);
642 return real->cached_line_number;
646 * gtk_text_iter_get_line_offset:
649 * Returns the character offset of the iterator,
650 * counting from the start of a newline-terminated line.
651 * The first character on the line has offset 0.
653 * Return value: offset from start of line
656 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
658 GtkTextRealIter *real;
660 g_return_val_if_fail (iter != NULL, 0);
662 real = gtk_text_iter_make_surreal (iter);
667 ensure_char_offsets (real);
669 check_invariants (iter);
671 return real->line_char_offset;
675 * gtk_text_iter_get_line_index:
678 * Returns the byte index of the iterator, counting
679 * from the start of a newline-terminated line.
680 * Remember that #GtkTextBuffer encodes text in
681 * UTF-8, and that characters can require a variable
682 * number of bytes to represent.
684 * Return value: distance from start of line, in bytes
687 gtk_text_iter_get_line_index (const GtkTextIter *iter)
689 GtkTextRealIter *real;
691 g_return_val_if_fail (iter != NULL, 0);
693 real = gtk_text_iter_make_surreal (iter);
698 ensure_byte_offsets (real);
700 check_invariants (iter);
702 return real->line_byte_offset;
706 * gtk_text_iter_get_visible_line_offset:
707 * @iter: a #GtkTextIter
709 * Returns the offset in characters from the start of the
710 * line to the given @iter, not counting characters that
711 * are invisible due to tags with the "invisible" flag
714 * Return value: offset in visible characters from the start of the line
717 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
719 GtkTextRealIter *real;
721 GtkTextLineSegment *seg;
724 g_return_val_if_fail (iter != NULL, 0);
726 real = gtk_text_iter_make_real (iter);
731 ensure_char_offsets (real);
733 check_invariants (iter);
735 vis_offset = real->line_char_offset;
737 g_assert (vis_offset >= 0);
739 _gtk_text_btree_get_iter_at_line (real->tree,
744 seg = _gtk_text_iter_get_indexable_segment (&pos);
746 while (seg != real->segment)
748 /* This is a pretty expensive call, making the
749 * whole function pretty lame; we could keep track
750 * of current invisibility state by looking at toggle
751 * segments as we loop, and then call this function
752 * only once per line, in order to speed up the loop
755 if (_gtk_text_btree_char_is_invisible (&pos))
756 vis_offset -= seg->char_count;
758 _gtk_text_iter_forward_indexable_segment (&pos);
760 seg = _gtk_text_iter_get_indexable_segment (&pos);
763 if (_gtk_text_btree_char_is_invisible (&pos))
764 vis_offset -= real->segment_char_offset;
771 * gtk_text_iter_get_visible_line_index:
772 * @iter: a #GtkTextIter
774 * Returns the number of bytes from the start of the
775 * line to the given @iter, not counting bytes that
776 * are invisible due to tags with the "invisible" flag
779 * Return value: byte index of @iter with respect to the start of the line
782 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
784 GtkTextRealIter *real;
786 GtkTextLineSegment *seg;
789 g_return_val_if_fail (iter != NULL, 0);
791 real = gtk_text_iter_make_real (iter);
796 ensure_byte_offsets (real);
798 check_invariants (iter);
800 vis_offset = real->line_byte_offset;
802 g_assert (vis_offset >= 0);
804 _gtk_text_btree_get_iter_at_line (real->tree,
809 seg = _gtk_text_iter_get_indexable_segment (&pos);
811 while (seg != real->segment)
813 /* This is a pretty expensive call, making the
814 * whole function pretty lame; we could keep track
815 * of current invisibility state by looking at toggle
816 * segments as we loop, and then call this function
817 * only once per line, in order to speed up the loop
820 if (_gtk_text_btree_char_is_invisible (&pos))
821 vis_offset -= seg->byte_count;
823 _gtk_text_iter_forward_indexable_segment (&pos);
825 seg = _gtk_text_iter_get_indexable_segment (&pos);
828 if (_gtk_text_btree_char_is_invisible (&pos))
829 vis_offset -= real->segment_byte_offset;
839 * gtk_text_iter_get_char:
842 * Returns the Unicode character at this iterator. (Equivalent to
843 * operator* on a C++ iterator.) If the iterator points at a
844 * non-character element, such as an image embedded in the buffer, the
845 * Unicode "unknown" character 0xFFFC is returned. If invoked on
846 * the end iterator, zero is returned; zero is not a valid Unicode character.
847 * So you can write a loop which ends when gtk_text_iter_get_char ()
850 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
853 gtk_text_iter_get_char (const GtkTextIter *iter)
855 GtkTextRealIter *real;
857 g_return_val_if_fail (iter != NULL, 0);
859 real = gtk_text_iter_make_real (iter);
864 check_invariants (iter);
866 if (gtk_text_iter_is_end (iter))
868 else if (real->segment->type == >k_text_char_type)
870 ensure_byte_offsets (real);
872 return g_utf8_get_char (real->segment->body.chars +
873 real->segment_byte_offset);
877 /* Unicode "unknown character" 0xFFFC */
878 return GTK_TEXT_UNKNOWN_CHAR;
883 * gtk_text_iter_get_slice:
884 * @start: iterator at start of a range
885 * @end: iterator at end of a range
887 * Returns the text in the given range. A "slice" is an array of
888 * characters encoded in UTF-8 format, including the Unicode "unknown"
889 * character 0xFFFC for iterable non-character elements in the buffer,
890 * such as images. Because images are encoded in the slice, byte and
891 * character offsets in the returned array will correspond to byte
892 * offsets in the text buffer. Note that 0xFFFC can occur in normal
893 * text as well, so it is not a reliable indicator that a pixbuf or
894 * widget is in the buffer.
896 * Return value: slice of text from the buffer
899 gtk_text_iter_get_slice (const GtkTextIter *start,
900 const GtkTextIter *end)
902 g_return_val_if_fail (start != NULL, NULL);
903 g_return_val_if_fail (end != NULL, NULL);
905 check_invariants (start);
906 check_invariants (end);
908 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
912 * gtk_text_iter_get_text:
913 * @start: iterator at start of a range
914 * @end: iterator at end of a range
916 * Returns <emphasis>text</emphasis> in the given range. If the range
917 * contains non-text elements such as images, the character and byte
918 * offsets in the returned string will not correspond to character and
919 * byte offsets in the buffer. If you want offsets to correspond, see
920 * gtk_text_iter_get_slice ().
922 * Return value: array of characters from the buffer
925 gtk_text_iter_get_text (const GtkTextIter *start,
926 const GtkTextIter *end)
928 g_return_val_if_fail (start != NULL, NULL);
929 g_return_val_if_fail (end != NULL, NULL);
931 check_invariants (start);
932 check_invariants (end);
934 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
938 * gtk_text_iter_get_visible_slice:
939 * @start: iterator at start of range
940 * @end: iterator at end of range
942 * Like gtk_text_iter_get_slice (), but invisible text is not included.
943 * Invisible text is usually invisible because a #GtkTextTag with the
944 * "invisible" attribute turned on has been applied to it.
946 * Return value: slice of text from the buffer
949 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
950 const GtkTextIter *end)
952 g_return_val_if_fail (start != NULL, NULL);
953 g_return_val_if_fail (end != NULL, NULL);
955 check_invariants (start);
956 check_invariants (end);
958 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
962 * gtk_text_iter_get_visible_text:
963 * @start: iterator at start of range
964 * @end: iterator at end of range
966 * Like gtk_text_iter_get_text (), but invisible text is not included.
967 * Invisible text is usually invisible because a #GtkTextTag with the
968 * "invisible" attribute turned on has been applied to it.
970 * Return value: string containing visible text in the range
973 gtk_text_iter_get_visible_text (const GtkTextIter *start,
974 const GtkTextIter *end)
976 g_return_val_if_fail (start != NULL, NULL);
977 g_return_val_if_fail (end != NULL, NULL);
979 check_invariants (start);
980 check_invariants (end);
982 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
986 * gtk_text_iter_get_pixbuf:
989 * If the location pointed to by @iter contains a pixbuf, the pixbuf
990 * is returned (with no new reference count added). Otherwise,
993 * Return value: the pixbuf at @iter
996 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
998 GtkTextRealIter *real;
1000 g_return_val_if_fail (iter != NULL, NULL);
1002 real = gtk_text_iter_make_real (iter);
1007 check_invariants (iter);
1009 if (real->segment->type != >k_text_pixbuf_type)
1012 return real->segment->body.pixbuf.pixbuf;
1016 * gtk_text_iter_get_child_anchor:
1017 * @iter: an iterator
1019 * If the location pointed to by @iter contains a child anchor, the
1020 * anchor is returned (with no new reference count added). Otherwise,
1021 * %NULL is returned.
1023 * Return value: the anchor at @iter
1026 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1028 GtkTextRealIter *real;
1030 g_return_val_if_fail (iter != NULL, NULL);
1032 real = gtk_text_iter_make_real (iter);
1037 check_invariants (iter);
1039 if (real->segment->type != >k_text_child_type)
1042 return real->segment->body.child.obj;
1046 * gtk_text_iter_get_marks:
1047 * @iter: an iterator
1049 * Returns a list of all #GtkTextMark at this location. Because marks
1050 * are not iterable (they don't take up any "space" in the buffer,
1051 * they are just marks in between iterable locations), multiple marks
1052 * can exist in the same place. The returned list is not in any
1055 * Return value: list of #GtkTextMark
1058 gtk_text_iter_get_marks (const GtkTextIter *iter)
1060 GtkTextRealIter *real;
1061 GtkTextLineSegment *seg;
1064 g_return_val_if_fail (iter != NULL, NULL);
1066 real = gtk_text_iter_make_real (iter);
1071 check_invariants (iter);
1074 seg = real->any_segment;
1075 while (seg != real->segment)
1077 if (seg->type == >k_text_left_mark_type ||
1078 seg->type == >k_text_right_mark_type)
1079 retval = g_slist_prepend (retval, seg->body.mark.obj);
1084 /* The returned list isn't guaranteed to be in any special order,
1090 * gtk_text_iter_get_toggled_tags:
1091 * @iter: an iterator
1092 * @toggled_on: %TRUE to get toggled-on tags
1094 * Returns a list of #GtkTextTag that are toggled on or off at this
1095 * point. (If @toggled_on is %TRUE, the list contains tags that are
1096 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1097 * range of characters following @iter has that tag applied to it. If
1098 * a tag is toggled off, then some non-empty range following @iter
1099 * does <emphasis>not</emphasis> have the tag applied to it.
1101 * Return value: tags toggled at this point
1104 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1105 gboolean toggled_on)
1107 GtkTextRealIter *real;
1108 GtkTextLineSegment *seg;
1111 g_return_val_if_fail (iter != NULL, NULL);
1113 real = gtk_text_iter_make_real (iter);
1118 check_invariants (iter);
1121 seg = real->any_segment;
1122 while (seg != real->segment)
1126 if (seg->type == >k_text_toggle_on_type)
1128 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1133 if (seg->type == >k_text_toggle_off_type)
1135 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1142 /* The returned list isn't guaranteed to be in any special order,
1148 * gtk_text_iter_begins_tag:
1149 * @iter: an iterator
1150 * @tag: a #GtkTextTag, or %NULL
1152 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1153 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1154 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1155 * <emphasis>start</emphasis> of the tagged range;
1156 * gtk_text_iter_has_tag () tells you whether an iterator is
1157 * <emphasis>within</emphasis> a tagged range.
1159 * Return value: whether @iter is the start of a range tagged with @tag
1162 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1165 GtkTextRealIter *real;
1166 GtkTextLineSegment *seg;
1168 g_return_val_if_fail (iter != NULL, FALSE);
1170 real = gtk_text_iter_make_real (iter);
1175 check_invariants (iter);
1177 seg = real->any_segment;
1178 while (seg != real->segment)
1180 if (seg->type == >k_text_toggle_on_type)
1183 seg->body.toggle.info->tag == tag)
1194 * gtk_text_iter_ends_tag:
1195 * @iter: an iterator
1196 * @tag: a #GtkTextTag, or %NULL
1198 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1199 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1200 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1201 * <emphasis>end</emphasis> of the tagged range;
1202 * gtk_text_iter_has_tag () tells you whether an iterator is
1203 * <emphasis>within</emphasis> a tagged range.
1205 * Return value: whether @iter is the end of a range tagged with @tag
1209 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1212 GtkTextRealIter *real;
1213 GtkTextLineSegment *seg;
1215 g_return_val_if_fail (iter != NULL, FALSE);
1217 real = gtk_text_iter_make_real (iter);
1222 check_invariants (iter);
1224 seg = real->any_segment;
1225 while (seg != real->segment)
1227 if (seg->type == >k_text_toggle_off_type)
1230 seg->body.toggle.info->tag == tag)
1241 * gtk_text_iter_toggles_tag:
1242 * @iter: an iterator
1243 * @tag: a #GtkTextTag, or %NULL
1245 * This is equivalent to (gtk_text_iter_begins_tag () ||
1246 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1247 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1249 * Return value: whether @tag is toggled on or off at @iter
1252 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1255 GtkTextRealIter *real;
1256 GtkTextLineSegment *seg;
1258 g_return_val_if_fail (iter != NULL, FALSE);
1260 real = gtk_text_iter_make_real (iter);
1265 check_invariants (iter);
1267 seg = real->any_segment;
1268 while (seg != real->segment)
1270 if ( (seg->type == >k_text_toggle_off_type ||
1271 seg->type == >k_text_toggle_on_type) &&
1273 seg->body.toggle.info->tag == tag) )
1283 * gtk_text_iter_has_tag:
1284 * @iter: an iterator
1285 * @tag: a #GtkTextTag
1287 * Returns %TRUE if @iter is within a range tagged with @tag.
1289 * Return value: whether @iter is tagged with @tag
1292 gtk_text_iter_has_tag (const GtkTextIter *iter,
1295 GtkTextRealIter *real;
1297 g_return_val_if_fail (iter != NULL, FALSE);
1298 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1300 real = gtk_text_iter_make_surreal (iter);
1305 check_invariants (iter);
1307 if (real->line_byte_offset >= 0)
1309 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1310 real->line_byte_offset, tag);
1314 g_assert (real->line_char_offset >= 0);
1315 return _gtk_text_line_char_has_tag (real->line, real->tree,
1316 real->line_char_offset, tag);
1321 * gtk_text_iter_get_tags:
1322 * @iter: a #GtkTextIter
1324 * Returns a list of tags that apply to @iter, in ascending order of
1325 * priority (highest-priority tags are last). The #GtkTextTag in the
1326 * list don't have a reference added, but you have to free the list
1329 * Return value: list of #GtkTextTag
1332 gtk_text_iter_get_tags (const GtkTextIter *iter)
1339 g_return_val_if_fail (iter != NULL, NULL);
1341 /* Get the tags at this spot */
1342 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1344 /* No tags, use default style */
1345 if (tags == NULL || tag_count == 0)
1353 /* Sort tags in ascending order of priority */
1354 _gtk_text_tag_array_sort (tags, tag_count);
1358 while (i < tag_count)
1360 retval = g_slist_prepend (retval, tags[i]);
1366 /* Return tags in ascending order of priority */
1367 return g_slist_reverse (retval);
1371 * gtk_text_iter_editable:
1372 * @iter: an iterator
1373 * @default_setting: %TRUE if text is editable by default
1375 * Returns whether the character at @iter is within an editable region
1376 * of text. Non-editable text is "locked" and can't be changed by the
1377 * user via #GtkTextView. This function is simply a convenience
1378 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1379 * to this text affect editability, @default_setting will be returned.
1381 * You don't want to use this function to decide whether text can be
1382 * inserted at @iter, because for insertion you don't want to know
1383 * whether the char at @iter is inside an editable range, you want to
1384 * know whether a new character inserted at @iter would be inside an
1385 * editable range. Use gtk_text_iter_can_insert() to handle this
1388 * Return value: whether @iter is inside an editable range
1391 gtk_text_iter_editable (const GtkTextIter *iter,
1392 gboolean default_setting)
1394 GtkTextAttributes *values;
1397 g_return_val_if_fail (iter != NULL, FALSE);
1399 values = gtk_text_attributes_new ();
1401 values->editable = default_setting;
1403 gtk_text_iter_get_attributes (iter, values);
1405 retval = values->editable;
1407 gtk_text_attributes_unref (values);
1413 * gtk_text_iter_can_insert:
1414 * @iter: an iterator
1415 * @default_editability: %TRUE if text is editable by default
1417 * Considering the default editability of the buffer, and tags that
1418 * affect editability, determines whether text inserted at @iter would
1419 * be editable. If text inserted at @iter would be editable then the
1420 * user should be allowed to insert text at @iter.
1421 * gtk_text_buffer_insert_interactive() uses this function to decide
1422 * whether insertions are allowed at a given position.
1424 * Return value: whether text inserted at @iter would be editable
1427 gtk_text_iter_can_insert (const GtkTextIter *iter,
1428 gboolean default_editability)
1430 g_return_val_if_fail (iter != NULL, FALSE);
1432 if (gtk_text_iter_editable (iter, default_editability))
1434 /* If at start/end of buffer, default editability is used */
1435 else if ((gtk_text_iter_is_start (iter) ||
1436 gtk_text_iter_is_end (iter)) &&
1437 default_editability)
1441 /* if iter isn't editable, and the char before iter is,
1442 * then iter is the first char in an editable region
1443 * and thus insertion at iter results in editable text.
1445 GtkTextIter prev = *iter;
1446 gtk_text_iter_backward_char (&prev);
1447 return gtk_text_iter_editable (&prev, default_editability);
1453 * gtk_text_iter_get_language:
1454 * @iter: an iterator
1456 * A convenience wrapper around gtk_text_iter_get_attributes (),
1457 * which returns the language in effect at @iter. If no tags affecting
1458 * language apply to @iter, the return value is identical to that of
1459 * gtk_get_default_language ().
1461 * Return value: language in effect at @iter
1464 gtk_text_iter_get_language (const GtkTextIter *iter)
1466 GtkTextAttributes *values;
1467 PangoLanguage *retval;
1469 values = gtk_text_attributes_new ();
1471 gtk_text_iter_get_attributes (iter, values);
1473 retval = values->language;
1475 gtk_text_attributes_unref (values);
1481 * gtk_text_iter_starts_line:
1482 * @iter: an iterator
1484 * Returns %TRUE if @iter begins a paragraph,
1485 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1486 * However this function is potentially more efficient than
1487 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1488 * the offset, it just has to see whether it's 0.
1490 * Return value: whether @iter begins a line
1493 gtk_text_iter_starts_line (const GtkTextIter *iter)
1495 GtkTextRealIter *real;
1497 g_return_val_if_fail (iter != NULL, FALSE);
1499 real = gtk_text_iter_make_surreal (iter);
1504 check_invariants (iter);
1506 if (real->line_byte_offset >= 0)
1508 return (real->line_byte_offset == 0);
1512 g_assert (real->line_char_offset >= 0);
1513 return (real->line_char_offset == 0);
1518 * gtk_text_iter_ends_line:
1519 * @iter: an iterator
1521 * Returns %TRUE if @iter points to the start of the paragraph
1522 * delimiter characters for a line (delimiters will be either a
1523 * newline, a carriage return, a carriage return followed by a
1524 * newline, or a Unicode paragraph separator character). Note that an
1525 * iterator pointing to the \n of a \r\n pair will not be counted as
1526 * the end of a line, the line ends before the \r. The end iterator is
1527 * considered to be at the end of a line, even though there are no
1528 * paragraph delimiter chars there.
1530 * Return value: whether @iter is at the end of a line
1533 gtk_text_iter_ends_line (const GtkTextIter *iter)
1535 GtkTextRealIter *real;
1538 g_return_val_if_fail (iter != NULL, FALSE);
1540 real = gtk_text_iter_make_real (iter);
1542 check_invariants (iter);
1544 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1545 * Unicode 3.0; update this if that changes.
1547 #define PARAGRAPH_SEPARATOR 0x2029
1549 wc = gtk_text_iter_get_char (iter);
1551 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1553 else if (wc == '\n')
1555 /* need to determine if a \r precedes the \n, in which case
1556 * we aren't the end of the line
1558 GtkTextIter tmp = *iter;
1559 if (!gtk_text_iter_backward_char (&tmp))
1562 return gtk_text_iter_get_char (&tmp) != '\r';
1569 * gtk_text_iter_is_end:
1570 * @iter: an iterator
1572 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1573 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1574 * the most efficient way to check whether an iterator is the end
1577 * Return value: whether @iter is the end iterator
1580 gtk_text_iter_is_end (const GtkTextIter *iter)
1582 GtkTextRealIter *real;
1584 g_return_val_if_fail (iter != NULL, FALSE);
1586 real = gtk_text_iter_make_surreal (iter);
1591 check_invariants (iter);
1593 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1596 /* Now we need the segments validated */
1597 real = gtk_text_iter_make_real (iter);
1602 return _gtk_text_btree_is_end (real->tree, real->line,
1604 real->segment_byte_offset,
1605 real->segment_char_offset);
1609 * gtk_text_iter_is_start:
1610 * @iter: an iterator
1612 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1613 * if @iter has a character offset of 0.
1615 * Return value: whether @iter is the first in the buffer
1618 gtk_text_iter_is_start (const GtkTextIter *iter)
1620 return gtk_text_iter_get_offset (iter) == 0;
1624 * gtk_text_iter_get_chars_in_line:
1625 * @iter: an iterator
1627 * Returns the number of characters in the line containing @iter,
1628 * including the paragraph delimiters.
1630 * Return value: number of characters in the line
1633 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1635 GtkTextRealIter *real;
1637 GtkTextLineSegment *seg;
1639 g_return_val_if_fail (iter != NULL, FALSE);
1641 real = gtk_text_iter_make_surreal (iter);
1646 check_invariants (iter);
1648 if (real->line_char_offset >= 0)
1650 /* We can start at the segments we've already found. */
1651 count = real->line_char_offset - real->segment_char_offset;
1652 seg = _gtk_text_iter_get_indexable_segment (iter);
1656 /* count whole line. */
1657 seg = real->line->segments;
1664 count += seg->char_count;
1669 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1670 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1676 * gtk_text_iter_get_bytes_in_line:
1677 * @iter: an iterator
1679 * Returns the number of bytes in the line containing @iter,
1680 * including the paragraph delimiters.
1682 * Return value: number of bytes in the line
1685 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1687 GtkTextRealIter *real;
1689 GtkTextLineSegment *seg;
1691 g_return_val_if_fail (iter != NULL, FALSE);
1693 real = gtk_text_iter_make_surreal (iter);
1698 check_invariants (iter);
1700 if (real->line_byte_offset >= 0)
1702 /* We can start at the segments we've already found. */
1703 count = real->line_byte_offset - real->segment_byte_offset;
1704 seg = _gtk_text_iter_get_indexable_segment (iter);
1708 /* count whole line. */
1709 seg = real->line->segments;
1715 count += seg->byte_count;
1720 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1721 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1727 * gtk_text_iter_get_attributes:
1728 * @iter: an iterator
1729 * @values: a #GtkTextAttributes to be filled in
1731 * Computes the effect of any tags applied to this spot in the
1732 * text. The @values parameter should be initialized to the default
1733 * settings you wish to use if no tags are in effect. You'd typically
1734 * obtain the defaults from gtk_text_view_get_default_attributes().
1736 * gtk_text_iter_get_attributes () will modify @values, applying the
1737 * effects of any tags present at @iter. If any tags affected @values,
1738 * the function returns %TRUE.
1740 * Return value: %TRUE if @values was modified
1743 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1744 GtkTextAttributes *values)
1749 /* Get the tags at this spot */
1750 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1752 /* No tags, use default style */
1753 if (tags == NULL || tag_count == 0)
1761 /* Sort tags in ascending order of priority */
1762 _gtk_text_tag_array_sort (tags, tag_count);
1764 _gtk_text_attributes_fill_from_tags (values,
1774 * Increments/decrements
1777 /* The return value of this indicates WHETHER WE MOVED.
1778 * The return value of public functions indicates
1779 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1781 * This function will not change the iterator if
1782 * it's already on the last (end iter) line, i.e. it
1783 * won't move to the end of the last line.
1786 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1788 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1790 GtkTextLine *new_line;
1792 new_line = _gtk_text_line_next (real->line);
1793 g_assert (new_line);
1794 g_assert (new_line != real->line);
1795 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1797 real->line = new_line;
1799 real->line_byte_offset = 0;
1800 real->line_char_offset = 0;
1802 real->segment_byte_offset = 0;
1803 real->segment_char_offset = 0;
1805 /* Find first segments in new line */
1806 real->any_segment = real->line->segments;
1807 real->segment = real->any_segment;
1808 while (real->segment->char_count == 0)
1809 real->segment = real->segment->next;
1815 /* There is no way to move forward a line; we were already at
1816 * the line containing the end iterator.
1817 * However we may not be at the end iterator itself.
1825 /* The return value of this indicates WHETHER WE MOVED.
1826 * The return value of public functions indicates
1827 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1830 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1832 GtkTextLine *new_line;
1834 new_line = _gtk_text_line_previous (real->line);
1836 g_assert (new_line != real->line);
1838 if (new_line != NULL)
1840 real->line = new_line;
1842 real->line_byte_offset = 0;
1843 real->line_char_offset = 0;
1845 real->segment_byte_offset = 0;
1846 real->segment_char_offset = 0;
1848 /* Find first segments in new line */
1849 real->any_segment = real->line->segments;
1850 real->segment = real->any_segment;
1851 while (real->segment->char_count == 0)
1852 real->segment = real->segment->next;
1858 /* There is no way to move backward; we were already
1859 at the first line. */
1861 /* We leave real->line as-is */
1863 /* Note that we didn't clamp to the start of the first line. */
1869 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1873 forward_char (GtkTextRealIter *real)
1875 GtkTextIter *iter = (GtkTextIter*)real;
1877 check_invariants ((GtkTextIter*)real);
1879 ensure_char_offsets (real);
1881 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1883 /* Need to move to the next segment; if no next segment,
1884 need to move to next line. */
1885 return _gtk_text_iter_forward_indexable_segment (iter);
1889 /* Just moving within a segment. Keep byte count
1890 up-to-date, if it was already up-to-date. */
1892 g_assert (real->segment->type == >k_text_char_type);
1894 if (real->line_byte_offset >= 0)
1897 const char * start =
1898 real->segment->body.chars + real->segment_byte_offset;
1900 bytes = g_utf8_next_char (start) - start;
1902 real->line_byte_offset += bytes;
1903 real->segment_byte_offset += bytes;
1905 g_assert (real->segment_byte_offset < real->segment->byte_count);
1908 real->line_char_offset += 1;
1909 real->segment_char_offset += 1;
1911 adjust_char_index (real, 1);
1913 g_assert (real->segment_char_offset < real->segment->char_count);
1915 /* We moved into the middle of a segment, so the any_segment
1916 must now be the segment we're in the middle of. */
1917 real->any_segment = real->segment;
1919 check_invariants ((GtkTextIter*)real);
1921 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1929 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1931 /* Need to move to the next segment; if no next segment,
1932 need to move to next line. */
1933 GtkTextLineSegment *seg;
1934 GtkTextLineSegment *any_seg;
1935 GtkTextRealIter *real;
1939 g_return_val_if_fail (iter != NULL, FALSE);
1941 real = gtk_text_iter_make_real (iter);
1946 check_invariants (iter);
1948 if (real->line_char_offset >= 0)
1950 chars_skipped = real->segment->char_count - real->segment_char_offset;
1951 g_assert (chars_skipped > 0);
1956 if (real->line_byte_offset >= 0)
1958 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1959 g_assert (bytes_skipped > 0);
1964 /* Get first segment of any kind */
1965 any_seg = real->segment->next;
1966 /* skip non-indexable segments, if any */
1968 while (seg != NULL && seg->char_count == 0)
1973 real->any_segment = any_seg;
1974 real->segment = seg;
1976 if (real->line_byte_offset >= 0)
1978 g_assert (bytes_skipped > 0);
1979 real->segment_byte_offset = 0;
1980 real->line_byte_offset += bytes_skipped;
1983 if (real->line_char_offset >= 0)
1985 g_assert (chars_skipped > 0);
1986 real->segment_char_offset = 0;
1987 real->line_char_offset += chars_skipped;
1988 adjust_char_index (real, chars_skipped);
1991 check_invariants (iter);
1993 return !gtk_text_iter_is_end (iter);
1997 /* End of the line */
1998 if (forward_line_leaving_caches_unmodified (real))
2000 adjust_line_number (real, 1);
2001 if (real->line_char_offset >= 0)
2002 adjust_char_index (real, chars_skipped);
2004 g_assert (real->line_byte_offset == 0);
2005 g_assert (real->line_char_offset == 0);
2006 g_assert (real->segment_byte_offset == 0);
2007 g_assert (real->segment_char_offset == 0);
2008 g_assert (gtk_text_iter_starts_line (iter));
2010 check_invariants (iter);
2012 return !gtk_text_iter_is_end (iter);
2016 /* End of buffer, but iter is still at start of last segment,
2017 * not at the end iterator. We put it on the end iterator.
2020 check_invariants (iter);
2022 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2023 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2025 gtk_text_iter_forward_to_line_end (iter);
2027 g_assert (gtk_text_iter_is_end (iter));
2035 at_last_indexable_segment (GtkTextRealIter *real)
2037 GtkTextLineSegment *seg;
2039 /* Return TRUE if there are no indexable segments after
2043 seg = real->segment->next;
2046 if (seg->char_count > 0)
2053 /* Goes back to the start of the next segment, even if
2054 * we're not at the start of the current segment (always
2055 * ends up on a different segment if it returns TRUE)
2058 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2060 /* Move to the start of the previous segment; if no previous
2061 * segment, to the last segment in the previous line. This is
2062 * inherently a bit inefficient due to the singly-linked list and
2063 * tree nodes, but we can't afford the RAM for doubly-linked.
2065 GtkTextRealIter *real;
2066 GtkTextLineSegment *seg;
2067 GtkTextLineSegment *any_seg;
2068 GtkTextLineSegment *prev_seg;
2069 GtkTextLineSegment *prev_any_seg;
2073 g_return_val_if_fail (iter != NULL, FALSE);
2075 real = gtk_text_iter_make_real (iter);
2080 check_invariants (iter);
2082 /* Find first segments in line */
2083 any_seg = real->line->segments;
2085 while (seg->char_count == 0)
2088 if (seg == real->segment)
2090 /* Could probably do this case faster by hand-coding the
2094 /* We were already at the start of a line;
2095 * go back to the previous line.
2097 if (gtk_text_iter_backward_line (iter))
2099 /* Go forward to last indexable segment in line. */
2100 while (!at_last_indexable_segment (real))
2101 _gtk_text_iter_forward_indexable_segment (iter);
2103 check_invariants (iter);
2108 return FALSE; /* We were at the start of the first line. */
2111 /* We must be in the middle of a line; so find the indexable
2112 * segment just before our current segment.
2114 g_assert (seg != real->segment);
2118 prev_any_seg = any_seg;
2120 any_seg = seg->next;
2122 while (seg->char_count == 0)
2125 while (seg != real->segment);
2127 g_assert (prev_seg != NULL);
2128 g_assert (prev_any_seg != NULL);
2129 g_assert (prev_seg->char_count > 0);
2131 /* We skipped the entire previous segment, plus any
2132 * chars we were into the current segment.
2134 if (real->segment_byte_offset >= 0)
2135 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2139 if (real->segment_char_offset >= 0)
2140 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2144 real->segment = prev_seg;
2145 real->any_segment = prev_any_seg;
2146 real->segment_byte_offset = 0;
2147 real->segment_char_offset = 0;
2149 if (bytes_skipped >= 0)
2151 if (real->line_byte_offset >= 0)
2153 real->line_byte_offset -= bytes_skipped;
2154 g_assert (real->line_byte_offset >= 0);
2158 real->line_byte_offset = -1;
2160 if (chars_skipped >= 0)
2162 if (real->line_char_offset >= 0)
2164 real->line_char_offset -= chars_skipped;
2165 g_assert (real->line_char_offset >= 0);
2168 if (real->cached_char_index >= 0)
2170 real->cached_char_index -= chars_skipped;
2171 g_assert (real->cached_char_index >= 0);
2176 real->line_char_offset = -1;
2177 real->cached_char_index = -1;
2180 /* line number is unchanged. */
2182 check_invariants (iter);
2188 * gtk_text_iter_forward_char:
2189 * @iter: an iterator
2191 * Moves @iter forward by one character offset. Note that images
2192 * embedded in the buffer occupy 1 character slot, so
2193 * gtk_text_iter_forward_char () may actually move onto an image instead
2194 * of a character, if you have images in your buffer. If @iter is the
2195 * end iterator or one character before it, @iter will now point at
2196 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2197 * convenience when writing loops.
2199 * Return value: whether @iter moved and is dereferenceable
2202 gtk_text_iter_forward_char (GtkTextIter *iter)
2204 GtkTextRealIter *real;
2206 g_return_val_if_fail (iter != NULL, FALSE);
2208 real = gtk_text_iter_make_real (iter);
2214 check_invariants (iter);
2215 return forward_char (real);
2220 * gtk_text_iter_backward_char:
2221 * @iter: an iterator
2223 * Moves backward by one character offset. Returns %TRUE if movement
2224 * was possible; if @iter was the first in the buffer (character
2225 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2228 * Return value: whether movement was possible
2231 gtk_text_iter_backward_char (GtkTextIter *iter)
2233 g_return_val_if_fail (iter != NULL, FALSE);
2235 check_invariants (iter);
2237 return gtk_text_iter_backward_chars (iter, 1);
2241 Definitely we should try to linear scan as often as possible for
2242 movement within a single line, because we can't use the BTree to
2243 speed within-line searches up; for movement between lines, we would
2244 like to avoid the linear scan probably.
2246 Instead of using this constant, it might be nice to cache the line
2247 length in the iterator and linear scan if motion is within a single
2250 I guess you'd have to profile the various approaches.
2252 #define MAX_LINEAR_SCAN 150
2256 * gtk_text_iter_forward_chars:
2257 * @iter: an iterator
2258 * @count: number of characters to move, may be negative
2260 * Moves @count characters if possible (if @count would move past the
2261 * start or end of the buffer, moves to the start or end of the
2262 * buffer). The return value indicates whether the new position of
2263 * @iter is different from its original position, and dereferenceable
2264 * (the last iterator in the buffer is not dereferenceable). If @count
2265 * is 0, the function does nothing and returns %FALSE.
2267 * Return value: whether @iter moved and is dereferenceable
2270 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2272 GtkTextRealIter *real;
2274 g_return_val_if_fail (iter != NULL, FALSE);
2276 FIX_OVERFLOWS (count);
2278 real = gtk_text_iter_make_real (iter);
2282 else if (count == 0)
2285 return gtk_text_iter_backward_chars (iter, 0 - count);
2286 else if (count < MAX_LINEAR_SCAN)
2288 check_invariants (iter);
2292 if (!forward_char (real))
2297 return forward_char (real);
2301 gint current_char_index;
2302 gint new_char_index;
2304 check_invariants (iter);
2306 current_char_index = gtk_text_iter_get_offset (iter);
2308 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2309 return FALSE; /* can't move forward */
2311 new_char_index = current_char_index + count;
2312 gtk_text_iter_set_offset (iter, new_char_index);
2314 check_invariants (iter);
2316 /* Return FALSE if we're on the non-dereferenceable end
2319 if (gtk_text_iter_is_end (iter))
2327 * gtk_text_iter_backward_chars:
2328 * @iter: an iterator
2329 * @count: number of characters to move
2331 * Moves @count characters backward, if possible (if @count would move
2332 * past the start or end of the buffer, moves to the start or end of
2333 * the buffer). The return value indicates whether the iterator moved
2334 * onto a dereferenceable position; if the iterator didn't move, or
2335 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2336 * the function does nothing and returns %FALSE.
2338 * Return value: whether @iter moved and is dereferenceable
2342 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2344 GtkTextRealIter *real;
2346 g_return_val_if_fail (iter != NULL, FALSE);
2348 FIX_OVERFLOWS (count);
2350 real = gtk_text_iter_make_real (iter);
2354 else if (count == 0)
2357 return gtk_text_iter_forward_chars (iter, 0 - count);
2359 ensure_char_offsets (real);
2360 check_invariants (iter);
2362 /* <, not <=, because if count == segment_char_offset
2363 * we're going to the front of the segment and the any_segment
2366 if (count < real->segment_char_offset)
2368 /* Optimize the within-segment case */
2369 g_assert (real->segment->char_count > 0);
2370 g_assert (real->segment->type == >k_text_char_type);
2372 real->segment_char_offset -= count;
2373 g_assert (real->segment_char_offset >= 0);
2375 if (real->line_byte_offset >= 0)
2377 gint new_byte_offset;
2380 new_byte_offset = 0;
2382 while (i < real->segment_char_offset)
2384 const char * start = real->segment->body.chars + new_byte_offset;
2385 new_byte_offset += g_utf8_next_char (start) - start;
2390 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2391 real->segment_byte_offset = new_byte_offset;
2394 real->line_char_offset -= count;
2396 adjust_char_index (real, 0 - count);
2398 check_invariants (iter);
2404 /* We need to go back into previous segments. For now,
2405 * just keep this really simple. FIXME
2406 * use backward_indexable_segment.
2408 if (TRUE || count > MAX_LINEAR_SCAN)
2410 gint current_char_index;
2411 gint new_char_index;
2413 current_char_index = gtk_text_iter_get_offset (iter);
2415 if (current_char_index == 0)
2416 return FALSE; /* can't move backward */
2418 new_char_index = current_char_index - count;
2419 if (new_char_index < 0)
2422 gtk_text_iter_set_offset (iter, new_char_index);
2424 check_invariants (iter);
2430 /* FIXME backward_indexable_segment here */
2439 /* These two can't be implemented efficiently (always have to use
2440 * a linear scan, since that's the only way to find all the non-text
2445 * gtk_text_iter_forward_text_chars:
2446 * @iter: a #GtkTextIter
2447 * @count: number of chars to move
2449 * Moves forward by @count text characters (pixbufs, widgets,
2450 * etc. do not count as characters for this). Equivalent to moving
2451 * through the results of gtk_text_iter_get_text (), rather than
2452 * gtk_text_iter_get_slice ().
2454 * Return value: whether @iter moved and is dereferenceable
2457 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2466 * gtk_text_iter_forward_text_chars:
2467 * @iter: a #GtkTextIter
2468 * @count: number of chars to move
2470 * Moves backward by @count text characters (pixbufs, widgets,
2471 * etc. do not count as characters for this). Equivalent to moving
2472 * through the results of gtk_text_iter_get_text (), rather than
2473 * gtk_text_iter_get_slice ().
2475 * Return value: whether @iter moved and is dereferenceable
2478 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2487 * gtk_text_iter_forward_line:
2488 * @iter: an iterator
2490 * Moves @iter to the start of the next line. Returns %TRUE if there
2491 * was a next line to move to, and %FALSE if @iter was simply moved to
2492 * the end of the buffer and is now not dereferenceable, or if @iter was
2493 * already at the end of the buffer.
2495 * Return value: whether @iter can be dereferenced
2498 gtk_text_iter_forward_line (GtkTextIter *iter)
2500 GtkTextRealIter *real;
2502 g_return_val_if_fail (iter != NULL, FALSE);
2504 real = gtk_text_iter_make_real (iter);
2509 check_invariants (iter);
2511 if (forward_line_leaving_caches_unmodified (real))
2513 invalidate_char_index (real);
2514 adjust_line_number (real, 1);
2516 check_invariants (iter);
2518 if (gtk_text_iter_is_end (iter))
2525 /* On the last line, move to end of it */
2527 if (!gtk_text_iter_is_end (iter))
2528 gtk_text_iter_forward_to_end (iter);
2530 check_invariants (iter);
2536 * gtk_text_iter_backward_line:
2537 * @iter: an iterator
2539 * Moves @iter to the start of the previous line. Returns %TRUE if
2540 * @iter could be moved; i.e. if @iter was at character offset 0, this
2541 * function returns %FALSE. Therefore if @iter was already on line 0,
2542 * but not at the start of the line, @iter is snapped to the start of
2543 * the line and the function returns %TRUE. (Note that this implies that
2544 * in a loop calling this function, the line number may not change on
2545 * every iteration, if your first iteration is on line 0.)
2547 * Return value: whether @iter moved
2550 gtk_text_iter_backward_line (GtkTextIter *iter)
2552 GtkTextLine *new_line;
2553 GtkTextRealIter *real;
2554 gboolean offset_will_change;
2557 g_return_val_if_fail (iter != NULL, FALSE);
2559 real = gtk_text_iter_make_real (iter);
2564 check_invariants (iter);
2566 new_line = _gtk_text_line_previous (real->line);
2568 offset_will_change = FALSE;
2569 if (real->line_char_offset > 0)
2570 offset_will_change = TRUE;
2572 if (new_line != NULL)
2574 real->line = new_line;
2576 adjust_line_number (real, -1);
2580 if (!offset_will_change)
2584 invalidate_char_index (real);
2586 real->line_byte_offset = 0;
2587 real->line_char_offset = 0;
2589 real->segment_byte_offset = 0;
2590 real->segment_char_offset = 0;
2592 /* Find first segment in line */
2593 real->any_segment = real->line->segments;
2594 real->segment = _gtk_text_line_byte_to_segment (real->line,
2597 g_assert (offset == 0);
2599 /* Note that if we are on the first line, we snap to the start of
2600 * the first line and return TRUE, so TRUE means the iterator
2601 * changed, not that the line changed; this is maybe a bit
2602 * weird. I'm not sure there's an obvious right thing to do though.
2605 check_invariants (iter);
2612 * gtk_text_iter_forward_lines:
2613 * @iter: a #GtkTextIter
2614 * @count: number of lines to move forward
2616 * Moves @count lines forward, if possible (if @count would move
2617 * past the start or end of the buffer, moves to the start or end of
2618 * the buffer). The return value indicates whether the iterator moved
2619 * onto a dereferenceable position; if the iterator didn't move, or
2620 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2621 * the function does nothing and returns %FALSE. If @count is negative,
2622 * moves backward by 0 - @count lines.
2624 * Return value: whether @iter moved and is dereferenceable
2627 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2629 FIX_OVERFLOWS (count);
2632 return gtk_text_iter_backward_lines (iter, 0 - count);
2633 else if (count == 0)
2635 else if (count == 1)
2637 check_invariants (iter);
2638 return gtk_text_iter_forward_line (iter);
2644 if (gtk_text_iter_is_end (iter))
2647 old_line = gtk_text_iter_get_line (iter);
2649 gtk_text_iter_set_line (iter, old_line + count);
2651 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2653 /* count went past the last line, so move to end of last line */
2654 if (!gtk_text_iter_is_end (iter))
2655 gtk_text_iter_forward_to_end (iter);
2658 return !gtk_text_iter_is_end (iter);
2663 * gtk_text_iter_backward_lines:
2664 * @iter: a #GtkTextIter
2665 * @count: number of lines to move backward
2667 * Moves @count lines backward, if possible (if @count would move
2668 * past the start or end of the buffer, moves to the start or end of
2669 * the buffer). The return value indicates whether the iterator moved
2670 * onto a dereferenceable position; if the iterator didn't move, or
2671 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2672 * the function does nothing and returns %FALSE. If @count is negative,
2673 * moves forward by 0 - @count lines.
2675 * Return value: whether @iter moved and is dereferenceable
2678 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2680 FIX_OVERFLOWS (count);
2683 return gtk_text_iter_forward_lines (iter, 0 - count);
2684 else if (count == 0)
2686 else if (count == 1)
2688 return gtk_text_iter_backward_line (iter);
2694 old_line = gtk_text_iter_get_line (iter);
2696 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2698 return (gtk_text_iter_get_line (iter) != old_line);
2702 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2707 gboolean already_moved_initially);
2709 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2717 find_word_end_func (const PangoLogAttr *attrs,
2722 gboolean already_moved_initially)
2724 if (!already_moved_initially)
2727 /* Find end of next word */
2728 while (offset < min_offset + len &&
2729 !attrs[offset].is_word_end)
2732 *found_offset = offset;
2734 return offset < min_offset + len;
2738 is_word_end_func (const PangoLogAttr *attrs,
2743 return attrs[offset].is_word_end;
2747 find_word_start_func (const PangoLogAttr *attrs,
2752 gboolean already_moved_initially)
2754 if (!already_moved_initially)
2757 /* Find start of prev word */
2758 while (offset >= min_offset &&
2759 !attrs[offset].is_word_start)
2762 *found_offset = offset;
2764 return offset >= min_offset;
2768 is_word_start_func (const PangoLogAttr *attrs,
2773 return attrs[offset].is_word_start;
2777 inside_word_func (const PangoLogAttr *attrs,
2782 /* Find next word start or end */
2783 while (offset >= min_offset &&
2784 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2787 return attrs[offset].is_word_start;
2790 /* Sentence funcs */
2793 find_sentence_end_func (const PangoLogAttr *attrs,
2798 gboolean already_moved_initially)
2800 if (!already_moved_initially)
2803 /* Find end of next sentence */
2804 while (offset < min_offset + len &&
2805 !attrs[offset].is_sentence_end)
2808 *found_offset = offset;
2810 return offset < min_offset + len;
2814 is_sentence_end_func (const PangoLogAttr *attrs,
2819 return attrs[offset].is_sentence_end;
2823 find_sentence_start_func (const PangoLogAttr *attrs,
2828 gboolean already_moved_initially)
2830 if (!already_moved_initially)
2833 /* Find start of prev sentence */
2834 while (offset >= min_offset &&
2835 !attrs[offset].is_sentence_start)
2838 *found_offset = offset;
2840 return offset >= min_offset;
2844 is_sentence_start_func (const PangoLogAttr *attrs,
2849 return attrs[offset].is_sentence_start;
2853 inside_sentence_func (const PangoLogAttr *attrs,
2858 /* Find next sentence start or end */
2859 while (offset >= min_offset &&
2860 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2863 return attrs[offset].is_sentence_start;
2867 test_log_attrs (const GtkTextIter *iter,
2868 TestLogAttrFunc func)
2871 const PangoLogAttr *attrs;
2873 gboolean result = FALSE;
2875 g_return_val_if_fail (iter != NULL, FALSE);
2877 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2880 offset = gtk_text_iter_get_line_offset (iter);
2882 /* char_len may be 0 and attrs will be NULL if so, if
2883 * iter is the end iter and the last line is empty.
2885 * offset may be equal to char_len, since attrs contains an entry
2886 * for one past the end
2889 if (attrs && offset <= char_len)
2890 result = (* func) (attrs, offset, 0, char_len);
2896 find_line_log_attrs (const GtkTextIter *iter,
2897 FindLogAttrFunc func,
2899 gboolean already_moved_initially)
2902 const PangoLogAttr *attrs;
2904 gboolean result = FALSE;
2906 g_return_val_if_fail (iter != NULL, FALSE);
2908 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2911 offset = gtk_text_iter_get_line_offset (iter);
2913 /* char_len may be 0 and attrs will be NULL if so, if
2914 * iter is the end iter and the last line is empty
2918 result = (* func) (attrs, offset, 0, char_len, found_offset,
2919 already_moved_initially);
2924 /* FIXME this function is very, very gratuitously slow */
2926 find_by_log_attrs (GtkTextIter *iter,
2927 FindLogAttrFunc func,
2929 gboolean already_moved_initially)
2933 gboolean found = FALSE;
2935 g_return_val_if_fail (iter != NULL, FALSE);
2939 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2945 if (gtk_text_iter_forward_line (iter))
2946 return find_by_log_attrs (iter, func, forward,
2953 /* go to end of previous line. need to check that
2954 * line is > 0 because backward_line snaps to start of
2955 * line 0 if it's on line 0
2957 if (gtk_text_iter_get_line (iter) > 0 &&
2958 gtk_text_iter_backward_line (iter))
2960 if (!gtk_text_iter_ends_line (iter))
2961 gtk_text_iter_forward_to_line_end (iter);
2963 return find_by_log_attrs (iter, func, forward,
2972 gtk_text_iter_set_line_offset (iter, offset);
2975 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2976 !gtk_text_iter_is_end (iter);
2981 * gtk_text_iter_forward_word_end:
2982 * @iter: a #GtkTextIter
2984 * Moves forward to the next word end. (If @iter is currently on a
2985 * word end, moves forward to the next one after that.) Word breaks
2986 * are determined by Pango and should be correct for nearly any
2987 * language (if not, the correct fix would be to the Pango word break
2990 * Return value: %TRUE if @iter moved and is not the end iterator
2993 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2995 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2999 * gtk_text_iter_backward_word_start:
3000 * @iter: a #GtkTextIter
3002 * Moves backward to the previous word start. (If @iter is currently on a
3003 * word start, moves backward 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_backward_word_start (GtkTextIter *iter)
3013 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3016 /* FIXME a loop around a truly slow function means
3017 * a truly spectacularly slow function.
3021 * gtk_text_iter_forward_word_ends:
3022 * @iter: a #GtkTextIter
3023 * @count: number of times to move
3025 * Calls gtk_text_iter_forward_word_end() up to @count times.
3027 * Return value: %TRUE if @iter moved and is not the end iterator
3030 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3033 g_return_val_if_fail (iter != NULL, FALSE);
3035 FIX_OVERFLOWS (count);
3041 return gtk_text_iter_backward_word_starts (iter, -count);
3043 if (!gtk_text_iter_forward_word_end (iter))
3049 if (!gtk_text_iter_forward_word_end (iter))
3054 return !gtk_text_iter_is_end (iter);
3058 * gtk_text_iter_backward_word_starts
3059 * @iter: a #GtkTextIter
3060 * @count: number of times to move
3062 * Calls gtk_text_iter_backward_word_start() up to @count times.
3064 * Return value: %TRUE if @iter moved and is not the end iterator
3067 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3070 g_return_val_if_fail (iter != NULL, FALSE);
3072 FIX_OVERFLOWS (count);
3075 return gtk_text_iter_forward_word_ends (iter, -count);
3077 if (!gtk_text_iter_backward_word_start (iter))
3083 if (!gtk_text_iter_backward_word_start (iter))
3088 return !gtk_text_iter_is_end (iter);
3092 * gtk_text_iter_starts_word:
3093 * @iter: a #GtkTextIter
3095 * Determines whether @iter begins a natural-language word. Word
3096 * breaks are determined by Pango and should be correct for nearly any
3097 * language (if not, the correct fix would be to the Pango word break
3100 * Return value: %TRUE if @iter is at the start of a word
3103 gtk_text_iter_starts_word (const GtkTextIter *iter)
3105 return test_log_attrs (iter, is_word_start_func);
3109 * gtk_text_iter_ends_word:
3110 * @iter: a #GtkTextIter
3112 * Determines whether @iter ends a natural-language word. Word breaks
3113 * are determined by Pango and should be correct for nearly any
3114 * language (if not, the correct fix would be to the Pango word break
3117 * Return value: %TRUE if @iter is at the end of a word
3120 gtk_text_iter_ends_word (const GtkTextIter *iter)
3122 return test_log_attrs (iter, is_word_end_func);
3126 * gtk_text_iter_inside_word:
3127 * @iter: a #GtkTextIter
3129 * Determines whether @iter is inside a natural-language word (as
3130 * opposed to say inside some whitespace). Word breaks are determined
3131 * by Pango and should be correct for nearly any language (if not, the
3132 * correct fix would be to the Pango word break algorithms).
3134 * Return value: %TRUE if @iter is inside a word
3137 gtk_text_iter_inside_word (const GtkTextIter *iter)
3139 return test_log_attrs (iter, inside_word_func);
3143 * gtk_text_iter_starts_sentence:
3144 * @iter: a #GtkTextIter
3146 * Determines whether @iter begins a sentence. Sentence boundaries are
3147 * determined by Pango and should be correct for nearly any language
3148 * (if not, the correct fix would be to the Pango text boundary
3151 * Return value: %TRUE if @iter is at the start of a sentence.
3154 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3156 return test_log_attrs (iter, is_sentence_start_func);
3160 * gtk_text_iter_ends_sentence:
3161 * @iter: a #GtkTextIter
3163 * Determines whether @iter ends a sentence. Sentence boundaries are
3164 * determined by Pango and should be correct for nearly any language
3165 * (if not, the correct fix would be to the Pango text boundary
3168 * Return value: %TRUE if @iter is at the end of a sentence.
3171 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3173 return test_log_attrs (iter, is_sentence_end_func);
3177 * gtk_text_iter_inside_sentence:
3178 * @iter: a #GtkTextIter
3180 * Determines whether @iter is inside a sentence (as opposed to in
3181 * between two sentences, e.g. after a period and before the first
3182 * letter of the next sentence). Sentence boundaries are determined
3183 * by Pango and should be correct for nearly any language (if not, the
3184 * correct fix would be to the Pango text boundary algorithms).
3186 * Return value: %TRUE if @iter is inside a sentence.
3189 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3191 return test_log_attrs (iter, inside_sentence_func);
3195 * gtk_text_iter_forward_sentence_end:
3196 * @iter: a #GtkTextIter
3198 * Moves forward to the next sentence end. (If @iter is at the end of
3199 * a sentence, moves to the next end of sentence.) Sentence
3200 * boundaries are determined by Pango and should be correct for nearly
3201 * any language (if not, the correct fix would be to the Pango text
3202 * boundary algorithms).
3204 * Return value: %TRUE if @iter moved and is not the end iterator
3207 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3209 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3213 * gtk_text_iter_backward_sentence_start:
3214 * @iter: a #GtkTextIter
3216 * Moves backward to the previous sentence start; if @iter is already at
3217 * the start of a sentence, moves backward to the next one. 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_backward_sentence_start (GtkTextIter *iter)
3227 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3230 /* FIXME a loop around a truly slow function means
3231 * a truly spectacularly slow function.
3234 * gtk_text_iter_forward_sentence_ends:
3235 * @iter: a #GtkTextIter
3236 * @count: number of sentences to move
3238 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3239 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3240 * negative, moves backward instead of forward.
3242 * Return value: %TRUE if @iter moved and is not the end iterator
3245 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3248 g_return_val_if_fail (iter != NULL, FALSE);
3254 return gtk_text_iter_backward_sentence_starts (iter, -count);
3256 if (!gtk_text_iter_forward_sentence_end (iter))
3262 if (!gtk_text_iter_forward_sentence_end (iter))
3267 return !gtk_text_iter_is_end (iter);
3271 * gtk_text_iter_backward_sentence_starts:
3272 * @iter: a #GtkTextIter
3273 * @count: number of sentences to move
3275 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3276 * or until it returns %FALSE. If @count is negative, moves forward
3277 * instead of backward.
3279 * Return value: %TRUE if @iter moved and is not the end iterator
3282 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3285 g_return_val_if_fail (iter != NULL, FALSE);
3288 return gtk_text_iter_forward_sentence_ends (iter, -count);
3290 if (!gtk_text_iter_backward_sentence_start (iter))
3296 if (!gtk_text_iter_backward_sentence_start (iter))
3301 return !gtk_text_iter_is_end (iter);
3305 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3310 gboolean already_moved_initially)
3312 if (!already_moved_initially)
3315 while (offset < (min_offset + len) &&
3316 !attrs[offset].is_cursor_position)
3319 *found_offset = offset;
3321 return offset < (min_offset + len);
3325 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3330 gboolean already_moved_initially)
3332 if (!already_moved_initially)
3335 while (offset > min_offset &&
3336 !attrs[offset].is_cursor_position)
3339 *found_offset = offset;
3341 return offset >= min_offset;
3345 is_cursor_pos_func (const PangoLogAttr *attrs,
3350 return attrs[offset].is_cursor_position;
3354 * gtk_text_iter_forward_cursor_position:
3355 * @iter: a #GtkTextIter
3357 * Moves @iter forward by a single cursor position. Cursor positions
3358 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3359 * surprisingly, there may not be a cursor position between all
3360 * characters. The most common example for European languages would be
3361 * a carriage return/newline sequence. For some Unicode characters,
3362 * the equivalent of say the letter "a" with an accent mark will be
3363 * represented as two characters, first the letter then a "combining
3364 * mark" that causes the accent to be rendered; so the cursor can't go
3365 * between those two characters. See also the #PangoLogAttr structure and
3366 * pango_break() function.
3368 * Return value: %TRUE if we moved and the new position is dereferenceable
3371 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3373 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3377 * gtk_text_iter_backward_cursor_position:
3378 * @iter: a #GtkTextIter
3380 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3382 * Return value: %TRUE if we moved and the new position is dereferenceable
3385 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3387 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3391 * gtk_text_iter_forward_cursor_positions:
3392 * @iter: a #GtkTextIter
3393 * @count: number of positions to move
3395 * Moves up to @count cursor positions. See
3396 * gtk_text_iter_forward_cursor_position() for details.
3398 * Return value: %TRUE if we moved and the new position is dereferenceable
3401 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3404 g_return_val_if_fail (iter != NULL, FALSE);
3406 FIX_OVERFLOWS (count);
3412 return gtk_text_iter_backward_cursor_positions (iter, -count);
3414 if (!gtk_text_iter_forward_cursor_position (iter))
3420 if (!gtk_text_iter_forward_cursor_position (iter))
3425 return !gtk_text_iter_is_end (iter);
3429 * gtk_text_iter_backward_cursor_positions:
3430 * @iter: a #GtkTextIter
3431 * @count: number of positions to move
3433 * Moves up to @count cursor positions. See
3434 * gtk_text_iter_forward_cursor_position() for details.
3436 * Return value: %TRUE if we moved and the new position is dereferenceable
3439 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3442 g_return_val_if_fail (iter != NULL, FALSE);
3444 FIX_OVERFLOWS (count);
3450 return gtk_text_iter_forward_cursor_positions (iter, -count);
3452 if (!gtk_text_iter_backward_cursor_position (iter))
3458 if (!gtk_text_iter_backward_cursor_position (iter))
3463 return !gtk_text_iter_is_end (iter);
3467 * gtk_text_iter_is_cursor_position:
3468 * @iter: a #GtkTextIter
3470 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3471 * pango_break() for details on what a cursor position is.
3473 * Return value: %TRUE if the cursor can be placed at @iter
3476 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3478 return test_log_attrs (iter, is_cursor_pos_func);
3482 * gtk_text_iter_set_line_offset:
3483 * @iter: a #GtkTextIter
3484 * @char_on_line: a character offset relative to the start of @iter's current line
3486 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3487 * (not byte) offset. The given character offset must be less than or
3488 * equal to the number of characters in the line; if equal, @iter
3489 * moves to the start of the next line. See
3490 * gtk_text_iter_set_line_index() if you have a byte index rather than
3491 * a character offset.
3495 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3498 GtkTextRealIter *real;
3501 g_return_if_fail (iter != NULL);
3503 real = gtk_text_iter_make_surreal (iter);
3508 check_invariants (iter);
3510 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3512 g_return_if_fail (char_on_line <= chars_in_line);
3514 if (char_on_line < chars_in_line)
3515 iter_set_from_char_offset (real, real->line, char_on_line);
3517 gtk_text_iter_forward_line (iter); /* set to start of next line */
3519 check_invariants (iter);
3523 * gtk_text_iter_set_line_index:
3524 * @iter: a #GtkTextIter
3525 * @byte_on_line: a byte index relative to the start of @iter's current line
3527 * Same as gtk_text_iter_set_line_offset(), but works with a
3528 * <emphasis>byte</emphasis> index. The given byte index must be at
3529 * the start of a character, it can't be in the middle of a UTF-8
3530 * encoded character.
3534 gtk_text_iter_set_line_index (GtkTextIter *iter,
3537 GtkTextRealIter *real;
3540 g_return_if_fail (iter != NULL);
3542 real = gtk_text_iter_make_surreal (iter);
3547 check_invariants (iter);
3549 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3551 g_return_if_fail (byte_on_line <= bytes_in_line);
3553 if (byte_on_line < bytes_in_line)
3554 iter_set_from_byte_offset (real, real->line, byte_on_line);
3556 gtk_text_iter_forward_line (iter);
3558 if (real->segment->type == >k_text_char_type &&
3559 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3560 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3561 "character; this will crash the text buffer. "
3562 "Byte indexes must refer to the start of a character.",
3563 G_STRLOC, byte_on_line);
3565 check_invariants (iter);
3570 * gtk_text_iter_set_visible_line_offset:
3571 * @iter: a #GtkTextIter
3572 * @char_on_line: a character offset
3574 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3575 * characters, i.e. text with a tag making it invisible is not
3576 * counted in the offset.
3579 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3582 gint chars_seen = 0;
3585 g_return_if_fail (iter != NULL);
3589 /* For now we use a ludicrously slow implementation */
3590 while (chars_seen < char_on_line)
3592 if (!_gtk_text_btree_char_is_invisible (&pos))
3595 if (!gtk_text_iter_forward_char (&pos))
3598 if (chars_seen == char_on_line)
3602 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3605 gtk_text_iter_forward_line (iter);
3609 bytes_in_char (GtkTextIter *iter)
3611 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3615 * gtk_text_iter_set_visible_line_index:
3616 * @iter: a #GtkTextIter
3617 * @byte_on_line: a byte index
3619 * Like gtk_text_iter_set_line_index(), but the index is in visible
3620 * bytes, i.e. text with a tag making it invisible is not counted
3624 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3627 gint bytes_seen = 0;
3630 g_return_if_fail (iter != NULL);
3634 /* For now we use a ludicrously slow implementation */
3635 while (bytes_seen < byte_on_line)
3637 if (!_gtk_text_btree_char_is_invisible (&pos))
3638 bytes_seen += bytes_in_char (&pos);
3640 if (!gtk_text_iter_forward_char (&pos))
3643 if (bytes_seen >= byte_on_line)
3647 if (bytes_seen > byte_on_line)
3648 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3649 "character; this will crash the text buffer. "
3650 "Byte indexes must refer to the start of a character.",
3651 G_STRLOC, byte_on_line);
3653 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3656 gtk_text_iter_forward_line (iter);
3660 * gtk_text_iter_set_line:
3661 * @iter: a #GtkTextIter
3662 * @line_number: line number (counted from 0)
3664 * Moves iterator @iter to the start of the line @line_number. If
3665 * @line_number is negative or larger than the number of lines in the
3666 * buffer, moves @iter to the start of the last line in the buffer.
3670 gtk_text_iter_set_line (GtkTextIter *iter,
3675 GtkTextRealIter *real;
3677 g_return_if_fail (iter != NULL);
3679 real = gtk_text_iter_make_surreal (iter);
3684 check_invariants (iter);
3686 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3688 iter_set_from_char_offset (real, line, 0);
3690 /* We might as well cache this, since we know it. */
3691 real->cached_line_number = real_line;
3693 check_invariants (iter);
3697 * gtk_text_iter_set_offset:
3698 * @iter: a #GtkTextIter
3699 * @char_offset: a character number
3701 * Sets @iter to point to @char_offset. @char_offset counts from the start
3702 * of the entire text buffer, starting with 0.
3705 gtk_text_iter_set_offset (GtkTextIter *iter,
3709 GtkTextRealIter *real;
3711 gint real_char_index;
3713 g_return_if_fail (iter != NULL);
3715 real = gtk_text_iter_make_surreal (iter);
3720 check_invariants (iter);
3722 if (real->cached_char_index >= 0 &&
3723 real->cached_char_index == char_offset)
3726 line = _gtk_text_btree_get_line_at_char (real->tree,
3731 iter_set_from_char_offset (real, line, real_char_index - line_start);
3733 /* Go ahead and cache this since we have it. */
3734 real->cached_char_index = real_char_index;
3736 check_invariants (iter);
3740 * gtk_text_iter_forward_to_end:
3741 * @iter: a #GtkTextIter
3743 * Moves @iter forward to the "end iterator," which points one past the last
3744 * valid character in the buffer. gtk_text_iter_get_char() called on the
3745 * end iterator returns 0, which is convenient for writing loops.
3748 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3750 GtkTextBuffer *buffer;
3751 GtkTextRealIter *real;
3753 g_return_if_fail (iter != NULL);
3755 real = gtk_text_iter_make_surreal (iter);
3760 buffer = _gtk_text_btree_get_buffer (real->tree);
3762 gtk_text_buffer_get_end_iter (buffer, iter);
3765 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3766 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3767 * If all else fails we could cache the para delimiter pos in the iter.
3768 * I think forward_to_line_end() actually gets called fairly often.
3771 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3776 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3777 _gtk_text_iter_get_btree (&end)))
3779 gtk_text_iter_forward_to_end (&end);
3783 /* if we aren't on the last line, go forward to start of next line, then scan
3784 * back for the delimiters on the previous line
3786 gtk_text_iter_forward_line (&end);
3787 gtk_text_iter_backward_char (&end);
3788 while (!gtk_text_iter_ends_line (&end))
3789 gtk_text_iter_backward_char (&end);
3792 return gtk_text_iter_get_line_offset (&end);
3796 * gtk_text_iter_forward_to_line_end:
3797 * @iter: a #GtkTextIter
3799 * Moves the iterator to point to the paragraph delimiter characters,
3800 * which will be either a newline, a carriage return, a carriage
3801 * return/newline in sequence, or the Unicode paragraph separator
3802 * character. If the iterator is already at the paragraph delimiter
3803 * characters, moves to the paragraph delimiter characters for the
3804 * next line. If @iter is on the last line in the buffer, which does
3805 * not end in paragraph delimiters, moves to the end iterator (end of
3806 * the last line), and returns %FALSE.
3808 * Return value: %TRUE if we moved and the new location is not the end iterator
3811 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3813 gint current_offset;
3817 g_return_val_if_fail (iter != NULL, FALSE);
3819 current_offset = gtk_text_iter_get_line_offset (iter);
3820 new_offset = find_paragraph_delimiter_for_line (iter);
3822 if (current_offset < new_offset)
3824 /* Move to end of this line. */
3825 gtk_text_iter_set_line_offset (iter, new_offset);
3826 return !gtk_text_iter_is_end (iter);
3830 /* Move to end of next line. */
3831 if (gtk_text_iter_forward_line (iter))
3833 /* We don't want to move past all
3836 if (!gtk_text_iter_ends_line (iter))
3837 gtk_text_iter_forward_to_line_end (iter);
3838 return !gtk_text_iter_is_end (iter);
3846 * gtk_text_iter_forward_to_tag_toggle:
3847 * @iter: a #GtkTextIter
3848 * @tag: a #GtkTextTag, or %NULL
3850 * Moves forward to the next toggle (on or off) of the
3851 * #GtkTextTag @tag, or to the next toggle of any tag if
3852 * @tag is %NULL. If no matching tag toggles are found,
3853 * returns %FALSE, otherwise %TRUE. Does not return toggles
3854 * located at @iter, only toggles after @iter. Sets @iter to
3855 * the location of the toggle, or to the end of the buffer
3856 * if no toggle is found.
3858 * Return value: whether we found a tag toggle after @iter
3861 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3864 GtkTextLine *next_line;
3865 GtkTextLine *current_line;
3866 GtkTextRealIter *real;
3868 g_return_val_if_fail (iter != NULL, FALSE);
3870 real = gtk_text_iter_make_real (iter);
3875 check_invariants (iter);
3877 current_line = real->line;
3878 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3881 while (_gtk_text_iter_forward_indexable_segment (iter))
3883 /* If we went forward to a line that couldn't contain a toggle
3884 for the tag, then skip forward to a line that could contain
3885 it. This potentially skips huge hunks of the tree, so we
3886 aren't a purely linear search. */
3887 if (real->line != current_line)
3889 if (next_line == NULL)
3891 /* End of search. Set to end of buffer. */
3892 _gtk_text_btree_get_end_iter (real->tree, iter);
3896 if (real->line != next_line)
3897 iter_set_from_byte_offset (real, next_line, 0);
3899 current_line = real->line;
3900 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3905 if (gtk_text_iter_toggles_tag (iter, tag))
3907 /* If there's a toggle here, it isn't indexable so
3908 any_segment can't be the indexable segment. */
3909 g_assert (real->any_segment != real->segment);
3914 /* Check end iterator for tags */
3915 if (gtk_text_iter_toggles_tag (iter, tag))
3917 /* If there's a toggle here, it isn't indexable so
3918 any_segment can't be the indexable segment. */
3919 g_assert (real->any_segment != real->segment);
3923 /* Reached end of buffer */
3928 * gtk_text_iter_backward_to_tag_toggle:
3929 * @iter: a #GtkTextIter
3930 * @tag: a #GtkTextTag, or %NULL
3932 * Moves backward to the next toggle (on or off) of the
3933 * #GtkTextTag @tag, or to the next toggle of any tag if
3934 * @tag is %NULL. If no matching tag toggles are found,
3935 * returns %FALSE, otherwise %TRUE. Does not return toggles
3936 * located at @iter, only toggles before @iter. Sets @iter
3937 * to the location of the toggle, or the start of the buffer
3938 * if no toggle is found.
3940 * Return value: whether we found a tag toggle before @iter
3943 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3946 GtkTextLine *prev_line;
3947 GtkTextLine *current_line;
3948 GtkTextRealIter *real;
3950 g_return_val_if_fail (iter != NULL, FALSE);
3952 real = gtk_text_iter_make_real (iter);
3957 check_invariants (iter);
3959 current_line = real->line;
3960 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3964 /* If we're at segment start, go to the previous segment;
3965 * if mid-segment, snap to start of current segment.
3967 if (is_segment_start (real))
3969 if (!_gtk_text_iter_backward_indexable_segment (iter))
3974 ensure_char_offsets (real);
3976 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3982 /* If we went backward to a line that couldn't contain a toggle
3983 * for the tag, then skip backward further to a line that
3984 * could contain it. This potentially skips huge hunks of the
3985 * tree, so we aren't a purely linear search.
3987 if (real->line != current_line)
3989 if (prev_line == NULL)
3991 /* End of search. Set to start of buffer. */
3992 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3996 if (real->line != prev_line)
3998 /* Set to last segment in prev_line (could do this
4001 iter_set_from_byte_offset (real, prev_line, 0);
4003 while (!at_last_indexable_segment (real))
4004 _gtk_text_iter_forward_indexable_segment (iter);
4007 current_line = real->line;
4008 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4013 if (gtk_text_iter_toggles_tag (iter, tag))
4015 /* If there's a toggle here, it isn't indexable so
4016 * any_segment can't be the indexable segment.
4018 g_assert (real->any_segment != real->segment);
4022 while (_gtk_text_iter_backward_indexable_segment (iter));
4024 /* Reached front of buffer */
4029 matches_pred (GtkTextIter *iter,
4030 GtkTextCharPredicate pred,
4035 ch = gtk_text_iter_get_char (iter);
4037 return (*pred) (ch, user_data);
4041 * gtk_text_iter_forward_find_char:
4042 * @iter: a #GtkTextIter
4043 * @pred: a function to be called on each character
4044 * @user_data: user data for @pred
4045 * @limit: search limit, or %NULL for none
4047 * Advances @iter, calling @pred on each character. If
4048 * @pred returns %TRUE, returns %TRUE and stops scanning.
4049 * If @pred never returns %TRUE, @iter is set to @limit if
4050 * @limit is non-%NULL, otherwise to the end iterator.
4052 * Return value: whether a match was found
4055 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4056 GtkTextCharPredicate pred,
4058 const GtkTextIter *limit)
4060 g_return_val_if_fail (iter != NULL, FALSE);
4061 g_return_val_if_fail (pred != NULL, FALSE);
4064 gtk_text_iter_compare (iter, limit) >= 0)
4067 while ((limit == NULL ||
4068 !gtk_text_iter_equal (limit, iter)) &&
4069 gtk_text_iter_forward_char (iter))
4071 if (matches_pred (iter, pred, user_data))
4079 * gtk_text_iter_backward_find_char:
4080 * @iter: a #GtkTextIter
4081 * @pred: function to be called on each character
4082 * @user_data: user data for @pred
4083 * @limit: search limit, or %NULL for none
4085 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4087 * Return value: whether a match was found
4090 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4091 GtkTextCharPredicate pred,
4093 const GtkTextIter *limit)
4095 g_return_val_if_fail (iter != NULL, FALSE);
4096 g_return_val_if_fail (pred != NULL, FALSE);
4099 gtk_text_iter_compare (iter, limit) <= 0)
4102 while ((limit == NULL ||
4103 !gtk_text_iter_equal (limit, iter)) &&
4104 gtk_text_iter_backward_char (iter))
4106 if (matches_pred (iter, pred, user_data))
4114 forward_chars_with_skipping (GtkTextIter *iter,
4116 gboolean skip_invisible,
4117 gboolean skip_nontext)
4122 g_return_if_fail (count >= 0);
4128 gboolean ignored = FALSE;
4131 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4136 _gtk_text_btree_char_is_invisible (iter))
4139 gtk_text_iter_forward_char (iter);
4147 lines_match (const GtkTextIter *start,
4148 const gchar **lines,
4149 gboolean visible_only,
4151 GtkTextIter *match_start,
4152 GtkTextIter *match_end)
4159 if (*lines == NULL || **lines == '\0')
4162 *match_start = *start;
4165 *match_end = *start;
4170 gtk_text_iter_forward_line (&next);
4172 /* No more text in buffer, but *lines is nonempty */
4173 if (gtk_text_iter_equal (start, &next))
4181 line_text = gtk_text_iter_get_visible_slice (start, &next);
4183 line_text = gtk_text_iter_get_slice (start, &next);
4188 line_text = gtk_text_iter_get_visible_text (start, &next);
4190 line_text = gtk_text_iter_get_text (start, &next);
4193 if (match_start) /* if this is the first line we're matching */
4194 found = strstr (line_text, *lines);
4197 /* If it's not the first line, we have to match from the
4198 * start of the line.
4200 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4212 /* Get offset to start of search string */
4213 offset = g_utf8_strlen (line_text, found - line_text);
4217 /* If match start needs to be returned, set it to the
4218 * start of the search string.
4222 *match_start = next;
4224 forward_chars_with_skipping (match_start, offset,
4225 visible_only, !slice);
4228 /* Go to end of search string */
4229 offset += g_utf8_strlen (*lines, -1);
4231 forward_chars_with_skipping (&next, offset,
4232 visible_only, !slice);
4241 /* pass NULL for match_start, since we don't need to find the
4244 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4247 /* strsplit () that retains the delimiter as part of the string. */
4249 strbreakup (const char *string,
4250 const char *delimiter,
4253 GSList *string_list = NULL, *slist;
4254 gchar **str_array, *s;
4257 g_return_val_if_fail (string != NULL, NULL);
4258 g_return_val_if_fail (delimiter != NULL, NULL);
4261 max_tokens = G_MAXINT;
4263 s = strstr (string, delimiter);
4266 guint delimiter_len = strlen (delimiter);
4273 len = s - string + delimiter_len;
4274 new_string = g_new (gchar, len + 1);
4275 strncpy (new_string, string, len);
4276 new_string[len] = 0;
4277 string_list = g_slist_prepend (string_list, new_string);
4279 string = s + delimiter_len;
4280 s = strstr (string, delimiter);
4282 while (--max_tokens && s);
4287 string_list = g_slist_prepend (string_list, g_strdup (string));
4290 str_array = g_new (gchar*, n);
4294 str_array[i--] = NULL;
4295 for (slist = string_list; slist; slist = slist->next)
4296 str_array[i--] = slist->data;
4298 g_slist_free (string_list);
4304 * gtk_text_iter_forward_search:
4305 * @iter: start of search
4306 * @str: a search string
4307 * @flags: flags affecting how the search is done
4308 * @match_start: return location for start of match, or %NULL
4309 * @match_end: return location for end of match, or %NULL
4310 * @limit: bound for the search, or %NULL for the end of the buffer
4312 * Searches forward for @str. Any match is returned as the range
4313 * @match_start, @match_end. The search will not continue past
4314 * @limit. Note that a search is a linear or O(n) operation, so you
4315 * may wish to use @limit to avoid locking up your UI on large
4318 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4319 * have invisible text interspersed in @str. i.e. @str will be a
4320 * possibly-noncontiguous subsequence of the matched range. similarly,
4321 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4322 * pixbufs or child widgets mixed inside the matched range. If these
4323 * flags are not given, the match must be exact; the special 0xFFFC
4324 * character in @str will match embedded pixbufs or child widgets.
4326 * Return value: whether a match was found
4329 gtk_text_iter_forward_search (const GtkTextIter *iter,
4331 GtkTextSearchFlags flags,
4332 GtkTextIter *match_start,
4333 GtkTextIter *match_end,
4334 const GtkTextIter *limit)
4336 gchar **lines = NULL;
4338 gboolean retval = FALSE;
4340 gboolean visible_only;
4343 g_return_val_if_fail (iter != NULL, FALSE);
4344 g_return_val_if_fail (str != NULL, FALSE);
4347 gtk_text_iter_compare (iter, limit) >= 0)
4352 /* If we can move one char, return the empty string there */
4355 if (gtk_text_iter_forward_char (&match))
4358 gtk_text_iter_equal (&match, limit))
4362 *match_start = match;
4371 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4372 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4374 /* locate all lines */
4376 lines = strbreakup (str, "\n", -1);
4382 /* This loop has an inefficient worst-case, where
4383 * gtk_text_iter_get_text () is called repeatedly on
4389 gtk_text_iter_compare (&search, limit) >= 0)
4392 if (lines_match (&search, (const gchar**)lines,
4393 visible_only, slice, &match, &end))
4395 if (limit == NULL ||
4397 gtk_text_iter_compare (&end, limit) < 0))
4402 *match_start = match;
4411 while (gtk_text_iter_forward_line (&search));
4413 g_strfreev ((gchar**)lines);
4419 vectors_equal_ignoring_trailing (gchar **vec1,
4422 /* Ignores trailing chars in vec2's last line */
4431 if (strcmp (*i1, *i2) != 0)
4433 if (*(i2 + 1) == NULL) /* if this is the last line */
4435 gint len1 = strlen (*i1);
4436 gint len2 = strlen (*i2);
4439 strncmp (*i1, *i2, len1) == 0)
4441 /* We matched ignoring the trailing stuff in vec2 */
4466 typedef struct _LinesWindow LinesWindow;
4472 GtkTextIter first_line_start;
4473 GtkTextIter first_line_end;
4475 gboolean visible_only;
4479 lines_window_init (LinesWindow *win,
4480 const GtkTextIter *start)
4483 GtkTextIter line_start;
4484 GtkTextIter line_end;
4486 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4489 if (gtk_text_iter_is_start (start) ||
4490 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4492 /* Already at the end, or not enough lines to match */
4493 win->lines = g_new0 (gchar*, 1);
4498 line_start = *start;
4501 /* Move to start iter to start of line */
4502 gtk_text_iter_set_line_offset (&line_start, 0);
4504 if (gtk_text_iter_equal (&line_start, &line_end))
4506 /* we were already at the start; so go back one line */
4507 gtk_text_iter_backward_line (&line_start);
4510 win->first_line_start = line_start;
4511 win->first_line_end = line_end;
4513 win->lines = g_new0 (gchar*, win->n_lines + 1);
4515 i = win->n_lines - 1;
4522 if (win->visible_only)
4523 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4525 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4529 if (win->visible_only)
4530 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4532 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4535 win->lines[i] = line_text;
4537 line_end = line_start;
4538 gtk_text_iter_backward_line (&line_start);
4545 lines_window_back (LinesWindow *win)
4547 GtkTextIter new_start;
4550 new_start = win->first_line_start;
4552 if (!gtk_text_iter_backward_line (&new_start))
4556 win->first_line_start = new_start;
4557 win->first_line_end = new_start;
4559 gtk_text_iter_forward_line (&win->first_line_end);
4564 if (win->visible_only)
4565 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4566 &win->first_line_end);
4568 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4569 &win->first_line_end);
4573 if (win->visible_only)
4574 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4575 &win->first_line_end);
4577 line_text = gtk_text_iter_get_text (&win->first_line_start,
4578 &win->first_line_end);
4581 /* Move lines to make room for first line. */
4582 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4584 *win->lines = line_text;
4586 /* Free old last line and NULL-terminate */
4587 g_free (win->lines[win->n_lines]);
4588 win->lines[win->n_lines] = NULL;
4594 lines_window_free (LinesWindow *win)
4596 g_strfreev (win->lines);
4600 my_strrstr (const gchar *haystack,
4601 const gchar *needle)
4603 /* FIXME GLib should have a nice implementation in it, this
4607 gint haystack_len = strlen (haystack);
4608 gint needle_len = strlen (needle);
4609 const gchar *needle_end = needle + needle_len;
4610 const gchar *haystack_rend = haystack - 1;
4611 const gchar *needle_rend = needle - 1;
4614 p = haystack + haystack_len;
4615 while (p != haystack)
4617 const gchar *n = needle_end - 1;
4618 const gchar *s = p - 1;
4619 while (s != haystack_rend &&
4627 if (n == needle_rend)
4637 * gtk_text_iter_backward_search:
4638 * @iter: a #GtkTextIter where the search begins
4639 * @str: search string
4640 * @flags: bitmask of flags affecting the search
4641 * @match_start: return location for start of match, or %NULL
4642 * @match_end: return location for end of match, or %NULL
4643 * @limit: location of last possible @match_start, or %NULL for start of buffer
4645 * Same as gtk_text_iter_forward_search(), but moves backward.
4647 * Return value: whether a match was found
4650 gtk_text_iter_backward_search (const GtkTextIter *iter,
4652 GtkTextSearchFlags flags,
4653 GtkTextIter *match_start,
4654 GtkTextIter *match_end,
4655 const GtkTextIter *limit)
4657 gchar **lines = NULL;
4661 gboolean retval = FALSE;
4662 gboolean visible_only;
4665 g_return_val_if_fail (iter != NULL, FALSE);
4666 g_return_val_if_fail (str != NULL, FALSE);
4669 gtk_text_iter_compare (limit, iter) > 0)
4674 /* If we can move one char, return the empty string there */
4675 GtkTextIter match = *iter;
4677 if (limit && gtk_text_iter_equal (limit, &match))
4680 if (gtk_text_iter_backward_char (&match))
4683 *match_start = match;
4692 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4693 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4695 /* locate all lines */
4697 lines = strbreakup (str, "\n", -1);
4707 win.n_lines = n_lines;
4709 win.visible_only = visible_only;
4711 lines_window_init (&win, iter);
4713 if (*win.lines == NULL)
4718 gchar *first_line_match;
4721 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4723 /* We're now before the search limit, abort. */
4727 /* If there are multiple lines, the first line will
4728 * end in '\n', so this will only match at the
4729 * end of the first line, which is correct.
4731 first_line_match = my_strrstr (*win.lines, *lines);
4733 if (first_line_match &&
4734 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4739 GtkTextIter start_tmp;
4741 /* Offset to start of search string */
4742 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4744 next = win.first_line_start;
4746 forward_chars_with_skipping (&start_tmp, offset,
4747 visible_only, !slice);
4750 gtk_text_iter_compare (limit, &start_tmp) > 0)
4751 goto out; /* match was bogus */
4754 *match_start = start_tmp;
4756 /* Go to end of search string */
4760 offset += g_utf8_strlen (*l, -1);
4764 forward_chars_with_skipping (&next, offset,
4765 visible_only, !slice);
4774 while (lines_window_back (&win));
4777 lines_window_free (&win);
4788 * gtk_text_iter_equal:
4789 * @lhs: a #GtkTextIter
4790 * @rhs: another #GtkTextIter
4792 * Tests whether two iterators are equal, using the fastest possible
4793 * mechanism. This function is very fast; you can expect it to perform
4794 * better than e.g. getting the character offset for each iterator and
4795 * comparing the offsets yourself. Also, it's a bit faster than
4796 * gtk_text_iter_compare().
4798 * Return value: %TRUE if the iterators point to the same place in the buffer
4801 gtk_text_iter_equal (const GtkTextIter *lhs,
4802 const GtkTextIter *rhs)
4804 GtkTextRealIter *real_lhs;
4805 GtkTextRealIter *real_rhs;
4807 real_lhs = (GtkTextRealIter*)lhs;
4808 real_rhs = (GtkTextRealIter*)rhs;
4810 check_invariants (lhs);
4811 check_invariants (rhs);
4813 if (real_lhs->line != real_rhs->line)
4815 else if (real_lhs->line_byte_offset >= 0 &&
4816 real_rhs->line_byte_offset >= 0)
4817 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4820 /* the ensure_char_offsets () calls do nothing if the char offsets
4821 are already up-to-date. */
4822 ensure_char_offsets (real_lhs);
4823 ensure_char_offsets (real_rhs);
4824 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4829 * gtk_text_iter_compare:
4830 * @lhs: a #GtkTextIter
4831 * @rhs: another #GtkTextIter
4833 * A qsort()-style function that returns negative if @lhs is less than
4834 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4835 * Ordering is in character offset order, i.e. the first character in the buffer
4836 * is less than the second character in the buffer.
4838 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4841 gtk_text_iter_compare (const GtkTextIter *lhs,
4842 const GtkTextIter *rhs)
4844 GtkTextRealIter *real_lhs;
4845 GtkTextRealIter *real_rhs;
4847 real_lhs = gtk_text_iter_make_surreal (lhs);
4848 real_rhs = gtk_text_iter_make_surreal (rhs);
4850 if (real_lhs == NULL ||
4852 return -1; /* why not */
4854 check_invariants (lhs);
4855 check_invariants (rhs);
4857 if (real_lhs->line == real_rhs->line)
4859 gint left_index, right_index;
4861 if (real_lhs->line_byte_offset >= 0 &&
4862 real_rhs->line_byte_offset >= 0)
4864 left_index = real_lhs->line_byte_offset;
4865 right_index = real_rhs->line_byte_offset;
4869 /* the ensure_char_offsets () calls do nothing if
4870 the offsets are already up-to-date. */
4871 ensure_char_offsets (real_lhs);
4872 ensure_char_offsets (real_rhs);
4873 left_index = real_lhs->line_char_offset;
4874 right_index = real_rhs->line_char_offset;
4877 if (left_index < right_index)
4879 else if (left_index > right_index)
4888 line1 = gtk_text_iter_get_line (lhs);
4889 line2 = gtk_text_iter_get_line (rhs);
4892 else if (line1 > line2)
4900 * gtk_text_iter_in_range:
4901 * @iter: a #GtkTextIter
4902 * @start: start of range
4903 * @end: end of range
4905 * Checks whether @iter falls in the range [@start, @end).
4906 * @start and @end must be in ascending order.
4908 * Return value: %TRUE if @iter is in the range
4911 gtk_text_iter_in_range (const GtkTextIter *iter,
4912 const GtkTextIter *start,
4913 const GtkTextIter *end)
4915 g_return_val_if_fail (iter != NULL, FALSE);
4916 g_return_val_if_fail (start != NULL, FALSE);
4917 g_return_val_if_fail (end != NULL, FALSE);
4918 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4920 return gtk_text_iter_compare (iter, start) >= 0 &&
4921 gtk_text_iter_compare (iter, end) < 0;
4925 * gtk_text_iter_order:
4926 * @first: a #GtkTextIter
4927 * @second: another #GtkTextIter
4929 * Swaps the value of @first and @second if @second comes before
4930 * @first in the buffer. That is, ensures that @first and @second are
4931 * in sequence. Most text buffer functions that take a range call this
4932 * automatically on your behalf, so there's no real reason to call it yourself
4933 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4934 * that expect a pre-sorted range.
4938 gtk_text_iter_order (GtkTextIter *first,
4939 GtkTextIter *second)
4941 g_return_if_fail (first != NULL);
4942 g_return_if_fail (second != NULL);
4944 if (gtk_text_iter_compare (first, second) > 0)
4955 * Init iterators from the BTree
4959 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4963 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4964 gint real_char_index;
4968 g_return_if_fail (iter != NULL);
4969 g_return_if_fail (tree != NULL);
4971 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4972 &line_start, &real_char_index);
4974 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4976 real->cached_char_index = real_char_index;
4978 check_invariants (iter);
4982 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4987 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4991 g_return_if_fail (iter != NULL);
4992 g_return_if_fail (tree != NULL);
4994 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
4996 iter_init_from_char_offset (iter, tree, line, char_on_line);
4998 /* We might as well cache this, since we know it. */
4999 real->cached_line_number = real_line;
5001 check_invariants (iter);
5005 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5010 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5014 g_return_if_fail (iter != NULL);
5015 g_return_if_fail (tree != NULL);
5017 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5019 iter_init_from_byte_offset (iter, tree, line, byte_index);
5021 /* We might as well cache this, since we know it. */
5022 real->cached_line_number = real_line;
5024 check_invariants (iter);
5028 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5033 g_return_if_fail (iter != NULL);
5034 g_return_if_fail (tree != NULL);
5035 g_return_if_fail (line != NULL);
5037 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5039 check_invariants (iter);
5043 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5049 g_return_val_if_fail (iter != NULL, FALSE);
5050 g_return_val_if_fail (tree != NULL, FALSE);
5052 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5056 /* Set iter to last in tree */
5057 _gtk_text_btree_get_end_iter (tree, iter);
5058 check_invariants (iter);
5063 iter_init_from_byte_offset (iter, tree, line, 0);
5064 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5065 check_invariants (iter);
5071 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5075 g_return_val_if_fail (iter != NULL, FALSE);
5076 g_return_val_if_fail (tree != NULL, FALSE);
5078 _gtk_text_btree_get_end_iter (tree, iter);
5079 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5080 check_invariants (iter);
5086 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5088 const gchar *mark_name)
5092 g_return_val_if_fail (iter != NULL, FALSE);
5093 g_return_val_if_fail (tree != NULL, FALSE);
5095 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5101 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5102 check_invariants (iter);
5108 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5112 GtkTextLineSegment *seg;
5114 g_return_if_fail (iter != NULL);
5115 g_return_if_fail (tree != NULL);
5116 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5118 seg = mark->segment;
5120 iter_init_from_segment (iter, tree,
5121 seg->body.mark.line, seg);
5122 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5123 check_invariants (iter);
5127 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5129 GtkTextChildAnchor *anchor)
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_CHILD_ANCHOR (anchor));
5137 seg = anchor->segment;
5139 g_assert (seg->body.child.line != NULL);
5141 iter_init_from_segment (iter, tree,
5142 seg->body.child.line, seg);
5143 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5144 check_invariants (iter);
5148 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5151 g_return_if_fail (iter != NULL);
5152 g_return_if_fail (tree != NULL);
5154 _gtk_text_btree_get_iter_at_char (tree,
5156 _gtk_text_btree_char_count (tree));
5157 check_invariants (iter);
5161 _gtk_text_iter_check (const GtkTextIter *iter)
5163 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5164 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5165 GtkTextLineSegment *byte_segment = NULL;
5166 GtkTextLineSegment *byte_any_segment = NULL;
5167 GtkTextLineSegment *char_segment = NULL;
5168 GtkTextLineSegment *char_any_segment = NULL;
5169 gboolean segments_updated;
5171 /* This function checks our class invariants for the Iter class. */
5173 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5175 if (real->chars_changed_stamp !=
5176 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5177 g_error ("iterator check failed: invalid iterator");
5179 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5180 g_error ("iterator check failed: both char and byte offsets are invalid");
5182 segments_updated = (real->segments_changed_stamp ==
5183 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5186 printf ("checking iter, segments %s updated, byte %d char %d\n",
5187 segments_updated ? "are" : "aren't",
5188 real->line_byte_offset,
5189 real->line_char_offset);
5192 if (segments_updated)
5194 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5195 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5197 if (real->segment->char_count == 0)
5198 g_error ("iterator check failed: segment is not indexable.");
5200 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5201 g_error ("segment char offset is not properly up-to-date");
5203 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5204 g_error ("segment byte offset is not properly up-to-date");
5206 if (real->segment_byte_offset >= 0 &&
5207 real->segment_byte_offset >= real->segment->byte_count)
5208 g_error ("segment byte offset is too large.");
5210 if (real->segment_char_offset >= 0 &&
5211 real->segment_char_offset >= real->segment->char_count)
5212 g_error ("segment char offset is too large.");
5215 if (real->line_byte_offset >= 0)
5217 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5218 &byte_segment, &byte_any_segment,
5219 &seg_byte_offset, &line_byte_offset);
5221 if (line_byte_offset != real->line_byte_offset)
5222 g_error ("wrong byte offset was stored in iterator");
5224 if (segments_updated)
5226 if (real->segment != byte_segment)
5227 g_error ("wrong segment was stored in iterator");
5229 if (real->any_segment != byte_any_segment)
5230 g_error ("wrong any_segment was stored in iterator");
5232 if (seg_byte_offset != real->segment_byte_offset)
5233 g_error ("wrong segment byte offset was stored in iterator");
5235 if (byte_segment->type == >k_text_char_type)
5238 p = byte_segment->body.chars + seg_byte_offset;
5240 if (!gtk_text_byte_begins_utf8_char (p))
5241 g_error ("broken iterator byte index pointed into the middle of a character");
5246 if (real->line_char_offset >= 0)
5248 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5249 &char_segment, &char_any_segment,
5250 &seg_char_offset, &line_char_offset);
5252 if (line_char_offset != real->line_char_offset)
5253 g_error ("wrong char offset was stored in iterator");
5255 if (segments_updated)
5257 if (real->segment != char_segment)
5258 g_error ("wrong segment was stored in iterator");
5260 if (real->any_segment != char_any_segment)
5261 g_error ("wrong any_segment was stored in iterator");
5263 if (seg_char_offset != real->segment_char_offset)
5264 g_error ("wrong segment char offset was stored in iterator");
5266 if (char_segment->type == >k_text_char_type)
5269 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5272 /* hmm, not likely to happen eh */
5273 if (!gtk_text_byte_begins_utf8_char (p))
5274 g_error ("broken iterator char offset pointed into the middle of a character");
5279 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5281 if (byte_segment != char_segment)
5282 g_error ("char and byte offsets did not point to the same segment");
5284 if (byte_any_segment != char_any_segment)
5285 g_error ("char and byte offsets did not point to the same any segment");
5287 /* Make sure the segment offsets are equivalent, if it's a char
5289 if (char_segment->type == >k_text_char_type)
5291 gint byte_offset = 0;
5292 gint char_offset = 0;
5293 while (char_offset < seg_char_offset)
5295 const char * start = char_segment->body.chars + byte_offset;
5296 byte_offset += g_utf8_next_char (start) - start;
5300 if (byte_offset != seg_byte_offset)
5301 g_error ("byte offset did not correspond to char offset");
5304 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5306 if (char_offset != seg_char_offset)
5307 g_error ("char offset did not correspond to byte offset");
5309 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5310 g_error ("byte index for iterator does not index the start of a character");
5314 if (real->cached_line_number >= 0)
5318 should_be = _gtk_text_line_get_number (real->line);
5319 if (real->cached_line_number != should_be)
5320 g_error ("wrong line number was cached");
5323 if (real->cached_char_index >= 0)
5325 if (real->line_char_offset >= 0) /* only way we can check it
5326 efficiently, not a real
5331 char_index = _gtk_text_line_char_index (real->line);
5332 char_index += real->line_char_offset;
5334 if (real->cached_char_index != char_index)
5335 g_error ("wrong char index was cached");
5339 if (_gtk_text_line_is_last (real->line, real->tree))
5340 g_error ("Iterator was on last line (past the end iterator)");