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 #include "gtktextiter.h"
28 #include "gtktextbtree.h"
29 #include "gtktextiterprivate.h"
34 typedef struct _GtkTextRealIter GtkTextRealIter;
36 struct _GtkTextRealIter
38 /* Always-valid information */
41 /* At least one of these is always valid;
42 if invalid, they are -1.
44 If the line byte offset is valid, so is the segment byte offset;
45 and ditto for char offsets. */
46 gint line_byte_offset;
47 gint line_char_offset;
48 /* These two are valid if >= 0 */
49 gint cached_char_index;
50 gint cached_line_number;
51 /* Stamps to detect the buffer changing under us */
52 gint chars_changed_stamp;
53 gint segments_changed_stamp;
54 /* Valid if the segments_changed_stamp is up-to-date */
55 GtkTextLineSegment *segment; /* indexable segment we index */
56 GtkTextLineSegment *any_segment; /* first segment in our location,
57 maybe same as "segment" */
58 /* One of these will always be valid if segments_changed_stamp is
59 up-to-date. If invalid, they are -1.
61 If the line byte offset is valid, so is the segment byte offset;
62 and ditto for char offsets. */
63 gint segment_byte_offset;
64 gint segment_char_offset;
67 /* These "set" functions should not assume any fields
68 other than the char stamp and the tree are valid.
71 iter_set_common (GtkTextRealIter *iter,
74 /* Update segments stamp */
75 iter->segments_changed_stamp =
76 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
80 iter->line_byte_offset = -1;
81 iter->line_char_offset = -1;
82 iter->segment_byte_offset = -1;
83 iter->segment_char_offset = -1;
84 iter->cached_char_index = -1;
85 iter->cached_line_number = -1;
89 iter_set_from_byte_offset (GtkTextRealIter *iter,
93 iter_set_common (iter, line);
95 _gtk_text_line_byte_locate (iter->line,
99 &iter->segment_byte_offset,
100 &iter->line_byte_offset);
104 iter_set_from_char_offset (GtkTextRealIter *iter,
108 iter_set_common (iter, line);
110 _gtk_text_line_char_locate (iter->line,
114 &iter->segment_char_offset,
115 &iter->line_char_offset);
119 iter_set_from_segment (GtkTextRealIter *iter,
121 GtkTextLineSegment *segment)
123 GtkTextLineSegment *seg;
126 /* This could theoretically be optimized by computing all the iter
127 fields in this same loop, but I'm skipping it for now. */
129 seg = line->segments;
130 while (seg != segment)
132 byte_offset += seg->byte_count;
136 iter_set_from_byte_offset (iter, line, byte_offset);
139 /* This function ensures that the segment-dependent information is
140 truly computed lazily; often we don't need to do the full make_real
141 work. This ensures the btree and line are valid, but doesn't
142 update the segments. */
143 static GtkTextRealIter*
144 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
146 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
148 if (iter->chars_changed_stamp !=
149 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
151 g_warning ("Invalid text buffer iterator: either the iterator "
152 "is uninitialized, or the characters/pixbufs/widgets "
153 "in the buffer have been modified since the iterator "
154 "was created.\nYou must use marks, character numbers, "
155 "or line numbers to preserve a position across buffer "
156 "modifications.\nYou can apply tags and insert marks "
157 "without invalidating your iterators,\n"
158 "but any mutation that affects 'indexable' buffer contents "
159 "(contents that can be referred to by character offset)\n"
160 "will invalidate all outstanding iterators");
164 /* We don't update the segments information since we are becoming
165 only surreal. However we do invalidate the segments information
166 if appropriate, to be sure we segfault if we try to use it and we
167 should have used make_real. */
169 if (iter->segments_changed_stamp !=
170 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
172 iter->segment = NULL;
173 iter->any_segment = NULL;
174 /* set to segfault-causing values. */
175 iter->segment_byte_offset = -10000;
176 iter->segment_char_offset = -10000;
182 static GtkTextRealIter*
183 gtk_text_iter_make_real (const GtkTextIter *_iter)
185 GtkTextRealIter *iter;
187 iter = gtk_text_iter_make_surreal (_iter);
189 if (iter->segments_changed_stamp !=
190 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
192 if (iter->line_byte_offset >= 0)
194 iter_set_from_byte_offset (iter,
196 iter->line_byte_offset);
200 g_assert (iter->line_char_offset >= 0);
202 iter_set_from_char_offset (iter,
204 iter->line_char_offset);
208 g_assert (iter->segment != NULL);
209 g_assert (iter->any_segment != NULL);
210 g_assert (iter->segment->char_count > 0);
215 static GtkTextRealIter*
216 iter_init_common (GtkTextIter *_iter,
219 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
221 g_return_val_if_fail (iter != NULL, NULL);
222 g_return_val_if_fail (tree != NULL, NULL);
226 iter->chars_changed_stamp =
227 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
232 static GtkTextRealIter*
233 iter_init_from_segment (GtkTextIter *iter,
236 GtkTextLineSegment *segment)
238 GtkTextRealIter *real;
240 g_return_val_if_fail (line != NULL, NULL);
242 real = iter_init_common (iter, tree);
244 iter_set_from_segment (real, line, segment);
249 static GtkTextRealIter*
250 iter_init_from_byte_offset (GtkTextIter *iter,
253 gint line_byte_offset)
255 GtkTextRealIter *real;
257 g_return_val_if_fail (line != NULL, NULL);
259 real = iter_init_common (iter, tree);
261 iter_set_from_byte_offset (real, line, line_byte_offset);
266 static GtkTextRealIter*
267 iter_init_from_char_offset (GtkTextIter *iter,
270 gint line_char_offset)
272 GtkTextRealIter *real;
274 g_return_val_if_fail (line != NULL, NULL);
276 real = iter_init_common (iter, tree);
278 iter_set_from_char_offset (real, line, line_char_offset);
284 invalidate_segment (GtkTextRealIter *iter)
286 iter->segments_changed_stamp -= 1;
290 invalidate_char_index (GtkTextRealIter *iter)
292 iter->cached_char_index = -1;
296 invalidate_line_number (GtkTextRealIter *iter)
298 iter->cached_line_number = -1;
302 adjust_char_index (GtkTextRealIter *iter, gint count)
304 if (iter->cached_char_index >= 0)
305 iter->cached_char_index += count;
309 adjust_line_number (GtkTextRealIter *iter, gint count)
311 if (iter->cached_line_number >= 0)
312 iter->cached_line_number += count;
316 adjust_char_offsets (GtkTextRealIter *iter, gint count)
318 if (iter->line_char_offset >= 0)
320 iter->line_char_offset += count;
321 g_assert (iter->segment_char_offset >= 0);
322 iter->segment_char_offset += count;
327 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
329 if (iter->line_byte_offset >= 0)
331 iter->line_byte_offset += count;
332 g_assert (iter->segment_byte_offset >= 0);
333 iter->segment_byte_offset += count;
338 ensure_char_offsets (GtkTextRealIter *iter)
340 if (iter->line_char_offset < 0)
342 g_assert (iter->line_byte_offset >= 0);
344 _gtk_text_line_byte_to_char_offsets (iter->line,
345 iter->line_byte_offset,
346 &iter->line_char_offset,
347 &iter->segment_char_offset);
352 ensure_byte_offsets (GtkTextRealIter *iter)
354 if (iter->line_byte_offset < 0)
356 g_assert (iter->line_char_offset >= 0);
358 _gtk_text_line_char_to_byte_offsets (iter->line,
359 iter->line_char_offset,
360 &iter->line_byte_offset,
361 &iter->segment_byte_offset);
365 static inline gboolean
366 is_segment_start (GtkTextRealIter *real)
368 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
373 check_invariants (const GtkTextIter *iter)
375 if (gtk_debug_flags & GTK_DEBUG_TEXT)
376 _gtk_text_iter_check (iter);
379 #define check_invariants (x)
383 * gtk_text_iter_get_buffer:
386 * Return the #GtkTextBuffer this iterator is associated with
388 * Return value: the buffer
391 gtk_text_iter_get_buffer (const GtkTextIter *iter)
393 GtkTextRealIter *real;
395 g_return_val_if_fail (iter != NULL, NULL);
397 real = gtk_text_iter_make_surreal (iter);
402 check_invariants (iter);
404 return _gtk_text_btree_get_buffer (real->tree);
408 * gtk_text_iter_copy:
411 * Create a dynamically-allocated copy of an iterator. This function
412 * is not useful in applications, because iterators can be copied with a
413 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
414 * function is used by language bindings.
416 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
419 gtk_text_iter_copy (const GtkTextIter *iter)
421 GtkTextIter *new_iter;
423 g_return_val_if_fail (iter != NULL, NULL);
425 new_iter = g_new (GtkTextIter, 1);
433 * gtk_text_iter_free:
434 * @iter: a dynamically-allocated iterator
436 * Free an iterator allocated on the heap. This function
437 * is intended for use in language bindings, and is not
438 * especially useful for applications, because iterators can
439 * simply be allocated on the stack.
443 gtk_text_iter_free (GtkTextIter *iter)
445 g_return_if_fail (iter != NULL);
451 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
453 GtkTextRealIter *real;
455 g_return_val_if_fail (iter != NULL, 0);
457 real = gtk_text_iter_make_real (iter);
462 check_invariants (iter);
464 g_assert (real->segment != NULL);
466 return real->segment;
470 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
472 GtkTextRealIter *real;
474 g_return_val_if_fail (iter != NULL, 0);
476 real = gtk_text_iter_make_real (iter);
481 check_invariants (iter);
483 g_assert (real->any_segment != NULL);
485 return real->any_segment;
489 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
491 GtkTextRealIter *real;
493 g_return_val_if_fail (iter != NULL, 0);
495 real = gtk_text_iter_make_real (iter);
500 ensure_byte_offsets (real);
502 check_invariants (iter);
504 return real->segment_byte_offset;
508 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
510 GtkTextRealIter *real;
512 g_return_val_if_fail (iter != NULL, 0);
514 real = gtk_text_iter_make_real (iter);
519 ensure_char_offsets (real);
521 check_invariants (iter);
523 return real->segment_char_offset;
526 /* This function does not require a still-valid
529 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
531 const GtkTextRealIter *real;
533 g_return_val_if_fail (iter != NULL, 0);
535 real = (const GtkTextRealIter*)iter;
540 /* This function does not require a still-valid
543 _gtk_text_iter_get_btree (const GtkTextIter *iter)
545 const GtkTextRealIter *real;
547 g_return_val_if_fail (iter != NULL, 0);
549 real = (const GtkTextRealIter*)iter;
559 * gtk_text_iter_get_offset:
562 * Returns the character offset of an iterator.
563 * Each character in a #GtkTextBuffer has an offset,
564 * starting with 0 for the first character in the buffer.
565 * Use gtk_text_buffer_get_iter_at_offset () to convert an
566 * offset back into an iterator.
568 * Return value: a character offset
571 gtk_text_iter_get_offset (const GtkTextIter *iter)
573 GtkTextRealIter *real;
575 g_return_val_if_fail (iter != NULL, 0);
577 real = gtk_text_iter_make_surreal (iter);
582 check_invariants (iter);
584 if (real->cached_char_index < 0)
586 ensure_char_offsets (real);
588 real->cached_char_index =
589 _gtk_text_line_char_index (real->line);
590 real->cached_char_index += real->line_char_offset;
593 check_invariants (iter);
595 return real->cached_char_index;
599 * gtk_text_iter_get_line:
602 * Returns the line number containing the iterator. Lines in
603 * a #GtkTextBuffer are numbered beginning with 0 for the first
604 * line in the buffer.
606 * Return value: a line number
609 gtk_text_iter_get_line (const GtkTextIter *iter)
611 GtkTextRealIter *real;
613 g_return_val_if_fail (iter != NULL, 0);
615 real = gtk_text_iter_make_surreal (iter);
620 if (real->cached_line_number < 0)
621 real->cached_line_number =
622 _gtk_text_line_get_number (real->line);
624 check_invariants (iter);
626 return real->cached_line_number;
630 * gtk_text_iter_get_line_offset:
633 * Returns the character offset of the iterator,
634 * counting from the start of a newline-terminated line.
635 * The first character on the line has offset 0.
637 * Return value: offset from start of line
640 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
643 GtkTextRealIter *real;
645 g_return_val_if_fail (iter != NULL, 0);
647 real = gtk_text_iter_make_surreal (iter);
652 ensure_char_offsets (real);
654 check_invariants (iter);
656 return real->line_char_offset;
660 * gtk_text_iter_get_line_index:
663 * Returns the byte index of the iterator, counting
664 * from the start of a newline-terminated line.
665 * Remember that #GtkTextBuffer encodes text in
666 * UTF-8, and that characters can require a variable
667 * number of bytes to represent.
669 * Return value: distance from start of line, in bytes
672 gtk_text_iter_get_line_index (const GtkTextIter *iter)
674 GtkTextRealIter *real;
676 g_return_val_if_fail (iter != NULL, 0);
678 real = gtk_text_iter_make_surreal (iter);
683 ensure_byte_offsets (real);
685 check_invariants (iter);
687 return real->line_byte_offset;
695 * gtk_text_iter_get_char:
698 * Returns the Unicode character at this iterator. (Equivalent to
699 * operator* on a C++ iterator.) If the iterator points at a
700 * non-character element, such as an image embedded in the buffer, the
701 * Unicode "unknown" character 0xFFFC is returned. If invoked on
702 * the end iterator, zero is returned; zero is not a valid Unicode character.
703 * So you can write a loop which ends when gtk_text_iter_get_char ()
706 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
709 gtk_text_iter_get_char (const GtkTextIter *iter)
711 GtkTextRealIter *real;
713 g_return_val_if_fail (iter != NULL, 0);
715 real = gtk_text_iter_make_real (iter);
720 check_invariants (iter);
722 if (gtk_text_iter_is_last (iter))
724 else if (real->segment->type == >k_text_char_type)
726 ensure_byte_offsets (real);
728 return g_utf8_get_char (real->segment->body.chars +
729 real->segment_byte_offset);
733 /* Unicode "unknown character" 0xFFFC */
734 return GTK_TEXT_UNKNOWN_CHAR;
739 * gtk_text_iter_get_slice:
740 * @start: iterator at start of a range
741 * @end: iterator at end of a range
743 * Returns the text in the given range. A "slice" is an array of
744 * characters encoded in UTF-8 format, including the Unicode "unknown"
745 * character 0xFFFC for iterable non-character elements in the buffer,
746 * such as images. Because images are encoded in the slice, byte and
747 * character offsets in the returned array will correspond to byte
748 * offsets in the text buffer. Note that 0xFFFC can occur in normal
749 * text as well, so it is not a reliable indicator that a pixbuf or
750 * widget is in the buffer.
752 * Return value: slice of text from the buffer
755 gtk_text_iter_get_slice (const GtkTextIter *start,
756 const GtkTextIter *end)
758 g_return_val_if_fail (start != NULL, NULL);
759 g_return_val_if_fail (end != NULL, NULL);
761 check_invariants (start);
762 check_invariants (end);
764 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
768 * gtk_text_iter_get_text:
769 * @start: iterator at start of a range
770 * @end: iterator at end of a range
772 * Returns <emphasis>text</emphasis> in the given range. If the range
773 * contains non-text elements such as images, the character and byte
774 * offsets in the returned string will not correspond to character and
775 * byte offsets in the buffer. If you want offsets to correspond, see
776 * gtk_text_iter_get_slice ().
778 * Return value: array of characters from the buffer
781 gtk_text_iter_get_text (const GtkTextIter *start,
782 const GtkTextIter *end)
784 g_return_val_if_fail (start != NULL, NULL);
785 g_return_val_if_fail (end != NULL, NULL);
787 check_invariants (start);
788 check_invariants (end);
790 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
794 * gtk_text_iter_get_visible_slice:
795 * @start: iterator at start of range
796 * @end: iterator at end of range
798 * Like gtk_text_iter_get_slice (), but invisible text is not included.
799 * Invisible text is usually invisible because a #GtkTextTag with the
800 * "invisible" attribute turned on has been applied to it.
802 * Return value: slice of text from the buffer
805 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
806 const GtkTextIter *end)
808 g_return_val_if_fail (start != NULL, NULL);
809 g_return_val_if_fail (end != NULL, NULL);
811 check_invariants (start);
812 check_invariants (end);
814 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
818 * gtk_text_iter_get_visible_text:
819 * @start: iterator at start of range
820 * @end: iterator at end of range
822 * Like gtk_text_iter_get_text (), but invisible text is not included.
823 * Invisible text is usually invisible because a #GtkTextTag with the
824 * "invisible" attribute turned on has been applied to it.
826 * Return value: string containing visible text in the range
829 gtk_text_iter_get_visible_text (const GtkTextIter *start,
830 const GtkTextIter *end)
832 g_return_val_if_fail (start != NULL, NULL);
833 g_return_val_if_fail (end != NULL, NULL);
835 check_invariants (start);
836 check_invariants (end);
838 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
842 * gtk_text_iter_get_pixbuf:
845 * If the location pointed to by @iter contains a pixbuf, the pixbuf
846 * is returned (with no new reference count added). Otherwise,
849 * Return value: the pixbuf at @iter
852 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
854 GtkTextRealIter *real;
856 g_return_val_if_fail (iter != NULL, NULL);
858 real = gtk_text_iter_make_real (iter);
863 check_invariants (iter);
865 if (real->segment->type != >k_text_pixbuf_type)
868 return real->segment->body.pixbuf.pixbuf;
872 * gtk_text_iter_get_child_anchor:
875 * If the location pointed to by @iter contains a child anchor, the
876 * anchor is returned (with no new reference count added). Otherwise,
879 * Return value: the anchor at @iter
882 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
884 GtkTextRealIter *real;
886 g_return_val_if_fail (iter != NULL, NULL);
888 real = gtk_text_iter_make_real (iter);
893 check_invariants (iter);
895 if (real->segment->type != >k_text_child_type)
898 return real->segment->body.child.obj;
902 * gtk_text_iter_get_marks:
905 * Returns a list of all #GtkTextMark at this location. Because marks
906 * are not iterable (they don't take up any "space" in the buffer,
907 * they are just marks in between iterable locations), multiple marks
908 * can exist in the same place. The returned list is not in any
911 * Return value: list of #GtkTextMark
914 gtk_text_iter_get_marks (const GtkTextIter *iter)
916 GtkTextRealIter *real;
917 GtkTextLineSegment *seg;
920 g_return_val_if_fail (iter != NULL, NULL);
922 real = gtk_text_iter_make_real (iter);
927 check_invariants (iter);
930 seg = real->any_segment;
931 while (seg != real->segment)
933 if (seg->type == >k_text_left_mark_type ||
934 seg->type == >k_text_right_mark_type)
935 retval = g_slist_prepend (retval, seg->body.mark.obj);
940 /* The returned list isn't guaranteed to be in any special order,
946 * gtk_text_iter_get_toggled_tags:
948 * @toggled_on: TRUE to get toggled-on tags
950 * Returns a list of #GtkTextTag that are toggled on or off at this
951 * point. (If @toggled_on is TRUE, the list contains tags that are
952 * toggled on.) If a tag is toggled on at @iter, then some non-empty
953 * range of characters following @iter has that tag applied to it. If
954 * a tag is toggled off, then some non-empty range following @iter
955 * does <emphasis>not</emphasis> have the tag applied to it.
957 * Return value: tags toggled at this point
960 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
963 GtkTextRealIter *real;
964 GtkTextLineSegment *seg;
967 g_return_val_if_fail (iter != NULL, NULL);
969 real = gtk_text_iter_make_real (iter);
974 check_invariants (iter);
977 seg = real->any_segment;
978 while (seg != real->segment)
982 if (seg->type == >k_text_toggle_on_type)
984 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
989 if (seg->type == >k_text_toggle_off_type)
991 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
998 /* The returned list isn't guaranteed to be in any special order,
1004 * gtk_text_iter_begins_tag:
1005 * @iter: an iterator
1006 * @tag: a #GtkTextTag, or NULL
1008 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
1009 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1010 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1011 * <emphasis>start</emphasis> of the tagged range;
1012 * gtk_text_iter_has_tag () tells you whether an iterator is
1013 * <emphasis>within</emphasis> a tagged range.
1015 * Return value: whether @iter is the start of a range tagged with @tag
1018 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1021 GtkTextRealIter *real;
1022 GtkTextLineSegment *seg;
1024 g_return_val_if_fail (iter != NULL, FALSE);
1026 real = gtk_text_iter_make_real (iter);
1031 check_invariants (iter);
1033 seg = real->any_segment;
1034 while (seg != real->segment)
1036 if (seg->type == >k_text_toggle_on_type)
1039 seg->body.toggle.info->tag == tag)
1050 * gtk_text_iter_ends_tag:
1051 * @iter: an iterator
1052 * @tag: a #GtkTextTag, or NULL
1054 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1055 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1056 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1057 * <emphasis>end</emphasis> of the tagged range;
1058 * gtk_text_iter_has_tag () tells you whether an iterator is
1059 * <emphasis>within</emphasis> a tagged range.
1061 * Return value: whether @iter is the end of a range tagged with @tag
1065 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1068 GtkTextRealIter *real;
1069 GtkTextLineSegment *seg;
1071 g_return_val_if_fail (iter != NULL, FALSE);
1073 real = gtk_text_iter_make_real (iter);
1078 check_invariants (iter);
1080 seg = real->any_segment;
1081 while (seg != real->segment)
1083 if (seg->type == >k_text_toggle_off_type)
1086 seg->body.toggle.info->tag == tag)
1097 * gtk_text_iter_toggles_tag:
1098 * @iter: an iterator
1099 * @tag: a #GtkTextTag, or NULL
1101 * This is equivalent to (gtk_text_iter_begins_tag () ||
1102 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1103 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1105 * Return value: whether @tag is toggled on or off at @iter
1108 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1111 GtkTextRealIter *real;
1112 GtkTextLineSegment *seg;
1114 g_return_val_if_fail (iter != NULL, FALSE);
1116 real = gtk_text_iter_make_real (iter);
1121 check_invariants (iter);
1123 seg = real->any_segment;
1124 while (seg != real->segment)
1126 if ( (seg->type == >k_text_toggle_off_type ||
1127 seg->type == >k_text_toggle_on_type) &&
1129 seg->body.toggle.info->tag == tag) )
1139 * gtk_text_iter_has_tag:
1140 * @iter: an iterator
1141 * @tag: a #GtkTextTag
1143 * Returns TRUE if @iter is within a range tagged with @tag.
1145 * Return value: whether @iter is tagged with @tag
1148 gtk_text_iter_has_tag (const GtkTextIter *iter,
1151 GtkTextRealIter *real;
1153 g_return_val_if_fail (iter != NULL, FALSE);
1154 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1156 real = gtk_text_iter_make_surreal (iter);
1161 check_invariants (iter);
1163 if (real->line_byte_offset >= 0)
1165 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1166 real->line_byte_offset, tag);
1170 g_assert (real->line_char_offset >= 0);
1171 return _gtk_text_line_char_has_tag (real->line, real->tree,
1172 real->line_char_offset, tag);
1177 * gtk_text_iter_get_tags:
1178 * @iter: a #GtkTextIter
1180 * Returns a list of tags that apply to @iter, in ascending order of
1181 * priority (highest-priority tags are last). The #GtkTextTag in the
1182 * list don't have a reference added, but you have to free the list
1185 * Return value: list of #GtkTextTag
1188 gtk_text_iter_get_tags (const GtkTextIter *iter)
1195 g_return_val_if_fail (iter != NULL, NULL);
1197 /* Get the tags at this spot */
1198 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1200 /* No tags, use default style */
1201 if (tags == NULL || tag_count == 0)
1209 /* Sort tags in ascending order of priority */
1210 _gtk_text_tag_array_sort (tags, tag_count);
1214 while (i < tag_count)
1216 retval = g_slist_prepend (retval, tags[i]);
1222 /* Return tags in ascending order of priority */
1223 return g_slist_reverse (retval);
1227 * gtk_text_iter_editable:
1228 * @iter: an iterator
1229 * @default_setting: TRUE if text is editable by default
1231 * Returns whether @iter is within an editable region of text.
1232 * Non-editable text is "locked" and can't be changed by the user via
1233 * #GtkTextView. This function is simply a convenience wrapper around
1234 * gtk_text_iter_get_attributes (). If no tags applied to this text
1235 * affect editability, @default_setting will be returned.
1237 * Return value: whether @iter is inside an editable range
1240 gtk_text_iter_editable (const GtkTextIter *iter,
1241 gboolean default_setting)
1243 GtkTextAttributes *values;
1246 values = gtk_text_attributes_new ();
1248 values->editable = default_setting;
1250 gtk_text_iter_get_attributes (iter, values);
1252 retval = values->editable;
1254 gtk_text_attributes_unref (values);
1260 * gtk_text_iter_get_language:
1261 * @iter: an iterator
1263 * A convenience wrapper around gtk_text_iter_get_attributes (),
1264 * which returns the language in effect at @iter. If no tags affecting
1265 * language * apply to @iter, the return value is identical to that of
1266 * gtk_get_default_language ().
1268 * Return value: language in effect at @iter
1271 gtk_text_iter_get_language (const GtkTextIter *iter)
1273 GtkTextAttributes *values;
1276 values = gtk_text_attributes_new ();
1278 gtk_text_iter_get_attributes (iter, values);
1280 retval = g_strdup (values->language);
1282 gtk_text_attributes_unref (values);
1288 * gtk_text_iter_starts_line:
1289 * @iter: an iterator
1291 * Returns TRUE if @iter begins a paragraph,
1292 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1293 * However this function is potentially more efficient than
1294 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1295 * the offset, it just has to see whether it's 0.
1297 * Return value: whether @iter begins a line
1300 gtk_text_iter_starts_line (const GtkTextIter *iter)
1302 GtkTextRealIter *real;
1304 g_return_val_if_fail (iter != NULL, FALSE);
1306 real = gtk_text_iter_make_surreal (iter);
1311 check_invariants (iter);
1313 if (real->line_byte_offset >= 0)
1315 return (real->line_byte_offset == 0);
1319 g_assert (real->line_char_offset >= 0);
1320 return (real->line_char_offset == 0);
1325 * gtk_text_iter_ends_line:
1326 * @iter: an iterator
1328 * Returns TRUE if @iter points to the start of the paragraph delimiter
1329 * characters for a line (delimiters will be either a newline, a
1330 * carriage return, a carriage return followed by a newline, or a
1331 * Unicode paragraph separator character). Note that an iterator pointing
1332 * to the \n of a \r\n pair will not be counted as the end of a line,
1333 * the line ends before the \r.
1335 * Return value: whether @iter is at the end of a line
1338 gtk_text_iter_ends_line (const GtkTextIter *iter)
1340 GtkTextRealIter *real;
1343 g_return_val_if_fail (iter != NULL, FALSE);
1345 real = gtk_text_iter_make_real (iter);
1347 check_invariants (iter);
1349 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1350 * Unicode 3.0; update this if that changes.
1352 #define PARAGRAPH_SEPARATOR 0x2029
1354 wc = gtk_text_iter_get_char (iter);
1356 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1358 else if (wc == '\n')
1360 /* need to determine if a \r precedes the \n, in which case
1361 * we aren't the end of the line
1363 GtkTextIter tmp = *iter;
1364 if (!gtk_text_iter_backward_char (&tmp))
1367 return gtk_text_iter_get_char (&tmp) != '\r';
1374 * gtk_text_iter_is_last:
1375 * @iter: an iterator
1377 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1378 * dereferenceable iterator in the buffer. gtk_text_iter_is_last () is
1379 * the most efficient way to check whether an iterator is the end
1382 * Return value: whether @iter is the end iterator
1385 gtk_text_iter_is_last (const GtkTextIter *iter)
1387 GtkTextRealIter *real;
1389 g_return_val_if_fail (iter != NULL, FALSE);
1391 real = gtk_text_iter_make_surreal (iter);
1396 check_invariants (iter);
1398 return _gtk_text_line_is_last (real->line, real->tree);
1402 * gtk_text_iter_is_first:
1403 * @iter: an iterator
1405 * Returns TRUE if @iter is the first iterator in the buffer, that is
1406 * if @iter has a character offset of 0.
1408 * Return value: whether @iter is the first in the buffer
1411 gtk_text_iter_is_first (const GtkTextIter *iter)
1413 return gtk_text_iter_get_offset (iter) == 0;
1417 * gtk_text_iter_get_chars_in_line:
1418 * @iter: an iterator
1420 * Returns the number of characters in the line containing @iter,
1421 * including the paragraph delimiters.
1423 * Return value: number of characters in the line
1426 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1428 GtkTextRealIter *real;
1430 GtkTextLineSegment *seg;
1432 g_return_val_if_fail (iter != NULL, FALSE);
1434 real = gtk_text_iter_make_surreal (iter);
1439 check_invariants (iter);
1441 if (real->line_char_offset >= 0)
1443 /* We can start at the segments we've already found. */
1444 count = real->line_char_offset - real->segment_char_offset;
1445 seg = _gtk_text_iter_get_indexable_segment (iter);
1449 /* count whole line. */
1450 seg = real->line->segments;
1457 count += seg->char_count;
1466 * gtk_text_iter_get_bytes_in_line:
1467 * @iter: an iterator
1469 * Returns the number of bytes in the line containing @iter,
1470 * including the paragraph delimiters.
1472 * Return value: number of bytes in the line
1475 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1477 GtkTextRealIter *real;
1479 GtkTextLineSegment *seg;
1481 g_return_val_if_fail (iter != NULL, FALSE);
1483 real = gtk_text_iter_make_surreal (iter);
1488 check_invariants (iter);
1490 if (real->line_byte_offset >= 0)
1492 /* We can start at the segments we've already found. */
1493 count = real->line_byte_offset - real->segment_byte_offset;
1494 seg = _gtk_text_iter_get_indexable_segment (iter);
1498 /* count whole line. */
1499 seg = real->line->segments;
1505 count += seg->byte_count;
1514 * gtk_text_iter_get_attributes:
1515 * @iter: an iterator
1516 * @values: a #GtkTextAttributes to be filled in
1518 * Computes the effect of any tags applied to this spot in the
1519 * text. The @values parameter should be initialized to the default
1520 * settings you wish to use if no tags are in effect.
1521 * gtk_text_iter_get_attributes () will modify @values, applying the
1522 * effects of any tags present at @iter. If any tags affected @values,
1523 * the function returns TRUE.
1525 * Return value: TRUE if @values was modified
1528 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1529 GtkTextAttributes *values)
1534 /* Get the tags at this spot */
1535 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1537 /* No tags, use default style */
1538 if (tags == NULL || tag_count == 0)
1546 /* Sort tags in ascending order of priority */
1547 _gtk_text_tag_array_sort (tags, tag_count);
1549 _gtk_text_attributes_fill_from_tags (values,
1559 * Increments/decrements
1562 /* The return value of this indicates WHETHER WE MOVED.
1563 * The return value of public functions indicates
1564 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1567 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1569 GtkTextLine *new_line;
1571 new_line = _gtk_text_line_next (real->line);
1573 g_assert (new_line != real->line);
1575 if (new_line != NULL)
1577 real->line = new_line;
1579 real->line_byte_offset = 0;
1580 real->line_char_offset = 0;
1582 real->segment_byte_offset = 0;
1583 real->segment_char_offset = 0;
1585 /* Find first segments in new line */
1586 real->any_segment = real->line->segments;
1587 real->segment = real->any_segment;
1588 while (real->segment->char_count == 0)
1589 real->segment = real->segment->next;
1595 /* There is no way to move forward; we were already
1596 at the "end" index. (the end index is the last
1597 line pointer, segment_byte_offset of 0) */
1599 g_assert (real->line_char_offset == 0 ||
1600 real->line_byte_offset == 0);
1602 /* The only indexable segment allowed on the bogus
1603 line at the end is a single char segment containing
1605 if (real->segments_changed_stamp ==
1606 _gtk_text_btree_get_segments_changed_stamp (real->tree))
1608 g_assert (real->segment->type == >k_text_char_type);
1609 g_assert (real->segment->char_count == 1);
1611 /* We leave real->line as-is */
1618 /* The return value of this indicates WHETHER WE MOVED.
1619 * The return value of public functions indicates
1620 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1623 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1625 GtkTextLine *new_line;
1627 new_line = _gtk_text_line_previous (real->line);
1629 g_assert (new_line != real->line);
1631 if (new_line != NULL)
1633 real->line = new_line;
1635 real->line_byte_offset = 0;
1636 real->line_char_offset = 0;
1638 real->segment_byte_offset = 0;
1639 real->segment_char_offset = 0;
1641 /* Find first segments in new line */
1642 real->any_segment = real->line->segments;
1643 real->segment = real->any_segment;
1644 while (real->segment->char_count == 0)
1645 real->segment = real->segment->next;
1651 /* There is no way to move backward; we were already
1652 at the first line. */
1654 /* We leave real->line as-is */
1656 /* Note that we didn't clamp to the start of the first line. */
1662 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1666 forward_char (GtkTextRealIter *real)
1668 GtkTextIter *iter = (GtkTextIter*)real;
1670 check_invariants ((GtkTextIter*)real);
1672 ensure_char_offsets (real);
1674 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1676 /* Need to move to the next segment; if no next segment,
1677 need to move to next line. */
1678 return _gtk_text_iter_forward_indexable_segment (iter);
1682 /* Just moving within a segment. Keep byte count
1683 up-to-date, if it was already up-to-date. */
1685 g_assert (real->segment->type == >k_text_char_type);
1687 if (real->line_byte_offset >= 0)
1690 const char * start =
1691 real->segment->body.chars + real->segment_byte_offset;
1693 bytes = g_utf8_next_char (start) - start;
1695 real->line_byte_offset += bytes;
1696 real->segment_byte_offset += bytes;
1698 g_assert (real->segment_byte_offset < real->segment->byte_count);
1701 real->line_char_offset += 1;
1702 real->segment_char_offset += 1;
1704 adjust_char_index (real, 1);
1706 g_assert (real->segment_char_offset < real->segment->char_count);
1708 /* We moved into the middle of a segment, so the any_segment
1709 must now be the segment we're in the middle of. */
1710 real->any_segment = real->segment;
1712 check_invariants ((GtkTextIter*)real);
1714 if (gtk_text_iter_is_last ((GtkTextIter*)real))
1722 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1724 /* Need to move to the next segment; if no next segment,
1725 need to move to next line. */
1726 GtkTextLineSegment *seg;
1727 GtkTextLineSegment *any_seg;
1728 GtkTextRealIter *real;
1732 g_return_val_if_fail (iter != NULL, FALSE);
1734 real = gtk_text_iter_make_real (iter);
1739 check_invariants (iter);
1741 if (real->line_char_offset >= 0)
1743 chars_skipped = real->segment->char_count - real->segment_char_offset;
1744 g_assert (chars_skipped > 0);
1749 if (real->line_byte_offset >= 0)
1751 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1752 g_assert (bytes_skipped > 0);
1757 /* Get first segment of any kind */
1758 any_seg = real->segment->next;
1759 /* skip non-indexable segments, if any */
1761 while (seg != NULL && seg->char_count == 0)
1766 real->any_segment = any_seg;
1767 real->segment = seg;
1769 if (real->line_byte_offset >= 0)
1771 g_assert (bytes_skipped > 0);
1772 real->segment_byte_offset = 0;
1773 real->line_byte_offset += bytes_skipped;
1776 if (real->line_char_offset >= 0)
1778 g_assert (chars_skipped > 0);
1779 real->segment_char_offset = 0;
1780 real->line_char_offset += chars_skipped;
1781 adjust_char_index (real, chars_skipped);
1784 check_invariants (iter);
1790 /* End of the line */
1791 if (forward_line_leaving_caches_unmodified (real))
1793 adjust_line_number (real, 1);
1794 if (real->line_char_offset >= 0)
1795 adjust_char_index (real, chars_skipped);
1797 g_assert (real->line_byte_offset == 0);
1798 g_assert (real->line_char_offset == 0);
1799 g_assert (real->segment_byte_offset == 0);
1800 g_assert (real->segment_char_offset == 0);
1801 g_assert (gtk_text_iter_starts_line (iter));
1803 check_invariants (iter);
1805 if (gtk_text_iter_is_last (iter))
1814 check_invariants (iter);
1822 at_last_indexable_segment (GtkTextRealIter *real)
1824 GtkTextLineSegment *seg;
1826 /* Return TRUE if there are no indexable segments after
1830 seg = real->segment->next;
1833 if (seg->char_count > 0)
1840 /* Goes back to the start of the next segment, even if
1841 * we're not at the start of the current segment (always
1842 * ends up on a different segment if it returns TRUE)
1845 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1847 /* Move to the start of the previous segment; if no previous
1848 * segment, to the last segment in the previous line. This is
1849 * inherently a bit inefficient due to the singly-linked list and
1850 * tree nodes, but we can't afford the RAM for doubly-linked.
1852 GtkTextRealIter *real;
1853 GtkTextLineSegment *seg;
1854 GtkTextLineSegment *any_seg;
1855 GtkTextLineSegment *prev_seg;
1856 GtkTextLineSegment *prev_any_seg;
1860 g_return_val_if_fail (iter != NULL, FALSE);
1862 real = gtk_text_iter_make_real (iter);
1867 check_invariants (iter);
1869 /* Find first segments in line */
1870 any_seg = real->line->segments;
1872 while (seg->char_count == 0)
1875 if (seg == real->segment)
1877 /* Could probably do this case faster by hand-coding the
1881 /* We were already at the start of a line;
1882 * go back to the previous line.
1884 if (gtk_text_iter_backward_line (iter))
1886 /* Go forward to last indexable segment in line. */
1887 while (!at_last_indexable_segment (real))
1888 _gtk_text_iter_forward_indexable_segment (iter);
1890 check_invariants (iter);
1895 return FALSE; /* We were at the start of the first line. */
1898 /* We must be in the middle of a line; so find the indexable
1899 * segment just before our current segment.
1901 g_assert (seg != real->segment);
1902 while (seg != real->segment)
1905 prev_any_seg = any_seg;
1907 any_seg = seg->next;
1909 while (seg->char_count == 0)
1913 g_assert (prev_seg != NULL);
1914 g_assert (prev_any_seg != NULL);
1915 g_assert (prev_seg->char_count > 0);
1917 /* We skipped the entire previous segment, plus any
1918 * chars we were into the current segment.
1920 if (real->segment_byte_offset >= 0)
1921 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
1925 if (real->segment_char_offset >= 0)
1926 chars_skipped = prev_seg->char_count + real->segment_char_offset;
1930 real->segment = prev_seg;
1931 real->any_segment = prev_any_seg;
1932 real->segment_byte_offset = 0;
1933 real->segment_char_offset = 0;
1935 if (bytes_skipped >= 0)
1937 if (real->line_byte_offset >= 0)
1939 real->line_byte_offset -= bytes_skipped;
1940 g_assert (real->line_byte_offset >= 0);
1944 real->line_byte_offset = -1;
1946 if (chars_skipped >= 0)
1948 if (real->line_char_offset >= 0)
1950 real->line_char_offset -= chars_skipped;
1951 g_assert (real->line_char_offset >= 0);
1954 if (real->cached_char_index >= 0)
1956 real->cached_char_index -= chars_skipped;
1957 g_assert (real->cached_char_index >= 0);
1962 real->line_char_offset = -1;
1963 real->cached_char_index = -1;
1966 /* line number is unchanged. */
1968 check_invariants (iter);
1974 * gtk_text_iter_forward_char:
1975 * @iter: an iterator
1977 * Moves @iter forward by one character offset. Note that images
1978 * embedded in the buffer occupy 1 character slot, so
1979 * gtk_text_iter_forward_char () may actually move onto an image instead
1980 * of a character, if you have images in your buffer. If @iter is the
1981 * end iterator or one character before it, @iter will now point at
1982 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
1983 * convenience when writing loops.
1985 * Return value: whether the new position is the end iterator
1988 gtk_text_iter_forward_char (GtkTextIter *iter)
1990 GtkTextRealIter *real;
1992 g_return_val_if_fail (iter != NULL, FALSE);
1994 real = gtk_text_iter_make_real (iter);
2000 check_invariants (iter);
2001 return forward_char (real);
2006 * gtk_text_iter_backward_char:
2007 * @iter: an iterator
2009 * Moves backward by one character offset. Returns TRUE if movement
2010 * was possible; if @iter was the first in the buffer (character
2011 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2014 * Return value: whether movement was possible
2017 gtk_text_iter_backward_char (GtkTextIter *iter)
2019 g_return_val_if_fail (iter != NULL, FALSE);
2021 check_invariants (iter);
2023 return gtk_text_iter_backward_chars (iter, 1);
2027 Definitely we should try to linear scan as often as possible for
2028 movement within a single line, because we can't use the BTree to
2029 speed within-line searches up; for movement between lines, we would
2030 like to avoid the linear scan probably.
2032 Instead of using this constant, it might be nice to cache the line
2033 length in the iterator and linear scan if motion is within a single
2036 I guess you'd have to profile the various approaches.
2038 #define MAX_LINEAR_SCAN 150
2042 * gtk_text_iter_forward_chars:
2043 * @iter: an iterator
2044 * @count: number of characters to move, may be negative
2046 * Moves @count characters if possible (if @count would move past the
2047 * start or end of the buffer, moves to the start or end of the
2048 * buffer). The return value indicates whether the new position of
2049 * @iter is different from its original position, and dereferenceable
2050 * (the last iterator in the buffer is not dereferenceable). If @count
2051 * is 0, the function does nothing and returns FALSE.
2053 * Return value: whether @iter moved and is dereferenceable
2056 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2058 GtkTextRealIter *real;
2060 g_return_val_if_fail (iter != NULL, FALSE);
2062 real = gtk_text_iter_make_real (iter);
2066 else if (count == 0)
2069 return gtk_text_iter_backward_chars (iter, 0 - count);
2070 else if (count < MAX_LINEAR_SCAN)
2072 check_invariants (iter);
2076 if (!forward_char (real))
2081 return forward_char (real);
2085 gint current_char_index;
2086 gint new_char_index;
2088 check_invariants (iter);
2090 current_char_index = gtk_text_iter_get_offset (iter);
2092 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2093 return FALSE; /* can't move forward */
2095 new_char_index = current_char_index + count;
2096 gtk_text_iter_set_offset (iter, new_char_index);
2098 check_invariants (iter);
2100 /* Return FALSE if we're on the non-dereferenceable end
2103 if (gtk_text_iter_is_last (iter))
2111 * gtk_text_iter_backward_chars:
2112 * @iter: an iterator
2113 * @count: number of characters to move
2115 * Moves @count characters backward, if possible (if @count would move
2116 * past the start or end of the buffer, moves to the start or end of
2117 * the buffer). The return value indicates whether the iterator moved
2118 * onto a dereferenceable position; if the iterator didn't move, or
2119 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2120 * the function does nothing and returns FALSE.
2122 * Return value: whether @iter moved and is dereferenceable
2126 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2128 GtkTextRealIter *real;
2130 g_return_val_if_fail (iter != NULL, FALSE);
2132 real = gtk_text_iter_make_real (iter);
2136 else if (count == 0)
2139 return gtk_text_iter_forward_chars (iter, 0 - count);
2141 ensure_char_offsets (real);
2142 check_invariants (iter);
2144 if (count <= real->segment_char_offset)
2146 /* Optimize the within-segment case */
2147 g_assert (real->segment->char_count > 0);
2148 g_assert (real->segment->type == >k_text_char_type);
2150 real->segment_char_offset -= count;
2151 g_assert (real->segment_char_offset >= 0);
2153 if (real->line_byte_offset >= 0)
2155 gint new_byte_offset;
2158 new_byte_offset = 0;
2160 while (i < real->segment_char_offset)
2162 const char * start = real->segment->body.chars + new_byte_offset;
2163 new_byte_offset += g_utf8_next_char (start) - start;
2168 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2169 real->segment_byte_offset = new_byte_offset;
2172 real->line_char_offset -= count;
2174 adjust_char_index (real, 0 - count);
2176 check_invariants (iter);
2182 /* We need to go back into previous segments. For now,
2183 * just keep this really simple. FIXME
2184 * use backward_indexable_segment.
2186 if (TRUE || count > MAX_LINEAR_SCAN)
2188 gint current_char_index;
2189 gint new_char_index;
2191 current_char_index = gtk_text_iter_get_offset (iter);
2193 if (current_char_index == 0)
2194 return FALSE; /* can't move backward */
2196 new_char_index = current_char_index - count;
2197 if (new_char_index < 0)
2199 gtk_text_iter_set_offset (iter, new_char_index);
2201 check_invariants (iter);
2207 /* FIXME backward_indexable_segment here */
2216 /* These two can't be implemented efficiently (always have to use
2217 * a linear scan, since that's the only way to find all the non-text
2222 * gtk_text_iter_forward_text_chars:
2223 * @iter: a #GtkTextIter
2224 * @count: number of chars to move
2226 * Moves forward by @count text characters (pixbufs, widgets,
2227 * etc. do not count as characters for this). Equivalent to moving
2228 * through the results of gtk_text_iter_get_text (), rather than
2229 * gtk_text_iter_get_slice ().
2231 * Return value: whether @iter moved and is dereferenceable
2234 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2243 * gtk_text_iter_forward_text_chars:
2244 * @iter: a #GtkTextIter
2245 * @count: number of chars to move
2247 * Moves backward by @count text characters (pixbufs, widgets,
2248 * etc. do not count as characters for this). Equivalent to moving
2249 * through the results of gtk_text_iter_get_text (), rather than
2250 * gtk_text_iter_get_slice ().
2252 * Return value: whether @iter moved and is dereferenceable
2255 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2264 * gtk_text_iter_forward_line:
2265 * @iter: an iterator
2267 * Moves @iter to the start of the next line. Returns TRUE if there
2268 * was a next line to move to, and FALSE if @iter was simply moved to
2269 * the end of the buffer and is now not dereferenceable, or if @iter was
2270 * already at the end of the buffer.
2272 * Return value: whether @iter can be dereferenced
2275 gtk_text_iter_forward_line (GtkTextIter *iter)
2277 GtkTextRealIter *real;
2279 g_return_val_if_fail (iter != NULL, FALSE);
2281 real = gtk_text_iter_make_real (iter);
2286 check_invariants (iter);
2288 if (forward_line_leaving_caches_unmodified (real))
2290 invalidate_char_index (real);
2291 adjust_line_number (real, 1);
2293 check_invariants (iter);
2295 if (gtk_text_iter_is_last (iter))
2302 check_invariants (iter);
2308 * gtk_text_iter_backward_line:
2309 * @iter: an iterator
2311 * Moves @iter to the start of the previous line. Returns TRUE if
2312 * @iter could be moved; i.e. if @iter was at character offset 0, this
2313 * function returns FALSE. Therefore if @iter was already on line 0,
2314 * but not at the start of the line, @iter is snapped to the start of
2315 * the line and the function returns TRUE. (Note that this implies that
2316 * in a loop calling this function, the line number may not change on
2317 * every iteration, if your first iteration is on line 0.)
2319 * Return value: whether @iter moved
2322 gtk_text_iter_backward_line (GtkTextIter *iter)
2324 GtkTextLine *new_line;
2325 GtkTextRealIter *real;
2326 gboolean offset_will_change;
2329 g_return_val_if_fail (iter != NULL, FALSE);
2331 real = gtk_text_iter_make_real (iter);
2336 check_invariants (iter);
2338 new_line = _gtk_text_line_previous (real->line);
2340 offset_will_change = FALSE;
2341 if (real->line_char_offset > 0)
2342 offset_will_change = TRUE;
2344 if (new_line != NULL)
2346 real->line = new_line;
2348 adjust_line_number (real, -1);
2352 if (!offset_will_change)
2356 invalidate_char_index (real);
2358 real->line_byte_offset = 0;
2359 real->line_char_offset = 0;
2361 real->segment_byte_offset = 0;
2362 real->segment_char_offset = 0;
2364 /* Find first segment in line */
2365 real->any_segment = real->line->segments;
2366 real->segment = _gtk_text_line_byte_to_segment (real->line,
2369 g_assert (offset == 0);
2371 /* Note that if we are on the first line, we snap to the start of
2372 * the first line and return TRUE, so TRUE means the iterator
2373 * changed, not that the line changed; this is maybe a bit
2374 * weird. I'm not sure there's an obvious right thing to do though.
2377 check_invariants (iter);
2383 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2386 return gtk_text_iter_backward_lines (iter, 0 - count);
2387 else if (count == 0)
2389 else if (count == 1)
2391 check_invariants (iter);
2392 return gtk_text_iter_forward_line (iter);
2398 old_line = gtk_text_iter_get_line (iter);
2400 gtk_text_iter_set_line (iter, old_line + count);
2402 check_invariants (iter);
2404 /* return whether it moved, and is dereferenceable. */
2406 (gtk_text_iter_get_line (iter) != old_line) &&
2407 !gtk_text_iter_is_last (iter);
2412 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2415 return gtk_text_iter_forward_lines (iter, 0 - count);
2416 else if (count == 0)
2418 else if (count == 1)
2420 return gtk_text_iter_backward_line (iter);
2426 old_line = gtk_text_iter_get_line (iter);
2428 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2430 return (gtk_text_iter_get_line (iter) != old_line);
2434 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2439 gboolean already_moved_initially);
2441 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2447 find_word_end_func (const PangoLogAttr *attrs,
2452 gboolean already_moved_initially)
2454 if (!already_moved_initially)
2457 /* Find end of next word */
2458 while (offset < min_offset + len &&
2459 !attrs[offset].is_word_end)
2462 *found_offset = offset;
2464 return offset < min_offset + len;
2468 is_word_end_func (const PangoLogAttr *attrs,
2473 return attrs[offset].is_word_end;
2477 find_word_start_func (const PangoLogAttr *attrs,
2482 gboolean already_moved_initially)
2484 if (!already_moved_initially)
2487 /* Find start of prev word */
2488 while (offset >= min_offset &&
2489 !attrs[offset].is_word_start)
2492 *found_offset = offset;
2494 return offset >= min_offset;
2498 is_word_start_func (const PangoLogAttr *attrs,
2503 return attrs[offset].is_word_start;
2507 inside_word_func (const PangoLogAttr *attrs,
2512 /* Find next word start or end */
2513 while (offset >= min_offset &&
2514 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2517 return attrs[offset].is_word_start;
2521 test_log_attrs (const GtkTextIter *iter,
2522 TestLogAttrFunc func)
2525 const PangoLogAttr *attrs;
2527 gboolean result = FALSE;
2529 g_return_val_if_fail (iter != NULL, FALSE);
2531 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2534 offset = gtk_text_iter_get_line_offset (iter);
2536 g_assert (char_len > 0);
2538 if (offset < char_len)
2539 result = (* func) (attrs, offset, 0, char_len);
2545 find_line_log_attrs (const GtkTextIter *iter,
2546 FindLogAttrFunc func,
2548 gboolean already_moved_initially)
2551 const PangoLogAttr *attrs;
2553 gboolean result = FALSE;
2555 g_return_val_if_fail (iter != NULL, FALSE);
2557 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2560 offset = gtk_text_iter_get_line_offset (iter);
2562 g_assert (char_len > 0);
2564 if (offset < char_len)
2565 result = (* func) (attrs, offset, 0, char_len, found_offset,
2566 already_moved_initially);
2571 /* FIXME this function is very, very gratuitously slow */
2573 find_by_log_attrs (GtkTextIter *iter,
2574 FindLogAttrFunc func,
2576 gboolean already_moved_initially)
2580 gboolean found = FALSE;
2582 g_return_val_if_fail (iter != NULL, FALSE);
2586 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2592 if (gtk_text_iter_forward_line (iter))
2593 return find_by_log_attrs (iter, func, forward,
2600 /* go to end of previous line */
2601 gtk_text_iter_set_line_offset (iter, 0);
2603 if (gtk_text_iter_backward_char (iter))
2604 return find_by_log_attrs (iter, func, forward,
2612 gtk_text_iter_set_line_offset (iter, offset);
2615 !gtk_text_iter_equal (iter, &orig) &&
2616 !gtk_text_iter_is_last (iter);
2621 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2623 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2627 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2629 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2632 /* FIXME a loop around a truly slow function means
2633 * a truly spectacularly slow function.
2636 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2639 g_return_val_if_fail (iter != NULL, FALSE);
2645 return gtk_text_iter_backward_word_starts (iter, -count);
2647 if (!gtk_text_iter_forward_word_end (iter))
2653 if (!gtk_text_iter_forward_word_end (iter))
2661 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2664 g_return_val_if_fail (iter != NULL, FALSE);
2667 return gtk_text_iter_forward_word_ends (iter, -count);
2669 if (!gtk_text_iter_backward_word_start (iter))
2675 if (!gtk_text_iter_backward_word_start (iter))
2684 gtk_text_iter_starts_word (const GtkTextIter *iter)
2686 return test_log_attrs (iter, is_word_start_func);
2690 gtk_text_iter_ends_word (const GtkTextIter *iter)
2692 return test_log_attrs (iter, is_word_end_func);
2696 gtk_text_iter_inside_word (const GtkTextIter *iter)
2698 return test_log_attrs (iter, inside_word_func);
2702 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
2707 gboolean already_moved_initially)
2709 if (!already_moved_initially)
2712 while (offset < (min_offset + len) &&
2713 !attrs[offset].is_cursor_position)
2716 *found_offset = offset;
2718 return offset < (min_offset + len);
2722 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
2727 gboolean already_moved_initially)
2729 if (!already_moved_initially)
2732 while (offset > min_offset &&
2733 !attrs[offset].is_cursor_position)
2736 *found_offset = offset;
2738 return offset >= min_offset;
2742 is_cursor_pos_func (const PangoLogAttr *attrs,
2747 return attrs[offset].is_cursor_position;
2751 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
2753 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
2757 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
2759 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
2763 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
2766 g_return_val_if_fail (iter != NULL, FALSE);
2772 return gtk_text_iter_backward_cursor_positions (iter, -count);
2774 if (!gtk_text_iter_forward_cursor_position (iter))
2780 if (!gtk_text_iter_forward_cursor_position (iter))
2788 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
2791 g_return_val_if_fail (iter != NULL, FALSE);
2797 return gtk_text_iter_forward_cursor_positions (iter, -count);
2799 if (!gtk_text_iter_backward_cursor_position (iter))
2805 if (!gtk_text_iter_backward_cursor_position (iter))
2813 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
2815 return test_log_attrs (iter, is_cursor_pos_func);
2819 gtk_text_iter_set_line_offset (GtkTextIter *iter,
2822 GtkTextRealIter *real;
2825 g_return_if_fail (iter != NULL);
2827 real = gtk_text_iter_make_surreal (iter);
2832 check_invariants (iter);
2834 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
2836 g_return_if_fail (char_on_line <= chars_in_line);
2838 if (char_on_line < chars_in_line)
2839 iter_set_from_char_offset (real, real->line, char_on_line);
2841 gtk_text_iter_forward_line (iter); /* set to start of next line */
2843 check_invariants (iter);
2847 gtk_text_iter_set_line_index (GtkTextIter *iter,
2850 GtkTextRealIter *real;
2853 g_return_if_fail (iter != NULL);
2855 real = gtk_text_iter_make_surreal (iter);
2860 check_invariants (iter);
2862 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
2864 g_return_if_fail (byte_on_line <= bytes_in_line);
2866 if (byte_on_line < bytes_in_line)
2867 iter_set_from_byte_offset (real, real->line, byte_on_line);
2869 gtk_text_iter_forward_line (iter);
2871 if (real->segment->type == >k_text_char_type &&
2872 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
2873 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
2874 "character; this will crash the text buffer. "
2875 "Byte indexes must refer to the start of a character.",
2876 G_STRLOC, byte_on_line);
2878 check_invariants (iter);
2882 gtk_text_iter_set_line (GtkTextIter *iter,
2887 GtkTextRealIter *real;
2889 g_return_if_fail (iter != NULL);
2891 real = gtk_text_iter_make_surreal (iter);
2896 check_invariants (iter);
2898 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
2900 iter_set_from_char_offset (real, line, 0);
2902 /* We might as well cache this, since we know it. */
2903 real->cached_line_number = real_line;
2905 check_invariants (iter);
2909 gtk_text_iter_set_offset (GtkTextIter *iter, gint char_index)
2912 GtkTextRealIter *real;
2914 gint real_char_index;
2916 g_return_if_fail (iter != NULL);
2918 real = gtk_text_iter_make_surreal (iter);
2923 check_invariants (iter);
2925 if (real->cached_char_index >= 0 &&
2926 real->cached_char_index == char_index)
2929 line = _gtk_text_btree_get_line_at_char (real->tree,
2934 iter_set_from_char_offset (real, line, real_char_index - line_start);
2936 /* Go ahead and cache this since we have it. */
2937 real->cached_char_index = real_char_index;
2939 check_invariants (iter);
2943 gtk_text_iter_forward_to_end (GtkTextIter *iter)
2945 GtkTextBuffer *buffer;
2946 GtkTextRealIter *real;
2948 g_return_if_fail (iter != NULL);
2950 real = gtk_text_iter_make_surreal (iter);
2955 buffer = _gtk_text_btree_get_buffer (real->tree);
2957 gtk_text_buffer_get_last_iter (buffer, iter);
2961 * gtk_text_iter_forward_to_delimiters:
2962 * @iter: a #GtkTextIter
2964 * Moves the iterator to point to the paragraph delimiter characters,
2965 * which will be either a newline, a carriage return, a carriage
2966 * return/newline in sequence, or the Unicode paragraph separator
2967 * character. If the iterator is already at the paragraph delimiter
2968 * characters, moves to the paragraph delimiter characters for the
2971 * Return value: %TRUE if we moved and the new location is not the end iterator
2974 gtk_text_iter_forward_to_delimiters (GtkTextIter *iter)
2976 gint current_offset;
2979 g_return_val_if_fail (iter != NULL, FALSE);
2981 current_offset = gtk_text_iter_get_line_offset (iter);
2982 /* FIXME assumption that line ends in a newline; broken */
2983 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
2985 if (current_offset < new_offset)
2987 /* Move to end of this line. */
2988 gtk_text_iter_set_line_offset (iter, new_offset);
2993 /* Move to end of next line. */
2994 if (gtk_text_iter_forward_line (iter))
2996 /* We don't want to move past all
2999 if (!gtk_text_iter_ends_line (iter))
3000 gtk_text_iter_forward_to_delimiters (iter);
3009 * gtk_text_iter_forward_to_tag_toggle:
3010 * @iter: a #GtkTextIter
3011 * @tag: a #GtkTextTag, or NULL
3013 * Moves forward to the next toggle (on or off) of the
3014 * #GtkTextTag @tag, or to the next toggle of any tag if
3015 * @tag is NULL. If no matching tag toggles are found,
3016 * returns FALSE, otherwise TRUE. Does not return toggles
3017 * located at @iter, only toggles after @iter. Sets @iter to
3018 * the location of the toggle, or to the end of the buffer
3019 * if no toggle is found.
3021 * Return value: whether we found a tag toggle after @iter
3024 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3027 GtkTextLine *next_line;
3028 GtkTextLine *current_line;
3029 GtkTextRealIter *real;
3031 g_return_val_if_fail (iter != NULL, FALSE);
3033 real = gtk_text_iter_make_real (iter);
3038 check_invariants (iter);
3040 current_line = real->line;
3041 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3044 while (_gtk_text_iter_forward_indexable_segment (iter))
3046 /* If we went forward to a line that couldn't contain a toggle
3047 for the tag, then skip forward to a line that could contain
3048 it. This potentially skips huge hunks of the tree, so we
3049 aren't a purely linear search. */
3050 if (real->line != current_line)
3052 if (next_line == NULL)
3054 /* End of search. Set to end of buffer. */
3055 _gtk_text_btree_get_last_iter (real->tree, iter);
3059 if (real->line != next_line)
3060 iter_set_from_byte_offset (real, next_line, 0);
3062 current_line = real->line;
3063 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3068 if (gtk_text_iter_toggles_tag (iter, tag))
3070 /* If there's a toggle here, it isn't indexable so
3071 any_segment can't be the indexable segment. */
3072 g_assert (real->any_segment != real->segment);
3077 /* Check end iterator for tags */
3078 if (gtk_text_iter_toggles_tag (iter, tag))
3080 /* If there's a toggle here, it isn't indexable so
3081 any_segment can't be the indexable segment. */
3082 g_assert (real->any_segment != real->segment);
3086 /* Reached end of buffer */
3091 * gtk_text_iter_backward_to_tag_toggle:
3092 * @iter: a #GtkTextIter
3093 * @tag: a #GtkTextTag, or NULL
3095 * Moves backward to the next toggle (on or off) of the
3096 * #GtkTextTag @tag, or to the next toggle of any tag if
3097 * @tag is NULL. If no matching tag toggles are found,
3098 * returns FALSE, otherwise TRUE. Does not return toggles
3099 * located at @iter, only toggles before @iter. Sets @iter
3100 * to the location of the toggle, or the start of the buffer
3101 * if no toggle is found.
3103 * Return value: whether we found a tag toggle before @iter
3106 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3109 GtkTextLine *prev_line;
3110 GtkTextLine *current_line;
3111 GtkTextRealIter *real;
3113 g_return_val_if_fail (iter != NULL, FALSE);
3115 real = gtk_text_iter_make_real (iter);
3120 check_invariants (iter);
3122 current_line = real->line;
3123 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3127 /* If we're at segment start, go to the previous segment;
3128 * if mid-segment, snap to start of current segment.
3130 if (is_segment_start (real))
3132 if (!_gtk_text_iter_backward_indexable_segment (iter))
3137 ensure_char_offsets (real);
3139 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3145 /* If we went backward to a line that couldn't contain a toggle
3146 * for the tag, then skip backward further to a line that
3147 * could contain it. This potentially skips huge hunks of the
3148 * tree, so we aren't a purely linear search.
3150 if (real->line != current_line)
3152 if (prev_line == NULL)
3154 /* End of search. Set to start of buffer. */
3155 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3159 if (real->line != prev_line)
3161 /* Set to last segment in prev_line (could do this
3164 iter_set_from_byte_offset (real, prev_line, 0);
3166 while (!at_last_indexable_segment (real))
3167 _gtk_text_iter_forward_indexable_segment (iter);
3170 current_line = real->line;
3171 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3176 if (gtk_text_iter_toggles_tag (iter, tag))
3178 /* If there's a toggle here, it isn't indexable so
3179 * any_segment can't be the indexable segment.
3181 g_assert (real->any_segment != real->segment);
3185 while (_gtk_text_iter_backward_indexable_segment (iter));
3187 /* Reached front of buffer */
3192 matches_pred (GtkTextIter *iter,
3193 GtkTextCharPredicate pred,
3198 ch = gtk_text_iter_get_char (iter);
3200 return (*pred) (ch, user_data);
3204 * gtk_text_iter_forward_find_char:
3205 * @iter: a #GtkTextIter
3206 * @pred: a function to be called on each character
3207 * @user_data: user data for @pred
3208 * @limit: search limit, or %NULL for none
3210 * Advances @iter, calling @pred on each character. If
3211 * @pred returns %TRUE, returns %TRUE and stops scanning.
3212 * If @pred never returns %TRUE, @iter is set to @limit if
3213 * @limit is non-%NULL, otherwise to the end iterator.
3215 * Return value: whether a match was found
3218 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3219 GtkTextCharPredicate pred,
3221 const GtkTextIter *limit)
3223 g_return_val_if_fail (iter != NULL, FALSE);
3224 g_return_val_if_fail (pred != NULL, FALSE);
3227 gtk_text_iter_compare (iter, limit) >= 0)
3230 while ((limit == NULL ||
3231 !gtk_text_iter_equal (limit, iter)) &&
3232 gtk_text_iter_forward_char (iter))
3234 if (matches_pred (iter, pred, user_data))
3242 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3243 GtkTextCharPredicate pred,
3245 const GtkTextIter *limit)
3247 g_return_val_if_fail (iter != NULL, FALSE);
3248 g_return_val_if_fail (pred != NULL, FALSE);
3251 gtk_text_iter_compare (iter, limit) <= 0)
3254 while ((limit == NULL ||
3255 !gtk_text_iter_equal (limit, iter)) &&
3256 gtk_text_iter_backward_char (iter))
3258 if (matches_pred (iter, pred, user_data))
3266 forward_chars_with_skipping (GtkTextIter *iter,
3268 gboolean skip_invisible,
3269 gboolean skip_nontext)
3274 g_return_if_fail (count >= 0);
3280 gboolean ignored = FALSE;
3283 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3288 _gtk_text_btree_char_is_invisible (iter))
3291 gtk_text_iter_forward_char (iter);
3299 lines_match (const GtkTextIter *start,
3300 const gchar **lines,
3301 gboolean visible_only,
3303 GtkTextIter *match_start,
3304 GtkTextIter *match_end)
3311 if (*lines == NULL || **lines == '\0')
3314 *match_start = *start;
3317 *match_end = *start;
3322 gtk_text_iter_forward_line (&next);
3324 /* No more text in buffer, but *lines is nonempty */
3325 if (gtk_text_iter_equal (start, &next))
3333 line_text = gtk_text_iter_get_visible_slice (start, &next);
3335 line_text = gtk_text_iter_get_slice (start, &next);
3340 line_text = gtk_text_iter_get_visible_text (start, &next);
3342 line_text = gtk_text_iter_get_text (start, &next);
3345 if (match_start) /* if this is the first line we're matching */
3346 found = strstr (line_text, *lines);
3349 /* If it's not the first line, we have to match from the
3350 * start of the line.
3352 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
3364 /* Get offset to start of search string */
3365 offset = g_utf8_strlen (line_text, found - line_text);
3369 /* If match start needs to be returned, set it to the
3370 * start of the search string.
3374 *match_start = next;
3376 forward_chars_with_skipping (match_start, offset,
3377 visible_only, !slice);
3380 /* Go to end of search string */
3381 offset += g_utf8_strlen (*lines, -1);
3383 forward_chars_with_skipping (&next, offset,
3384 visible_only, !slice);
3393 /* pass NULL for match_start, since we don't need to find the
3396 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
3399 /* strsplit () that retains the delimiter as part of the string. */
3401 strbreakup (const char *string,
3402 const char *delimiter,
3405 GSList *string_list = NULL, *slist;
3406 gchar **str_array, *s;
3409 g_return_val_if_fail (string != NULL, NULL);
3410 g_return_val_if_fail (delimiter != NULL, NULL);
3413 max_tokens = G_MAXINT;
3415 s = strstr (string, delimiter);
3418 guint delimiter_len = strlen (delimiter);
3425 len = s - string + delimiter_len;
3426 new_string = g_new (gchar, len + 1);
3427 strncpy (new_string, string, len);
3428 new_string[len] = 0;
3429 string_list = g_slist_prepend (string_list, new_string);
3431 string = s + delimiter_len;
3432 s = strstr (string, delimiter);
3434 while (--max_tokens && s);
3439 string_list = g_slist_prepend (string_list, g_strdup (string));
3442 str_array = g_new (gchar*, n);
3446 str_array[i--] = NULL;
3447 for (slist = string_list; slist; slist = slist->next)
3448 str_array[i--] = slist->data;
3450 g_slist_free (string_list);
3456 * gtk_text_iter_forward_search:
3457 * @iter: start of search
3458 * @str: a search string
3459 * @visible_only: if %TRUE, search only visible text
3460 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
3461 * @match_start: return location for start of match, or %NULL
3462 * @match_end: return location for end of match, or %NULL
3463 * @limit: bound for the search, or %NULL for the end of the buffer
3467 * Return value: whether a match was found
3470 gtk_text_iter_forward_search (const GtkTextIter *iter,
3472 gboolean visible_only,
3474 GtkTextIter *match_start,
3475 GtkTextIter *match_end,
3476 const GtkTextIter *limit)
3478 gchar **lines = NULL;
3480 gboolean retval = FALSE;
3483 g_return_val_if_fail (iter != NULL, FALSE);
3484 g_return_val_if_fail (str != NULL, FALSE);
3487 gtk_text_iter_compare (iter, limit) >= 0)
3492 /* If we can move one char, return the empty string there */
3495 if (gtk_text_iter_forward_char (&match))
3498 gtk_text_iter_equal (&match, limit))
3502 *match_start = match;
3511 /* locate all lines */
3513 lines = strbreakup (str, "\n", -1);
3519 /* This loop has an inefficient worst-case, where
3520 * gtk_text_iter_get_text () is called repeatedly on
3526 gtk_text_iter_compare (&search, limit) >= 0)
3529 if (lines_match (&search, (const gchar**)lines,
3530 visible_only, slice, &match, &end))
3532 if (limit == NULL ||
3534 gtk_text_iter_compare (&end, limit) < 0))
3539 *match_start = match;
3548 while (gtk_text_iter_forward_line (&search));
3550 g_strfreev ((gchar**)lines);
3556 vectors_equal_ignoring_trailing (gchar **vec1,
3559 /* Ignores trailing chars in vec2's last line */
3568 if (strcmp (*i1, *i2) != 0)
3570 if (*(i2 + 1) == NULL) /* if this is the last line */
3572 gint len1 = strlen (*i1);
3573 gint len2 = strlen (*i2);
3576 strncmp (*i1, *i2, len1) == 0)
3578 /* We matched ignoring the trailing stuff in vec2 */
3603 typedef struct _LinesWindow LinesWindow;
3609 GtkTextIter first_line_start;
3610 GtkTextIter first_line_end;
3612 gboolean visible_only;
3616 lines_window_init (LinesWindow *win,
3617 const GtkTextIter *start)
3620 GtkTextIter line_start;
3621 GtkTextIter line_end;
3623 /* If we start on line 1, there are 2 lines to search (0 and 1), so
3626 if (gtk_text_iter_is_first (start) ||
3627 gtk_text_iter_get_line (start) + 1 < win->n_lines)
3629 /* Already at the end, or not enough lines to match */
3630 win->lines = g_new0 (gchar*, 1);
3635 line_start = *start;
3638 /* Move to start iter to start of line */
3639 gtk_text_iter_set_line_offset (&line_start, 0);
3641 if (gtk_text_iter_equal (&line_start, &line_end))
3643 /* we were already at the start; so go back one line */
3644 gtk_text_iter_backward_line (&line_start);
3647 win->first_line_start = line_start;
3648 win->first_line_end = line_end;
3650 win->lines = g_new0 (gchar*, win->n_lines + 1);
3652 i = win->n_lines - 1;
3659 if (win->visible_only)
3660 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
3662 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
3666 if (win->visible_only)
3667 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
3669 line_text = gtk_text_iter_get_text (&line_start, &line_end);
3672 win->lines[i] = line_text;
3674 line_end = line_start;
3675 gtk_text_iter_backward_line (&line_start);
3682 lines_window_back (LinesWindow *win)
3684 GtkTextIter new_start;
3687 new_start = win->first_line_start;
3689 if (!gtk_text_iter_backward_line (&new_start))
3693 win->first_line_start = new_start;
3694 win->first_line_end = new_start;
3696 gtk_text_iter_forward_line (&win->first_line_end);
3701 if (win->visible_only)
3702 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
3703 &win->first_line_end);
3705 line_text = gtk_text_iter_get_slice (&win->first_line_start,
3706 &win->first_line_end);
3710 if (win->visible_only)
3711 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
3712 &win->first_line_end);
3714 line_text = gtk_text_iter_get_text (&win->first_line_start,
3715 &win->first_line_end);
3718 /* Move lines to make room for first line. */
3719 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
3721 *win->lines = line_text;
3723 /* Free old last line and NULL-terminate */
3724 g_free (win->lines[win->n_lines]);
3725 win->lines[win->n_lines] = NULL;
3731 lines_window_free (LinesWindow *win)
3733 g_strfreev (win->lines);
3737 my_strrstr (const gchar *haystack,
3738 const gchar *needle)
3740 /* FIXME GLib should have a nice implementation in it, this
3744 gint haystack_len = strlen (haystack);
3745 gint needle_len = strlen (needle);
3746 const gchar *needle_end = needle + needle_len;
3747 const gchar *haystack_rend = haystack - 1;
3748 const gchar *needle_rend = needle - 1;
3751 p = haystack + haystack_len;
3752 while (p != haystack)
3754 const gchar *n = needle_end - 1;
3755 const gchar *s = p - 1;
3756 while (s != haystack_rend &&
3764 if (n == needle_rend)
3774 * gtk_text_iter_backward_search:
3775 * @iter: a #GtkTextIter where the search begins
3776 * @str: search string
3777 * @visible_only: if %TRUE search only visible text
3778 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
3779 * @match_start: return location for start of match, or %NULL
3780 * @match_end: return location for end of match, or %NULL
3781 * @limit: location of last possible @match_start, or %NULL for start of buffer
3785 * Return value: whether a match was found
3788 gtk_text_iter_backward_search (const GtkTextIter *iter,
3790 gboolean visible_only,
3792 GtkTextIter *match_start,
3793 GtkTextIter *match_end,
3794 const GtkTextIter *limit)
3796 gchar **lines = NULL;
3800 gboolean retval = FALSE;
3802 g_return_val_if_fail (iter != NULL, FALSE);
3803 g_return_val_if_fail (str != NULL, FALSE);
3806 gtk_text_iter_compare (limit, iter) > 0)
3811 /* If we can move one char, return the empty string there */
3812 GtkTextIter match = *iter;
3814 if (limit && gtk_text_iter_equal (limit, &match))
3817 if (gtk_text_iter_backward_char (&match))
3820 *match_start = match;
3829 /* locate all lines */
3831 lines = strbreakup (str, "\n", -1);
3841 win.n_lines = n_lines;
3843 win.visible_only = visible_only;
3845 lines_window_init (&win, iter);
3847 if (*win.lines == NULL)
3852 gchar *first_line_match;
3855 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
3857 /* We're now before the search limit, abort. */
3861 /* If there are multiple lines, the first line will
3862 * end in '\n', so this will only match at the
3863 * end of the first line, which is correct.
3865 first_line_match = my_strrstr (*win.lines, *lines);
3867 if (first_line_match &&
3868 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
3873 GtkTextIter start_tmp;
3875 /* Offset to start of search string */
3876 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
3878 next = win.first_line_start;
3880 forward_chars_with_skipping (&start_tmp, offset,
3881 visible_only, !slice);
3884 gtk_text_iter_compare (limit, &start_tmp) > 0)
3885 goto out; /* match was bogus */
3888 *match_start = start_tmp;
3890 /* Go to end of search string */
3894 offset += g_utf8_strlen (*l, -1);
3898 forward_chars_with_skipping (&next, offset,
3899 visible_only, !slice);
3908 while (lines_window_back (&win));
3911 lines_window_free (&win);
3922 gtk_text_iter_equal (const GtkTextIter *lhs,
3923 const GtkTextIter *rhs)
3925 GtkTextRealIter *real_lhs;
3926 GtkTextRealIter *real_rhs;
3928 real_lhs = (GtkTextRealIter*)lhs;
3929 real_rhs = (GtkTextRealIter*)rhs;
3931 check_invariants (lhs);
3932 check_invariants (rhs);
3934 if (real_lhs->line != real_rhs->line)
3936 else if (real_lhs->line_byte_offset >= 0 &&
3937 real_rhs->line_byte_offset >= 0)
3938 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
3941 /* the ensure_char_offsets () calls do nothing if the char offsets
3942 are already up-to-date. */
3943 ensure_char_offsets (real_lhs);
3944 ensure_char_offsets (real_rhs);
3945 return real_lhs->line_char_offset == real_rhs->line_char_offset;
3950 gtk_text_iter_compare (const GtkTextIter *lhs, const GtkTextIter *rhs)
3952 GtkTextRealIter *real_lhs;
3953 GtkTextRealIter *real_rhs;
3955 real_lhs = gtk_text_iter_make_surreal (lhs);
3956 real_rhs = gtk_text_iter_make_surreal (rhs);
3958 check_invariants (lhs);
3959 check_invariants (rhs);
3961 if (real_lhs == NULL ||
3963 return -1; /* why not */
3965 if (real_lhs->line == real_rhs->line)
3967 gint left_index, right_index;
3969 if (real_lhs->line_byte_offset >= 0 &&
3970 real_rhs->line_byte_offset >= 0)
3972 left_index = real_lhs->line_byte_offset;
3973 right_index = real_rhs->line_byte_offset;
3977 /* the ensure_char_offsets () calls do nothing if
3978 the offsets are already up-to-date. */
3979 ensure_char_offsets (real_lhs);
3980 ensure_char_offsets (real_rhs);
3981 left_index = real_lhs->line_char_offset;
3982 right_index = real_rhs->line_char_offset;
3985 if (left_index < right_index)
3987 else if (left_index > right_index)
3996 line1 = gtk_text_iter_get_line (lhs);
3997 line2 = gtk_text_iter_get_line (rhs);
4000 else if (line1 > line2)
4008 gtk_text_iter_in_range (const GtkTextIter *iter,
4009 const GtkTextIter *start,
4010 const GtkTextIter *end)
4012 return gtk_text_iter_compare (iter, start) >= 0 &&
4013 gtk_text_iter_compare (iter, end) < 0;
4017 gtk_text_iter_reorder (GtkTextIter *first,
4018 GtkTextIter *second)
4020 g_return_if_fail (first != NULL);
4021 g_return_if_fail (second != NULL);
4023 if (gtk_text_iter_compare (first, second) > 0)
4034 * Init iterators from the BTree
4038 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4042 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4043 gint real_char_index;
4047 g_return_if_fail (iter != NULL);
4048 g_return_if_fail (tree != NULL);
4050 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4051 &line_start, &real_char_index);
4053 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4055 real->cached_char_index = real_char_index;
4057 check_invariants (iter);
4061 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4066 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4070 g_return_if_fail (iter != NULL);
4071 g_return_if_fail (tree != NULL);
4073 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4075 iter_init_from_char_offset (iter, tree, line, char_on_line);
4077 /* We might as well cache this, since we know it. */
4078 real->cached_line_number = real_line;
4080 check_invariants (iter);
4084 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4089 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4093 g_return_if_fail (iter != NULL);
4094 g_return_if_fail (tree != NULL);
4096 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4098 iter_init_from_byte_offset (iter, tree, line, byte_index);
4100 /* We might as well cache this, since we know it. */
4101 real->cached_line_number = real_line;
4103 if (real->segment->type == >k_text_char_type &&
4104 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
4105 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
4106 "character; this will crash the text buffer. "
4107 "Byte indexes must refer to the start of a character.",
4108 G_STRLOC, byte_index);
4110 check_invariants (iter);
4114 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4119 g_return_if_fail (iter != NULL);
4120 g_return_if_fail (tree != NULL);
4121 g_return_if_fail (line != NULL);
4123 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4125 check_invariants (iter);
4129 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4135 g_return_val_if_fail (iter != NULL, FALSE);
4136 g_return_val_if_fail (tree != NULL, FALSE);
4138 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4142 /* Set iter to last in tree */
4143 _gtk_text_btree_get_last_iter (tree, iter);
4144 check_invariants (iter);
4149 iter_init_from_byte_offset (iter, tree, line, 0);
4150 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4151 check_invariants (iter);
4157 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4163 g_return_val_if_fail (iter != NULL, FALSE);
4164 g_return_val_if_fail (tree != NULL, FALSE);
4166 line = _gtk_text_btree_last_could_contain_tag (tree, tag);
4170 /* Set iter to first in tree */
4171 _gtk_text_btree_get_iter_at_line_char (tree, iter, 0, 0);
4172 check_invariants (iter);
4177 iter_init_from_byte_offset (iter, tree, line, -1);
4178 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4179 check_invariants (iter);
4185 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4187 const gchar *mark_name)
4191 g_return_val_if_fail (iter != NULL, FALSE);
4192 g_return_val_if_fail (tree != NULL, FALSE);
4194 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4200 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4201 check_invariants (iter);
4207 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4211 GtkTextLineSegment *seg;
4213 g_return_if_fail (iter != NULL);
4214 g_return_if_fail (tree != NULL);
4215 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4217 seg = mark->segment;
4219 iter_init_from_segment (iter, tree,
4220 seg->body.mark.line, seg);
4221 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4222 check_invariants (iter);
4226 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4228 GtkTextChildAnchor *anchor)
4230 GtkTextLineSegment *seg;
4232 g_return_if_fail (iter != NULL);
4233 g_return_if_fail (tree != NULL);
4234 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4236 seg = anchor->segment;
4238 iter_init_from_segment (iter, tree,
4239 seg->body.child.line, seg);
4240 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4241 check_invariants (iter);
4245 _gtk_text_btree_get_last_iter (GtkTextBTree *tree,
4248 g_return_if_fail (iter != NULL);
4249 g_return_if_fail (tree != NULL);
4251 _gtk_text_btree_get_iter_at_char (tree,
4253 _gtk_text_btree_char_count (tree));
4254 check_invariants (iter);
4258 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
4260 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4262 g_return_if_fail (iter != NULL);
4264 if (real->chars_changed_stamp != _gtk_text_btree_get_chars_changed_stamp (real->tree))
4265 g_print (" %20s: <invalidated iterator>\n", desc);
4268 check_invariants (iter);
4269 g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
4271 gtk_text_iter_get_line (iter),
4272 gtk_text_iter_get_offset (iter),
4273 gtk_text_iter_get_line_offset (iter),
4274 gtk_text_iter_get_line_index (iter));
4275 check_invariants (iter);
4280 _gtk_text_iter_check (const GtkTextIter *iter)
4282 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
4283 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
4284 GtkTextLineSegment *byte_segment = NULL;
4285 GtkTextLineSegment *byte_any_segment = NULL;
4286 GtkTextLineSegment *char_segment = NULL;
4287 GtkTextLineSegment *char_any_segment = NULL;
4288 gboolean segments_updated;
4290 /* This function checks our class invariants for the Iter class. */
4292 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
4294 if (real->chars_changed_stamp !=
4295 _gtk_text_btree_get_chars_changed_stamp (real->tree))
4296 g_error ("iterator check failed: invalid iterator");
4298 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
4299 g_error ("iterator check failed: both char and byte offsets are invalid");
4301 segments_updated = (real->segments_changed_stamp ==
4302 _gtk_text_btree_get_segments_changed_stamp (real->tree));
4305 printf ("checking iter, segments %s updated, byte %d char %d\n",
4306 segments_updated ? "are" : "aren't",
4307 real->line_byte_offset,
4308 real->line_char_offset);
4311 if (segments_updated)
4313 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
4314 g_error ("iterator check failed: both char and byte segment offsets are invalid");
4316 if (real->segment->char_count == 0)
4317 g_error ("iterator check failed: segment is not indexable.");
4319 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
4320 g_error ("segment char offset is not properly up-to-date");
4322 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
4323 g_error ("segment byte offset is not properly up-to-date");
4325 if (real->segment_byte_offset >= 0 &&
4326 real->segment_byte_offset >= real->segment->byte_count)
4327 g_error ("segment byte offset is too large.");
4329 if (real->segment_char_offset >= 0 &&
4330 real->segment_char_offset >= real->segment->char_count)
4331 g_error ("segment char offset is too large.");
4334 if (real->line_byte_offset >= 0)
4336 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
4337 &byte_segment, &byte_any_segment,
4338 &seg_byte_offset, &line_byte_offset);
4340 if (line_byte_offset != real->line_byte_offset)
4341 g_error ("wrong byte offset was stored in iterator");
4343 if (segments_updated)
4345 if (real->segment != byte_segment)
4346 g_error ("wrong segment was stored in iterator");
4348 if (real->any_segment != byte_any_segment)
4349 g_error ("wrong any_segment was stored in iterator");
4351 if (seg_byte_offset != real->segment_byte_offset)
4352 g_error ("wrong segment byte offset was stored in iterator");
4354 if (byte_segment->type == >k_text_char_type)
4357 p = byte_segment->body.chars + seg_byte_offset;
4359 if (!gtk_text_byte_begins_utf8_char (p))
4360 g_error ("broken iterator byte index pointed into the middle of a character");
4365 if (real->line_char_offset >= 0)
4367 _gtk_text_line_char_locate (real->line, real->line_char_offset,
4368 &char_segment, &char_any_segment,
4369 &seg_char_offset, &line_char_offset);
4371 if (line_char_offset != real->line_char_offset)
4372 g_error ("wrong char offset was stored in iterator");
4374 if (segments_updated)
4376 if (real->segment != char_segment)
4377 g_error ("wrong segment was stored in iterator");
4379 if (real->any_segment != char_any_segment)
4380 g_error ("wrong any_segment was stored in iterator");
4382 if (seg_char_offset != real->segment_char_offset)
4383 g_error ("wrong segment char offset was stored in iterator");
4385 if (char_segment->type == >k_text_char_type)
4388 p = g_utf8_offset_to_pointer (char_segment->body.chars,
4391 /* hmm, not likely to happen eh */
4392 if (!gtk_text_byte_begins_utf8_char (p))
4393 g_error ("broken iterator char offset pointed into the middle of a character");
4398 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
4400 if (byte_segment != char_segment)
4401 g_error ("char and byte offsets did not point to the same segment");
4403 if (byte_any_segment != char_any_segment)
4404 g_error ("char and byte offsets did not point to the same any segment");
4406 /* Make sure the segment offsets are equivalent, if it's a char
4408 if (char_segment->type == >k_text_char_type)
4410 gint byte_offset = 0;
4411 gint char_offset = 0;
4412 while (char_offset < seg_char_offset)
4414 const char * start = char_segment->body.chars + byte_offset;
4415 byte_offset += g_utf8_next_char (start) - start;
4419 if (byte_offset != seg_byte_offset)
4420 g_error ("byte offset did not correspond to char offset");
4423 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
4425 if (char_offset != seg_char_offset)
4426 g_error ("char offset did not correspond to byte offset");
4428 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
4429 g_error ("byte index for iterator does not index the start of a character");
4433 if (real->cached_line_number >= 0)
4437 should_be = _gtk_text_line_get_number (real->line);
4438 if (real->cached_line_number != should_be)
4439 g_error ("wrong line number was cached");
4442 if (real->cached_char_index >= 0)
4444 if (real->line_char_offset >= 0) /* only way we can check it
4445 efficiently, not a real
4450 char_index = _gtk_text_line_char_index (real->line);
4451 char_index += real->line_char_offset;
4453 if (real->cached_char_index != char_index)
4454 g_error ("wrong char index was cached");