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 if (!_gtk_text_line_byte_locate (iter->line,
99 &iter->segment_byte_offset,
100 &iter->line_byte_offset))
101 g_error ("Byte index %d is off the end of the line",
106 iter_set_from_char_offset (GtkTextRealIter *iter,
110 iter_set_common (iter, line);
112 if (!_gtk_text_line_char_locate (iter->line,
116 &iter->segment_char_offset,
117 &iter->line_char_offset))
118 g_error ("Char offset %d is off the end of the line",
123 iter_set_from_segment (GtkTextRealIter *iter,
125 GtkTextLineSegment *segment)
127 GtkTextLineSegment *seg;
130 /* This could theoretically be optimized by computing all the iter
131 fields in this same loop, but I'm skipping it for now. */
133 seg = line->segments;
134 while (seg != segment)
136 byte_offset += seg->byte_count;
140 iter_set_from_byte_offset (iter, line, byte_offset);
143 /* This function ensures that the segment-dependent information is
144 truly computed lazily; often we don't need to do the full make_real
145 work. This ensures the btree and line are valid, but doesn't
146 update the segments. */
147 static GtkTextRealIter*
148 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
150 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
152 if (iter->chars_changed_stamp !=
153 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
155 g_warning ("Invalid text buffer iterator: either the iterator "
156 "is uninitialized, or the characters/pixbufs/widgets "
157 "in the buffer have been modified since the iterator "
158 "was created.\nYou must use marks, character numbers, "
159 "or line numbers to preserve a position across buffer "
160 "modifications.\nYou can apply tags and insert marks "
161 "without invalidating your iterators,\n"
162 "but any mutation that affects 'indexable' buffer contents "
163 "(contents that can be referred to by character offset)\n"
164 "will invalidate all outstanding iterators");
168 /* We don't update the segments information since we are becoming
169 only surreal. However we do invalidate the segments information
170 if appropriate, to be sure we segfault if we try to use it and we
171 should have used make_real. */
173 if (iter->segments_changed_stamp !=
174 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
176 iter->segment = NULL;
177 iter->any_segment = NULL;
178 /* set to segfault-causing values. */
179 iter->segment_byte_offset = -10000;
180 iter->segment_char_offset = -10000;
186 static GtkTextRealIter*
187 gtk_text_iter_make_real (const GtkTextIter *_iter)
189 GtkTextRealIter *iter;
191 iter = gtk_text_iter_make_surreal (_iter);
193 if (iter->segments_changed_stamp !=
194 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
196 if (iter->line_byte_offset >= 0)
198 iter_set_from_byte_offset (iter,
200 iter->line_byte_offset);
204 g_assert (iter->line_char_offset >= 0);
206 iter_set_from_char_offset (iter,
208 iter->line_char_offset);
212 g_assert (iter->segment != NULL);
213 g_assert (iter->any_segment != NULL);
214 g_assert (iter->segment->char_count > 0);
219 static GtkTextRealIter*
220 iter_init_common (GtkTextIter *_iter,
223 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
225 g_return_val_if_fail (iter != NULL, NULL);
226 g_return_val_if_fail (tree != NULL, NULL);
230 iter->chars_changed_stamp =
231 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
236 static GtkTextRealIter*
237 iter_init_from_segment (GtkTextIter *iter,
240 GtkTextLineSegment *segment)
242 GtkTextRealIter *real;
244 g_return_val_if_fail (line != NULL, NULL);
246 real = iter_init_common (iter, tree);
248 iter_set_from_segment (real, line, segment);
253 static GtkTextRealIter*
254 iter_init_from_byte_offset (GtkTextIter *iter,
257 gint line_byte_offset)
259 GtkTextRealIter *real;
261 g_return_val_if_fail (line != NULL, NULL);
263 real = iter_init_common (iter, tree);
265 iter_set_from_byte_offset (real, line, line_byte_offset);
267 if (real->segment->type == >k_text_char_type &&
268 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
269 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
270 "character; this will crash the text buffer. "
271 "Byte indexes must refer to the start of a character.",
277 static GtkTextRealIter*
278 iter_init_from_char_offset (GtkTextIter *iter,
281 gint line_char_offset)
283 GtkTextRealIter *real;
285 g_return_val_if_fail (line != NULL, NULL);
287 real = iter_init_common (iter, tree);
289 iter_set_from_char_offset (real, line, line_char_offset);
295 invalidate_segment (GtkTextRealIter *iter)
297 iter->segments_changed_stamp -= 1;
301 invalidate_char_index (GtkTextRealIter *iter)
303 iter->cached_char_index = -1;
307 invalidate_line_number (GtkTextRealIter *iter)
309 iter->cached_line_number = -1;
313 adjust_char_index (GtkTextRealIter *iter, gint count)
315 if (iter->cached_char_index >= 0)
316 iter->cached_char_index += count;
320 adjust_line_number (GtkTextRealIter *iter, gint count)
322 if (iter->cached_line_number >= 0)
323 iter->cached_line_number += count;
327 adjust_char_offsets (GtkTextRealIter *iter, gint count)
329 if (iter->line_char_offset >= 0)
331 iter->line_char_offset += count;
332 g_assert (iter->segment_char_offset >= 0);
333 iter->segment_char_offset += count;
338 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
340 if (iter->line_byte_offset >= 0)
342 iter->line_byte_offset += count;
343 g_assert (iter->segment_byte_offset >= 0);
344 iter->segment_byte_offset += count;
349 ensure_char_offsets (GtkTextRealIter *iter)
351 if (iter->line_char_offset < 0)
353 g_assert (iter->line_byte_offset >= 0);
355 _gtk_text_line_byte_to_char_offsets (iter->line,
356 iter->line_byte_offset,
357 &iter->line_char_offset,
358 &iter->segment_char_offset);
363 ensure_byte_offsets (GtkTextRealIter *iter)
365 if (iter->line_byte_offset < 0)
367 g_assert (iter->line_char_offset >= 0);
369 _gtk_text_line_char_to_byte_offsets (iter->line,
370 iter->line_char_offset,
371 &iter->line_byte_offset,
372 &iter->segment_byte_offset);
376 static inline gboolean
377 is_segment_start (GtkTextRealIter *real)
379 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
384 check_invariants (const GtkTextIter *iter)
386 if (gtk_debug_flags & GTK_DEBUG_TEXT)
387 _gtk_text_iter_check (iter);
390 #define check_invariants (x)
394 * gtk_text_iter_get_buffer:
397 * Return the #GtkTextBuffer this iterator is associated with
399 * Return value: the buffer
402 gtk_text_iter_get_buffer (const GtkTextIter *iter)
404 GtkTextRealIter *real;
406 g_return_val_if_fail (iter != NULL, NULL);
408 real = gtk_text_iter_make_surreal (iter);
413 check_invariants (iter);
415 return _gtk_text_btree_get_buffer (real->tree);
419 * gtk_text_iter_copy:
422 * Create a dynamically-allocated copy of an iterator. This function
423 * is not useful in applications, because iterators can be copied with a
424 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
425 * function is used by language bindings.
427 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
430 gtk_text_iter_copy (const GtkTextIter *iter)
432 GtkTextIter *new_iter;
434 g_return_val_if_fail (iter != NULL, NULL);
436 new_iter = g_new (GtkTextIter, 1);
444 * gtk_text_iter_free:
445 * @iter: a dynamically-allocated iterator
447 * Free an iterator allocated on the heap. This function
448 * is intended for use in language bindings, and is not
449 * especially useful for applications, because iterators can
450 * simply be allocated on the stack.
454 gtk_text_iter_free (GtkTextIter *iter)
456 g_return_if_fail (iter != NULL);
462 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
464 GtkTextRealIter *real;
466 g_return_val_if_fail (iter != NULL, 0);
468 real = gtk_text_iter_make_real (iter);
473 check_invariants (iter);
475 g_assert (real->segment != NULL);
477 return real->segment;
481 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
483 GtkTextRealIter *real;
485 g_return_val_if_fail (iter != NULL, 0);
487 real = gtk_text_iter_make_real (iter);
492 check_invariants (iter);
494 g_assert (real->any_segment != NULL);
496 return real->any_segment;
500 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
502 GtkTextRealIter *real;
504 g_return_val_if_fail (iter != NULL, 0);
506 real = gtk_text_iter_make_real (iter);
511 ensure_byte_offsets (real);
513 check_invariants (iter);
515 return real->segment_byte_offset;
519 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
521 GtkTextRealIter *real;
523 g_return_val_if_fail (iter != NULL, 0);
525 real = gtk_text_iter_make_real (iter);
530 ensure_char_offsets (real);
532 check_invariants (iter);
534 return real->segment_char_offset;
537 /* This function does not require a still-valid
540 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
542 const GtkTextRealIter *real;
544 g_return_val_if_fail (iter != NULL, 0);
546 real = (const GtkTextRealIter*)iter;
551 /* This function does not require a still-valid
554 _gtk_text_iter_get_btree (const GtkTextIter *iter)
556 const GtkTextRealIter *real;
558 g_return_val_if_fail (iter != NULL, 0);
560 real = (const GtkTextRealIter*)iter;
570 * gtk_text_iter_get_offset:
573 * Returns the character offset of an iterator.
574 * Each character in a #GtkTextBuffer has an offset,
575 * starting with 0 for the first character in the buffer.
576 * Use gtk_text_buffer_get_iter_at_offset () to convert an
577 * offset back into an iterator.
579 * Return value: a character offset
582 gtk_text_iter_get_offset (const GtkTextIter *iter)
584 GtkTextRealIter *real;
586 g_return_val_if_fail (iter != NULL, 0);
588 real = gtk_text_iter_make_surreal (iter);
593 check_invariants (iter);
595 if (real->cached_char_index < 0)
597 ensure_char_offsets (real);
599 real->cached_char_index =
600 _gtk_text_line_char_index (real->line);
601 real->cached_char_index += real->line_char_offset;
604 check_invariants (iter);
606 return real->cached_char_index;
610 * gtk_text_iter_get_line:
613 * Returns the line number containing the iterator. Lines in
614 * a #GtkTextBuffer are numbered beginning with 0 for the first
615 * line in the buffer.
617 * Return value: a line number
620 gtk_text_iter_get_line (const GtkTextIter *iter)
622 GtkTextRealIter *real;
624 g_return_val_if_fail (iter != NULL, 0);
626 real = gtk_text_iter_make_surreal (iter);
631 if (real->cached_line_number < 0)
632 real->cached_line_number =
633 _gtk_text_line_get_number (real->line);
635 check_invariants (iter);
637 return real->cached_line_number;
641 * gtk_text_iter_get_line_offset:
644 * Returns the character offset of the iterator,
645 * counting from the start of a newline-terminated line.
646 * The first character on the line has offset 0.
648 * Return value: offset from start of line
651 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
653 GtkTextRealIter *real;
655 g_return_val_if_fail (iter != NULL, 0);
657 real = gtk_text_iter_make_surreal (iter);
662 ensure_char_offsets (real);
664 check_invariants (iter);
666 return real->line_char_offset;
670 * gtk_text_iter_get_line_index:
673 * Returns the byte index of the iterator, counting
674 * from the start of a newline-terminated line.
675 * Remember that #GtkTextBuffer encodes text in
676 * UTF-8, and that characters can require a variable
677 * number of bytes to represent.
679 * Return value: distance from start of line, in bytes
682 gtk_text_iter_get_line_index (const GtkTextIter *iter)
684 GtkTextRealIter *real;
686 g_return_val_if_fail (iter != NULL, 0);
688 real = gtk_text_iter_make_surreal (iter);
693 ensure_byte_offsets (real);
695 check_invariants (iter);
697 return real->line_byte_offset;
701 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
703 GtkTextRealIter *real;
705 GtkTextLineSegment *seg;
708 g_return_val_if_fail (iter != NULL, 0);
710 real = gtk_text_iter_make_real (iter);
715 ensure_char_offsets (real);
717 check_invariants (iter);
719 vis_offset = real->line_char_offset;
721 _gtk_text_btree_get_iter_at_line (real->tree,
726 seg = _gtk_text_iter_get_indexable_segment (&pos);
728 while (seg != real->segment)
730 /* This is a pretty expensive call, making the
731 * whole function pretty lame; we could keep track
732 * of current invisibility state by looking at toggle
733 * segments as we loop, and then call this function
734 * only once per line, in order to speed up the loop
737 if (_gtk_text_btree_char_is_invisible (&pos))
738 vis_offset -= seg->char_count;
740 _gtk_text_iter_forward_indexable_segment (&pos);
742 seg = _gtk_text_iter_get_indexable_segment (&pos);
745 if (_gtk_text_btree_char_is_invisible (&pos))
746 vis_offset -= real->segment_char_offset;
752 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
754 GtkTextRealIter *real;
756 GtkTextLineSegment *seg;
759 g_return_val_if_fail (iter != NULL, 0);
761 real = gtk_text_iter_make_real (iter);
766 ensure_char_offsets (real);
768 check_invariants (iter);
770 vis_offset = real->line_byte_offset;
772 _gtk_text_btree_get_iter_at_line (real->tree,
777 seg = _gtk_text_iter_get_indexable_segment (&pos);
779 while (seg != real->segment)
781 /* This is a pretty expensive call, making the
782 * whole function pretty lame; we could keep track
783 * of current invisibility state by looking at toggle
784 * segments as we loop, and then call this function
785 * only once per line, in order to speed up the loop
788 if (_gtk_text_btree_char_is_invisible (&pos))
789 vis_offset -= seg->byte_count;
791 _gtk_text_iter_forward_indexable_segment (&pos);
793 seg = _gtk_text_iter_get_indexable_segment (&pos);
796 if (_gtk_text_btree_char_is_invisible (&pos))
797 vis_offset -= real->segment_byte_offset;
807 * gtk_text_iter_get_char:
810 * Returns the Unicode character at this iterator. (Equivalent to
811 * operator* on a C++ iterator.) If the iterator points at a
812 * non-character element, such as an image embedded in the buffer, the
813 * Unicode "unknown" character 0xFFFC is returned. If invoked on
814 * the end iterator, zero is returned; zero is not a valid Unicode character.
815 * So you can write a loop which ends when gtk_text_iter_get_char ()
818 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
821 gtk_text_iter_get_char (const GtkTextIter *iter)
823 GtkTextRealIter *real;
825 g_return_val_if_fail (iter != NULL, 0);
827 real = gtk_text_iter_make_real (iter);
832 check_invariants (iter);
834 if (gtk_text_iter_is_end (iter))
836 else if (real->segment->type == >k_text_char_type)
838 ensure_byte_offsets (real);
840 return g_utf8_get_char (real->segment->body.chars +
841 real->segment_byte_offset);
845 /* Unicode "unknown character" 0xFFFC */
846 return GTK_TEXT_UNKNOWN_CHAR;
851 * gtk_text_iter_get_slice:
852 * @start: iterator at start of a range
853 * @end: iterator at end of a range
855 * Returns the text in the given range. A "slice" is an array of
856 * characters encoded in UTF-8 format, including the Unicode "unknown"
857 * character 0xFFFC for iterable non-character elements in the buffer,
858 * such as images. Because images are encoded in the slice, byte and
859 * character offsets in the returned array will correspond to byte
860 * offsets in the text buffer. Note that 0xFFFC can occur in normal
861 * text as well, so it is not a reliable indicator that a pixbuf or
862 * widget is in the buffer.
864 * Return value: slice of text from the buffer
867 gtk_text_iter_get_slice (const GtkTextIter *start,
868 const GtkTextIter *end)
870 g_return_val_if_fail (start != NULL, NULL);
871 g_return_val_if_fail (end != NULL, NULL);
873 check_invariants (start);
874 check_invariants (end);
876 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
880 * gtk_text_iter_get_text:
881 * @start: iterator at start of a range
882 * @end: iterator at end of a range
884 * Returns <emphasis>text</emphasis> in the given range. If the range
885 * contains non-text elements such as images, the character and byte
886 * offsets in the returned string will not correspond to character and
887 * byte offsets in the buffer. If you want offsets to correspond, see
888 * gtk_text_iter_get_slice ().
890 * Return value: array of characters from the buffer
893 gtk_text_iter_get_text (const GtkTextIter *start,
894 const GtkTextIter *end)
896 g_return_val_if_fail (start != NULL, NULL);
897 g_return_val_if_fail (end != NULL, NULL);
899 check_invariants (start);
900 check_invariants (end);
902 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
906 * gtk_text_iter_get_visible_slice:
907 * @start: iterator at start of range
908 * @end: iterator at end of range
910 * Like gtk_text_iter_get_slice (), but invisible text is not included.
911 * Invisible text is usually invisible because a #GtkTextTag with the
912 * "invisible" attribute turned on has been applied to it.
914 * Return value: slice of text from the buffer
917 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
918 const GtkTextIter *end)
920 g_return_val_if_fail (start != NULL, NULL);
921 g_return_val_if_fail (end != NULL, NULL);
923 check_invariants (start);
924 check_invariants (end);
926 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
930 * gtk_text_iter_get_visible_text:
931 * @start: iterator at start of range
932 * @end: iterator at end of range
934 * Like gtk_text_iter_get_text (), but invisible text is not included.
935 * Invisible text is usually invisible because a #GtkTextTag with the
936 * "invisible" attribute turned on has been applied to it.
938 * Return value: string containing visible text in the range
941 gtk_text_iter_get_visible_text (const GtkTextIter *start,
942 const GtkTextIter *end)
944 g_return_val_if_fail (start != NULL, NULL);
945 g_return_val_if_fail (end != NULL, NULL);
947 check_invariants (start);
948 check_invariants (end);
950 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
954 * gtk_text_iter_get_pixbuf:
957 * If the location pointed to by @iter contains a pixbuf, the pixbuf
958 * is returned (with no new reference count added). Otherwise,
961 * Return value: the pixbuf at @iter
964 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
966 GtkTextRealIter *real;
968 g_return_val_if_fail (iter != NULL, NULL);
970 real = gtk_text_iter_make_real (iter);
975 check_invariants (iter);
977 if (real->segment->type != >k_text_pixbuf_type)
980 return real->segment->body.pixbuf.pixbuf;
984 * gtk_text_iter_get_child_anchor:
987 * If the location pointed to by @iter contains a child anchor, the
988 * anchor is returned (with no new reference count added). Otherwise,
991 * Return value: the anchor at @iter
994 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
996 GtkTextRealIter *real;
998 g_return_val_if_fail (iter != NULL, NULL);
1000 real = gtk_text_iter_make_real (iter);
1005 check_invariants (iter);
1007 if (real->segment->type != >k_text_child_type)
1010 return real->segment->body.child.obj;
1014 * gtk_text_iter_get_marks:
1015 * @iter: an iterator
1017 * Returns a list of all #GtkTextMark at this location. Because marks
1018 * are not iterable (they don't take up any "space" in the buffer,
1019 * they are just marks in between iterable locations), multiple marks
1020 * can exist in the same place. The returned list is not in any
1023 * Return value: list of #GtkTextMark
1026 gtk_text_iter_get_marks (const GtkTextIter *iter)
1028 GtkTextRealIter *real;
1029 GtkTextLineSegment *seg;
1032 g_return_val_if_fail (iter != NULL, NULL);
1034 real = gtk_text_iter_make_real (iter);
1039 check_invariants (iter);
1042 seg = real->any_segment;
1043 while (seg != real->segment)
1045 if (seg->type == >k_text_left_mark_type ||
1046 seg->type == >k_text_right_mark_type)
1047 retval = g_slist_prepend (retval, seg->body.mark.obj);
1052 /* The returned list isn't guaranteed to be in any special order,
1058 * gtk_text_iter_get_toggled_tags:
1059 * @iter: an iterator
1060 * @toggled_on: TRUE to get toggled-on tags
1062 * Returns a list of #GtkTextTag that are toggled on or off at this
1063 * point. (If @toggled_on is TRUE, the list contains tags that are
1064 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1065 * range of characters following @iter has that tag applied to it. If
1066 * a tag is toggled off, then some non-empty range following @iter
1067 * does <emphasis>not</emphasis> have the tag applied to it.
1069 * Return value: tags toggled at this point
1072 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1073 gboolean toggled_on)
1075 GtkTextRealIter *real;
1076 GtkTextLineSegment *seg;
1079 g_return_val_if_fail (iter != NULL, NULL);
1081 real = gtk_text_iter_make_real (iter);
1086 check_invariants (iter);
1089 seg = real->any_segment;
1090 while (seg != real->segment)
1094 if (seg->type == >k_text_toggle_on_type)
1096 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1101 if (seg->type == >k_text_toggle_off_type)
1103 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1110 /* The returned list isn't guaranteed to be in any special order,
1116 * gtk_text_iter_begins_tag:
1117 * @iter: an iterator
1118 * @tag: a #GtkTextTag, or NULL
1120 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
1121 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1122 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1123 * <emphasis>start</emphasis> of the tagged range;
1124 * gtk_text_iter_has_tag () tells you whether an iterator is
1125 * <emphasis>within</emphasis> a tagged range.
1127 * Return value: whether @iter is the start of a range tagged with @tag
1130 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1133 GtkTextRealIter *real;
1134 GtkTextLineSegment *seg;
1136 g_return_val_if_fail (iter != NULL, FALSE);
1138 real = gtk_text_iter_make_real (iter);
1143 check_invariants (iter);
1145 seg = real->any_segment;
1146 while (seg != real->segment)
1148 if (seg->type == >k_text_toggle_on_type)
1151 seg->body.toggle.info->tag == tag)
1162 * gtk_text_iter_ends_tag:
1163 * @iter: an iterator
1164 * @tag: a #GtkTextTag, or NULL
1166 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1167 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1168 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1169 * <emphasis>end</emphasis> of the tagged range;
1170 * gtk_text_iter_has_tag () tells you whether an iterator is
1171 * <emphasis>within</emphasis> a tagged range.
1173 * Return value: whether @iter is the end of a range tagged with @tag
1177 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1180 GtkTextRealIter *real;
1181 GtkTextLineSegment *seg;
1183 g_return_val_if_fail (iter != NULL, FALSE);
1185 real = gtk_text_iter_make_real (iter);
1190 check_invariants (iter);
1192 seg = real->any_segment;
1193 while (seg != real->segment)
1195 if (seg->type == >k_text_toggle_off_type)
1198 seg->body.toggle.info->tag == tag)
1209 * gtk_text_iter_toggles_tag:
1210 * @iter: an iterator
1211 * @tag: a #GtkTextTag, or NULL
1213 * This is equivalent to (gtk_text_iter_begins_tag () ||
1214 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1215 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1217 * Return value: whether @tag is toggled on or off at @iter
1220 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1223 GtkTextRealIter *real;
1224 GtkTextLineSegment *seg;
1226 g_return_val_if_fail (iter != NULL, FALSE);
1228 real = gtk_text_iter_make_real (iter);
1233 check_invariants (iter);
1235 seg = real->any_segment;
1236 while (seg != real->segment)
1238 if ( (seg->type == >k_text_toggle_off_type ||
1239 seg->type == >k_text_toggle_on_type) &&
1241 seg->body.toggle.info->tag == tag) )
1251 * gtk_text_iter_has_tag:
1252 * @iter: an iterator
1253 * @tag: a #GtkTextTag
1255 * Returns TRUE if @iter is within a range tagged with @tag.
1257 * Return value: whether @iter is tagged with @tag
1260 gtk_text_iter_has_tag (const GtkTextIter *iter,
1263 GtkTextRealIter *real;
1265 g_return_val_if_fail (iter != NULL, FALSE);
1266 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1268 real = gtk_text_iter_make_surreal (iter);
1273 check_invariants (iter);
1275 if (real->line_byte_offset >= 0)
1277 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1278 real->line_byte_offset, tag);
1282 g_assert (real->line_char_offset >= 0);
1283 return _gtk_text_line_char_has_tag (real->line, real->tree,
1284 real->line_char_offset, tag);
1289 * gtk_text_iter_get_tags:
1290 * @iter: a #GtkTextIter
1292 * Returns a list of tags that apply to @iter, in ascending order of
1293 * priority (highest-priority tags are last). The #GtkTextTag in the
1294 * list don't have a reference added, but you have to free the list
1297 * Return value: list of #GtkTextTag
1300 gtk_text_iter_get_tags (const GtkTextIter *iter)
1307 g_return_val_if_fail (iter != NULL, NULL);
1309 /* Get the tags at this spot */
1310 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1312 /* No tags, use default style */
1313 if (tags == NULL || tag_count == 0)
1321 /* Sort tags in ascending order of priority */
1322 _gtk_text_tag_array_sort (tags, tag_count);
1326 while (i < tag_count)
1328 retval = g_slist_prepend (retval, tags[i]);
1334 /* Return tags in ascending order of priority */
1335 return g_slist_reverse (retval);
1339 * gtk_text_iter_editable:
1340 * @iter: an iterator
1341 * @default_setting: TRUE if text is editable by default
1343 * Returns whether @iter is within an editable region of text.
1344 * Non-editable text is "locked" and can't be changed by the user via
1345 * #GtkTextView. This function is simply a convenience wrapper around
1346 * gtk_text_iter_get_attributes (). If no tags applied to this text
1347 * affect editability, @default_setting will be returned.
1349 * Return value: whether @iter is inside an editable range
1352 gtk_text_iter_editable (const GtkTextIter *iter,
1353 gboolean default_setting)
1355 GtkTextAttributes *values;
1358 values = gtk_text_attributes_new ();
1360 values->editable = default_setting;
1362 gtk_text_iter_get_attributes (iter, values);
1364 retval = values->editable;
1366 gtk_text_attributes_unref (values);
1372 * gtk_text_iter_get_language:
1373 * @iter: an iterator
1375 * A convenience wrapper around gtk_text_iter_get_attributes (),
1376 * which returns the language in effect at @iter. If no tags affecting
1377 * language * apply to @iter, the return value is identical to that of
1378 * gtk_get_default_language ().
1380 * Return value: language in effect at @iter
1383 gtk_text_iter_get_language (const GtkTextIter *iter)
1385 GtkTextAttributes *values;
1386 PangoLanguage *retval;
1388 values = gtk_text_attributes_new ();
1390 gtk_text_iter_get_attributes (iter, values);
1392 retval = values->language;
1394 gtk_text_attributes_unref (values);
1400 * gtk_text_iter_starts_line:
1401 * @iter: an iterator
1403 * Returns TRUE if @iter begins a paragraph,
1404 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1405 * However this function is potentially more efficient than
1406 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1407 * the offset, it just has to see whether it's 0.
1409 * Return value: whether @iter begins a line
1412 gtk_text_iter_starts_line (const GtkTextIter *iter)
1414 GtkTextRealIter *real;
1416 g_return_val_if_fail (iter != NULL, FALSE);
1418 real = gtk_text_iter_make_surreal (iter);
1423 check_invariants (iter);
1425 if (real->line_byte_offset >= 0)
1427 return (real->line_byte_offset == 0);
1431 g_assert (real->line_char_offset >= 0);
1432 return (real->line_char_offset == 0);
1437 * gtk_text_iter_ends_line:
1438 * @iter: an iterator
1440 * Returns TRUE if @iter points to the start of the paragraph delimiter
1441 * characters for a line (delimiters will be either a newline, a
1442 * carriage return, a carriage return followed by a newline, or a
1443 * Unicode paragraph separator character). Note that an iterator pointing
1444 * to the \n of a \r\n pair will not be counted as the end of a line,
1445 * the line ends before the \r.
1447 * Return value: whether @iter is at the end of a line
1450 gtk_text_iter_ends_line (const GtkTextIter *iter)
1452 GtkTextRealIter *real;
1455 g_return_val_if_fail (iter != NULL, FALSE);
1457 real = gtk_text_iter_make_real (iter);
1459 check_invariants (iter);
1461 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1462 * Unicode 3.0; update this if that changes.
1464 #define PARAGRAPH_SEPARATOR 0x2029
1466 wc = gtk_text_iter_get_char (iter);
1468 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1470 else if (wc == '\n')
1472 /* need to determine if a \r precedes the \n, in which case
1473 * we aren't the end of the line
1475 GtkTextIter tmp = *iter;
1476 if (!gtk_text_iter_backward_char (&tmp))
1479 return gtk_text_iter_get_char (&tmp) != '\r';
1486 * gtk_text_iter_is_end:
1487 * @iter: an iterator
1489 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1490 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1491 * the most efficient way to check whether an iterator is the end
1494 * Return value: whether @iter is the end iterator
1497 gtk_text_iter_is_end (const GtkTextIter *iter)
1499 GtkTextRealIter *real;
1501 g_return_val_if_fail (iter != NULL, FALSE);
1503 real = gtk_text_iter_make_surreal (iter);
1508 check_invariants (iter);
1510 return _gtk_text_line_is_last (real->line, real->tree);
1514 * gtk_text_iter_is_start:
1515 * @iter: an iterator
1517 * Returns TRUE if @iter is the first iterator in the buffer, that is
1518 * if @iter has a character offset of 0.
1520 * Return value: whether @iter is the first in the buffer
1523 gtk_text_iter_is_start (const GtkTextIter *iter)
1525 return gtk_text_iter_get_offset (iter) == 0;
1529 * gtk_text_iter_get_chars_in_line:
1530 * @iter: an iterator
1532 * Returns the number of characters in the line containing @iter,
1533 * including the paragraph delimiters.
1535 * Return value: number of characters in the line
1538 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1540 GtkTextRealIter *real;
1542 GtkTextLineSegment *seg;
1544 g_return_val_if_fail (iter != NULL, FALSE);
1546 real = gtk_text_iter_make_surreal (iter);
1551 check_invariants (iter);
1553 if (real->line_char_offset >= 0)
1555 /* We can start at the segments we've already found. */
1556 count = real->line_char_offset - real->segment_char_offset;
1557 seg = _gtk_text_iter_get_indexable_segment (iter);
1561 /* count whole line. */
1562 seg = real->line->segments;
1569 count += seg->char_count;
1578 * gtk_text_iter_get_bytes_in_line:
1579 * @iter: an iterator
1581 * Returns the number of bytes in the line containing @iter,
1582 * including the paragraph delimiters.
1584 * Return value: number of bytes in the line
1587 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1589 GtkTextRealIter *real;
1591 GtkTextLineSegment *seg;
1593 g_return_val_if_fail (iter != NULL, FALSE);
1595 real = gtk_text_iter_make_surreal (iter);
1600 check_invariants (iter);
1602 if (real->line_byte_offset >= 0)
1604 /* We can start at the segments we've already found. */
1605 count = real->line_byte_offset - real->segment_byte_offset;
1606 seg = _gtk_text_iter_get_indexable_segment (iter);
1610 /* count whole line. */
1611 seg = real->line->segments;
1617 count += seg->byte_count;
1626 * gtk_text_iter_get_attributes:
1627 * @iter: an iterator
1628 * @values: a #GtkTextAttributes to be filled in
1630 * Computes the effect of any tags applied to this spot in the
1631 * text. The @values parameter should be initialized to the default
1632 * settings you wish to use if no tags are in effect. You'd typically
1633 * obtain the defaults from gtk_text_view_get_default_attributes().
1635 * gtk_text_iter_get_attributes () will modify @values, applying the
1636 * effects of any tags present at @iter. If any tags affected @values,
1637 * the function returns %TRUE.
1639 * Return value: %TRUE if @values was modified
1642 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1643 GtkTextAttributes *values)
1648 /* Get the tags at this spot */
1649 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1651 /* No tags, use default style */
1652 if (tags == NULL || tag_count == 0)
1660 /* Sort tags in ascending order of priority */
1661 _gtk_text_tag_array_sort (tags, tag_count);
1663 _gtk_text_attributes_fill_from_tags (values,
1673 * Increments/decrements
1676 /* The return value of this indicates WHETHER WE MOVED.
1677 * The return value of public functions indicates
1678 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1681 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1683 GtkTextLine *new_line;
1685 new_line = _gtk_text_line_next (real->line);
1687 g_assert (new_line != real->line);
1689 if (new_line != NULL)
1691 real->line = new_line;
1693 real->line_byte_offset = 0;
1694 real->line_char_offset = 0;
1696 real->segment_byte_offset = 0;
1697 real->segment_char_offset = 0;
1699 /* Find first segments in new line */
1700 real->any_segment = real->line->segments;
1701 real->segment = real->any_segment;
1702 while (real->segment->char_count == 0)
1703 real->segment = real->segment->next;
1709 /* There is no way to move forward; we were already
1710 at the "end" index. (the end index is the last
1711 line pointer, segment_byte_offset of 0) */
1713 g_assert (real->line_char_offset == 0 ||
1714 real->line_byte_offset == 0);
1716 /* The only indexable segment allowed on the bogus
1717 line at the end is a single char segment containing
1719 if (real->segments_changed_stamp ==
1720 _gtk_text_btree_get_segments_changed_stamp (real->tree))
1722 g_assert (real->segment->type == >k_text_char_type);
1723 g_assert (real->segment->char_count == 1);
1725 /* We leave real->line as-is */
1732 /* The return value of this indicates WHETHER WE MOVED.
1733 * The return value of public functions indicates
1734 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1737 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1739 GtkTextLine *new_line;
1741 new_line = _gtk_text_line_previous (real->line);
1743 g_assert (new_line != real->line);
1745 if (new_line != NULL)
1747 real->line = new_line;
1749 real->line_byte_offset = 0;
1750 real->line_char_offset = 0;
1752 real->segment_byte_offset = 0;
1753 real->segment_char_offset = 0;
1755 /* Find first segments in new line */
1756 real->any_segment = real->line->segments;
1757 real->segment = real->any_segment;
1758 while (real->segment->char_count == 0)
1759 real->segment = real->segment->next;
1765 /* There is no way to move backward; we were already
1766 at the first line. */
1768 /* We leave real->line as-is */
1770 /* Note that we didn't clamp to the start of the first line. */
1776 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1780 forward_char (GtkTextRealIter *real)
1782 GtkTextIter *iter = (GtkTextIter*)real;
1784 check_invariants ((GtkTextIter*)real);
1786 ensure_char_offsets (real);
1788 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1790 /* Need to move to the next segment; if no next segment,
1791 need to move to next line. */
1792 return _gtk_text_iter_forward_indexable_segment (iter);
1796 /* Just moving within a segment. Keep byte count
1797 up-to-date, if it was already up-to-date. */
1799 g_assert (real->segment->type == >k_text_char_type);
1801 if (real->line_byte_offset >= 0)
1804 const char * start =
1805 real->segment->body.chars + real->segment_byte_offset;
1807 bytes = g_utf8_next_char (start) - start;
1809 real->line_byte_offset += bytes;
1810 real->segment_byte_offset += bytes;
1812 g_assert (real->segment_byte_offset < real->segment->byte_count);
1815 real->line_char_offset += 1;
1816 real->segment_char_offset += 1;
1818 adjust_char_index (real, 1);
1820 g_assert (real->segment_char_offset < real->segment->char_count);
1822 /* We moved into the middle of a segment, so the any_segment
1823 must now be the segment we're in the middle of. */
1824 real->any_segment = real->segment;
1826 check_invariants ((GtkTextIter*)real);
1828 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1836 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1838 /* Need to move to the next segment; if no next segment,
1839 need to move to next line. */
1840 GtkTextLineSegment *seg;
1841 GtkTextLineSegment *any_seg;
1842 GtkTextRealIter *real;
1846 g_return_val_if_fail (iter != NULL, FALSE);
1848 real = gtk_text_iter_make_real (iter);
1853 check_invariants (iter);
1855 if (real->line_char_offset >= 0)
1857 chars_skipped = real->segment->char_count - real->segment_char_offset;
1858 g_assert (chars_skipped > 0);
1863 if (real->line_byte_offset >= 0)
1865 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1866 g_assert (bytes_skipped > 0);
1871 /* Get first segment of any kind */
1872 any_seg = real->segment->next;
1873 /* skip non-indexable segments, if any */
1875 while (seg != NULL && seg->char_count == 0)
1880 real->any_segment = any_seg;
1881 real->segment = seg;
1883 if (real->line_byte_offset >= 0)
1885 g_assert (bytes_skipped > 0);
1886 real->segment_byte_offset = 0;
1887 real->line_byte_offset += bytes_skipped;
1890 if (real->line_char_offset >= 0)
1892 g_assert (chars_skipped > 0);
1893 real->segment_char_offset = 0;
1894 real->line_char_offset += chars_skipped;
1895 adjust_char_index (real, chars_skipped);
1898 check_invariants (iter);
1904 /* End of the line */
1905 if (forward_line_leaving_caches_unmodified (real))
1907 adjust_line_number (real, 1);
1908 if (real->line_char_offset >= 0)
1909 adjust_char_index (real, chars_skipped);
1911 g_assert (real->line_byte_offset == 0);
1912 g_assert (real->line_char_offset == 0);
1913 g_assert (real->segment_byte_offset == 0);
1914 g_assert (real->segment_char_offset == 0);
1915 g_assert (gtk_text_iter_starts_line (iter));
1917 check_invariants (iter);
1919 if (gtk_text_iter_is_end (iter))
1928 check_invariants (iter);
1936 at_last_indexable_segment (GtkTextRealIter *real)
1938 GtkTextLineSegment *seg;
1940 /* Return TRUE if there are no indexable segments after
1944 seg = real->segment->next;
1947 if (seg->char_count > 0)
1954 /* Goes back to the start of the next segment, even if
1955 * we're not at the start of the current segment (always
1956 * ends up on a different segment if it returns TRUE)
1959 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1961 /* Move to the start of the previous segment; if no previous
1962 * segment, to the last segment in the previous line. This is
1963 * inherently a bit inefficient due to the singly-linked list and
1964 * tree nodes, but we can't afford the RAM for doubly-linked.
1966 GtkTextRealIter *real;
1967 GtkTextLineSegment *seg;
1968 GtkTextLineSegment *any_seg;
1969 GtkTextLineSegment *prev_seg;
1970 GtkTextLineSegment *prev_any_seg;
1974 g_return_val_if_fail (iter != NULL, FALSE);
1976 real = gtk_text_iter_make_real (iter);
1981 check_invariants (iter);
1983 /* Find first segments in line */
1984 any_seg = real->line->segments;
1986 while (seg->char_count == 0)
1989 if (seg == real->segment)
1991 /* Could probably do this case faster by hand-coding the
1995 /* We were already at the start of a line;
1996 * go back to the previous line.
1998 if (gtk_text_iter_backward_line (iter))
2000 /* Go forward to last indexable segment in line. */
2001 while (!at_last_indexable_segment (real))
2002 _gtk_text_iter_forward_indexable_segment (iter);
2004 check_invariants (iter);
2009 return FALSE; /* We were at the start of the first line. */
2012 /* We must be in the middle of a line; so find the indexable
2013 * segment just before our current segment.
2015 g_assert (seg != real->segment);
2016 while (seg != real->segment)
2019 prev_any_seg = any_seg;
2021 any_seg = seg->next;
2023 while (seg->char_count == 0)
2027 g_assert (prev_seg != NULL);
2028 g_assert (prev_any_seg != NULL);
2029 g_assert (prev_seg->char_count > 0);
2031 /* We skipped the entire previous segment, plus any
2032 * chars we were into the current segment.
2034 if (real->segment_byte_offset >= 0)
2035 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2039 if (real->segment_char_offset >= 0)
2040 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2044 real->segment = prev_seg;
2045 real->any_segment = prev_any_seg;
2046 real->segment_byte_offset = 0;
2047 real->segment_char_offset = 0;
2049 if (bytes_skipped >= 0)
2051 if (real->line_byte_offset >= 0)
2053 real->line_byte_offset -= bytes_skipped;
2054 g_assert (real->line_byte_offset >= 0);
2058 real->line_byte_offset = -1;
2060 if (chars_skipped >= 0)
2062 if (real->line_char_offset >= 0)
2064 real->line_char_offset -= chars_skipped;
2065 g_assert (real->line_char_offset >= 0);
2068 if (real->cached_char_index >= 0)
2070 real->cached_char_index -= chars_skipped;
2071 g_assert (real->cached_char_index >= 0);
2076 real->line_char_offset = -1;
2077 real->cached_char_index = -1;
2080 /* line number is unchanged. */
2082 check_invariants (iter);
2088 * gtk_text_iter_forward_char:
2089 * @iter: an iterator
2091 * Moves @iter forward by one character offset. Note that images
2092 * embedded in the buffer occupy 1 character slot, so
2093 * gtk_text_iter_forward_char () may actually move onto an image instead
2094 * of a character, if you have images in your buffer. If @iter is the
2095 * end iterator or one character before it, @iter will now point at
2096 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2097 * convenience when writing loops.
2099 * Return value: whether the new position is the end iterator
2102 gtk_text_iter_forward_char (GtkTextIter *iter)
2104 GtkTextRealIter *real;
2106 g_return_val_if_fail (iter != NULL, FALSE);
2108 real = gtk_text_iter_make_real (iter);
2114 check_invariants (iter);
2115 return forward_char (real);
2120 * gtk_text_iter_backward_char:
2121 * @iter: an iterator
2123 * Moves backward by one character offset. Returns TRUE if movement
2124 * was possible; if @iter was the first in the buffer (character
2125 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2128 * Return value: whether movement was possible
2131 gtk_text_iter_backward_char (GtkTextIter *iter)
2133 g_return_val_if_fail (iter != NULL, FALSE);
2135 check_invariants (iter);
2137 return gtk_text_iter_backward_chars (iter, 1);
2141 Definitely we should try to linear scan as often as possible for
2142 movement within a single line, because we can't use the BTree to
2143 speed within-line searches up; for movement between lines, we would
2144 like to avoid the linear scan probably.
2146 Instead of using this constant, it might be nice to cache the line
2147 length in the iterator and linear scan if motion is within a single
2150 I guess you'd have to profile the various approaches.
2152 #define MAX_LINEAR_SCAN 150
2156 * gtk_text_iter_forward_chars:
2157 * @iter: an iterator
2158 * @count: number of characters to move, may be negative
2160 * Moves @count characters if possible (if @count would move past the
2161 * start or end of the buffer, moves to the start or end of the
2162 * buffer). The return value indicates whether the new position of
2163 * @iter is different from its original position, and dereferenceable
2164 * (the last iterator in the buffer is not dereferenceable). If @count
2165 * is 0, the function does nothing and returns FALSE.
2167 * Return value: whether @iter moved and is dereferenceable
2170 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2172 GtkTextRealIter *real;
2174 g_return_val_if_fail (iter != NULL, FALSE);
2176 real = gtk_text_iter_make_real (iter);
2180 else if (count == 0)
2183 return gtk_text_iter_backward_chars (iter, 0 - count);
2184 else if (count < MAX_LINEAR_SCAN)
2186 check_invariants (iter);
2190 if (!forward_char (real))
2195 return forward_char (real);
2199 gint current_char_index;
2200 gint new_char_index;
2202 check_invariants (iter);
2204 current_char_index = gtk_text_iter_get_offset (iter);
2206 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2207 return FALSE; /* can't move forward */
2209 new_char_index = current_char_index + count;
2210 gtk_text_iter_set_offset (iter, new_char_index);
2212 check_invariants (iter);
2214 /* Return FALSE if we're on the non-dereferenceable end
2217 if (gtk_text_iter_is_end (iter))
2225 * gtk_text_iter_backward_chars:
2226 * @iter: an iterator
2227 * @count: number of characters to move
2229 * Moves @count characters backward, if possible (if @count would move
2230 * past the start or end of the buffer, moves to the start or end of
2231 * the buffer). The return value indicates whether the iterator moved
2232 * onto a dereferenceable position; if the iterator didn't move, or
2233 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2234 * the function does nothing and returns FALSE.
2236 * Return value: whether @iter moved and is dereferenceable
2240 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2242 GtkTextRealIter *real;
2244 g_return_val_if_fail (iter != NULL, FALSE);
2246 real = gtk_text_iter_make_real (iter);
2250 else if (count == 0)
2253 return gtk_text_iter_forward_chars (iter, 0 - count);
2255 ensure_char_offsets (real);
2256 check_invariants (iter);
2258 if (count <= real->segment_char_offset)
2260 /* Optimize the within-segment case */
2261 g_assert (real->segment->char_count > 0);
2262 g_assert (real->segment->type == >k_text_char_type);
2264 real->segment_char_offset -= count;
2265 g_assert (real->segment_char_offset >= 0);
2267 if (real->line_byte_offset >= 0)
2269 gint new_byte_offset;
2272 new_byte_offset = 0;
2274 while (i < real->segment_char_offset)
2276 const char * start = real->segment->body.chars + new_byte_offset;
2277 new_byte_offset += g_utf8_next_char (start) - start;
2282 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2283 real->segment_byte_offset = new_byte_offset;
2286 real->line_char_offset -= count;
2288 adjust_char_index (real, 0 - count);
2290 check_invariants (iter);
2296 /* We need to go back into previous segments. For now,
2297 * just keep this really simple. FIXME
2298 * use backward_indexable_segment.
2300 if (TRUE || count > MAX_LINEAR_SCAN)
2302 gint current_char_index;
2303 gint new_char_index;
2305 current_char_index = gtk_text_iter_get_offset (iter);
2307 if (current_char_index == 0)
2308 return FALSE; /* can't move backward */
2310 new_char_index = current_char_index - count;
2311 if (new_char_index < 0)
2313 gtk_text_iter_set_offset (iter, new_char_index);
2315 check_invariants (iter);
2321 /* FIXME backward_indexable_segment here */
2330 /* These two can't be implemented efficiently (always have to use
2331 * a linear scan, since that's the only way to find all the non-text
2336 * gtk_text_iter_forward_text_chars:
2337 * @iter: a #GtkTextIter
2338 * @count: number of chars to move
2340 * Moves forward by @count text characters (pixbufs, widgets,
2341 * etc. do not count as characters for this). Equivalent to moving
2342 * through the results of gtk_text_iter_get_text (), rather than
2343 * gtk_text_iter_get_slice ().
2345 * Return value: whether @iter moved and is dereferenceable
2348 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2357 * gtk_text_iter_forward_text_chars:
2358 * @iter: a #GtkTextIter
2359 * @count: number of chars to move
2361 * Moves backward by @count text characters (pixbufs, widgets,
2362 * etc. do not count as characters for this). Equivalent to moving
2363 * through the results of gtk_text_iter_get_text (), rather than
2364 * gtk_text_iter_get_slice ().
2366 * Return value: whether @iter moved and is dereferenceable
2369 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2378 * gtk_text_iter_forward_line:
2379 * @iter: an iterator
2381 * Moves @iter to the start of the next line. Returns TRUE if there
2382 * was a next line to move to, and FALSE if @iter was simply moved to
2383 * the end of the buffer and is now not dereferenceable, or if @iter was
2384 * already at the end of the buffer.
2386 * Return value: whether @iter can be dereferenced
2389 gtk_text_iter_forward_line (GtkTextIter *iter)
2391 GtkTextRealIter *real;
2393 g_return_val_if_fail (iter != NULL, FALSE);
2395 real = gtk_text_iter_make_real (iter);
2400 check_invariants (iter);
2402 if (forward_line_leaving_caches_unmodified (real))
2404 invalidate_char_index (real);
2405 adjust_line_number (real, 1);
2407 check_invariants (iter);
2409 if (gtk_text_iter_is_end (iter))
2416 check_invariants (iter);
2422 * gtk_text_iter_backward_line:
2423 * @iter: an iterator
2425 * Moves @iter to the start of the previous line. Returns TRUE if
2426 * @iter could be moved; i.e. if @iter was at character offset 0, this
2427 * function returns FALSE. Therefore if @iter was already on line 0,
2428 * but not at the start of the line, @iter is snapped to the start of
2429 * the line and the function returns TRUE. (Note that this implies that
2430 * in a loop calling this function, the line number may not change on
2431 * every iteration, if your first iteration is on line 0.)
2433 * Return value: whether @iter moved
2436 gtk_text_iter_backward_line (GtkTextIter *iter)
2438 GtkTextLine *new_line;
2439 GtkTextRealIter *real;
2440 gboolean offset_will_change;
2443 g_return_val_if_fail (iter != NULL, FALSE);
2445 real = gtk_text_iter_make_real (iter);
2450 check_invariants (iter);
2452 new_line = _gtk_text_line_previous (real->line);
2454 offset_will_change = FALSE;
2455 if (real->line_char_offset > 0)
2456 offset_will_change = TRUE;
2458 if (new_line != NULL)
2460 real->line = new_line;
2462 adjust_line_number (real, -1);
2466 if (!offset_will_change)
2470 invalidate_char_index (real);
2472 real->line_byte_offset = 0;
2473 real->line_char_offset = 0;
2475 real->segment_byte_offset = 0;
2476 real->segment_char_offset = 0;
2478 /* Find first segment in line */
2479 real->any_segment = real->line->segments;
2480 real->segment = _gtk_text_line_byte_to_segment (real->line,
2483 g_assert (offset == 0);
2485 /* Note that if we are on the first line, we snap to the start of
2486 * the first line and return TRUE, so TRUE means the iterator
2487 * changed, not that the line changed; this is maybe a bit
2488 * weird. I'm not sure there's an obvious right thing to do though.
2491 check_invariants (iter);
2497 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2500 return gtk_text_iter_backward_lines (iter, 0 - count);
2501 else if (count == 0)
2503 else if (count == 1)
2505 check_invariants (iter);
2506 return gtk_text_iter_forward_line (iter);
2512 old_line = gtk_text_iter_get_line (iter);
2514 gtk_text_iter_set_line (iter, old_line + count);
2516 check_invariants (iter);
2518 /* return whether it moved, and is dereferenceable. */
2520 (gtk_text_iter_get_line (iter) != old_line) &&
2521 !gtk_text_iter_is_end (iter);
2526 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2529 return gtk_text_iter_forward_lines (iter, 0 - count);
2530 else if (count == 0)
2532 else if (count == 1)
2534 return gtk_text_iter_backward_line (iter);
2540 old_line = gtk_text_iter_get_line (iter);
2542 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2544 return (gtk_text_iter_get_line (iter) != old_line);
2548 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2553 gboolean already_moved_initially);
2555 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2563 find_word_end_func (const PangoLogAttr *attrs,
2568 gboolean already_moved_initially)
2570 if (!already_moved_initially)
2573 /* Find end of next word */
2574 while (offset < min_offset + len &&
2575 !attrs[offset].is_word_end)
2578 *found_offset = offset;
2580 return offset < min_offset + len;
2584 is_word_end_func (const PangoLogAttr *attrs,
2589 return attrs[offset].is_word_end;
2593 find_word_start_func (const PangoLogAttr *attrs,
2598 gboolean already_moved_initially)
2600 if (!already_moved_initially)
2603 /* Find start of prev word */
2604 while (offset >= min_offset &&
2605 !attrs[offset].is_word_start)
2608 *found_offset = offset;
2610 return offset >= min_offset;
2614 is_word_start_func (const PangoLogAttr *attrs,
2619 return attrs[offset].is_word_start;
2623 inside_word_func (const PangoLogAttr *attrs,
2628 /* Find next word start or end */
2629 while (offset >= min_offset &&
2630 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2633 return attrs[offset].is_word_start;
2636 /* Sentence funcs */
2639 find_sentence_end_func (const PangoLogAttr *attrs,
2644 gboolean already_moved_initially)
2646 if (!already_moved_initially)
2649 /* Find end of next sentence */
2650 while (offset < min_offset + len &&
2651 !attrs[offset].is_sentence_end)
2654 *found_offset = offset;
2656 return offset < min_offset + len;
2660 is_sentence_end_func (const PangoLogAttr *attrs,
2665 return attrs[offset].is_sentence_end;
2669 find_sentence_start_func (const PangoLogAttr *attrs,
2674 gboolean already_moved_initially)
2676 if (!already_moved_initially)
2679 /* Find start of prev sentence */
2680 while (offset >= min_offset &&
2681 !attrs[offset].is_sentence_start)
2684 *found_offset = offset;
2686 return offset >= min_offset;
2690 is_sentence_start_func (const PangoLogAttr *attrs,
2695 return attrs[offset].is_sentence_start;
2699 inside_sentence_func (const PangoLogAttr *attrs,
2704 /* Find next sentence start or end */
2705 while (offset >= min_offset &&
2706 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2709 return attrs[offset].is_sentence_start;
2713 test_log_attrs (const GtkTextIter *iter,
2714 TestLogAttrFunc func)
2717 const PangoLogAttr *attrs;
2719 gboolean result = FALSE;
2721 g_return_val_if_fail (iter != NULL, FALSE);
2723 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2726 offset = gtk_text_iter_get_line_offset (iter);
2728 g_assert (char_len > 0);
2730 if (offset < char_len)
2731 result = (* func) (attrs, offset, 0, char_len);
2737 find_line_log_attrs (const GtkTextIter *iter,
2738 FindLogAttrFunc func,
2740 gboolean already_moved_initially)
2743 const PangoLogAttr *attrs;
2745 gboolean result = FALSE;
2747 g_return_val_if_fail (iter != NULL, FALSE);
2749 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2752 offset = gtk_text_iter_get_line_offset (iter);
2754 g_assert (char_len > 0);
2756 if (offset < char_len)
2757 result = (* func) (attrs, offset, 0, char_len, found_offset,
2758 already_moved_initially);
2763 /* FIXME this function is very, very gratuitously slow */
2765 find_by_log_attrs (GtkTextIter *iter,
2766 FindLogAttrFunc func,
2768 gboolean already_moved_initially)
2772 gboolean found = FALSE;
2774 g_return_val_if_fail (iter != NULL, FALSE);
2778 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2784 if (gtk_text_iter_forward_line (iter))
2785 return find_by_log_attrs (iter, func, forward,
2792 /* go to end of previous line */
2793 gtk_text_iter_set_line_offset (iter, 0);
2795 if (gtk_text_iter_backward_char (iter))
2796 return find_by_log_attrs (iter, func, forward,
2804 gtk_text_iter_set_line_offset (iter, offset);
2807 !gtk_text_iter_equal (iter, &orig) &&
2808 !gtk_text_iter_is_end (iter);
2813 * gtk_text_iter_forward_word_end:
2814 * @iter: a #GtkTextIter
2816 * Moves forward to the next word end. (If @iter is currently on a
2817 * word end, moves forward to the next one after that.) Word breaks
2818 * are determined by Pango and should be correct for nearly any
2819 * language (if not, the correct fix would be to the Pango word break
2822 * Return value: %TRUE if @iter moved and is not the end iterator
2825 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2827 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2831 * gtk_text_iter_forward_word_end:
2832 * @iter: a #GtkTextIter
2834 * Moves backward to the next word start. (If @iter is currently on a
2835 * word start, moves backward to the next one after that.) Word breaks
2836 * are determined by Pango and should be correct for nearly any
2837 * language (if not, the correct fix would be to the Pango word break
2840 * Return value: %TRUE if @iter moved and is not the end iterator
2843 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2845 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2848 /* FIXME a loop around a truly slow function means
2849 * a truly spectacularly slow function.
2853 * gtk_text_iter_forward_word_ends:
2854 * @iter: a #GtkTextIter
2855 * @count: number of times to move
2857 * Calls gtk_text_iter_forward_word_end() up to @count times.
2859 * Return value: %TRUE if @iter moved and is not the end iterator
2862 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2865 g_return_val_if_fail (iter != NULL, FALSE);
2871 return gtk_text_iter_backward_word_starts (iter, -count);
2873 if (!gtk_text_iter_forward_word_end (iter))
2879 if (!gtk_text_iter_forward_word_end (iter))
2887 * gtk_text_iter_backward_word_starts
2888 * @iter: a #GtkTextIter
2889 * @count: number of times to move
2891 * Calls gtk_text_iter_backward_word_starts() up to @count times.
2893 * Return value: %TRUE if @iter moved and is not the end iterator
2896 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2899 g_return_val_if_fail (iter != NULL, FALSE);
2902 return gtk_text_iter_forward_word_ends (iter, -count);
2904 if (!gtk_text_iter_backward_word_start (iter))
2910 if (!gtk_text_iter_backward_word_start (iter))
2918 * gtk_text_iter_starts_word:
2919 * @iter: a #GtkTextIter
2921 * Determines whether @iter begins a natural-language word. Word
2922 * breaks are determined by Pango and should be correct for nearly any
2923 * language (if not, the correct fix would be to the Pango word break
2926 * Return value: %TRUE if @iter is at the start of a word
2929 gtk_text_iter_starts_word (const GtkTextIter *iter)
2931 return test_log_attrs (iter, is_word_start_func);
2935 * gtk_text_iter_ends_word:
2936 * @iter: a #GtkTextIter
2938 * Determines whether @iter ends a natural-language word. Word breaks
2939 * are determined by Pango and should be correct for nearly any
2940 * language (if not, the correct fix would be to the Pango word break
2943 * Return value: %TRUE if @iter is at the end of a word
2946 gtk_text_iter_ends_word (const GtkTextIter *iter)
2948 return test_log_attrs (iter, is_word_end_func);
2952 * gtk_text_iter_inside_word:
2953 * @iter: a #GtkTextIter
2955 * Determines whether @iter is inside a natural-language word (as
2956 * opposed to say inside some whitespace). Word breaks are determined
2957 * by Pango and should be correct for nearly any language (if not, the
2958 * correct fix would be to the Pango word break algorithms).
2960 * Return value: %TRUE if @iter is inside a word
2963 gtk_text_iter_inside_word (const GtkTextIter *iter)
2965 return test_log_attrs (iter, inside_word_func);
2969 * gtk_text_iter_starts_sentence:
2970 * @iter: a #GtkTextIter
2972 * Determines whether @iter begins a sentence. Sentence boundaries are
2973 * determined by Pango and should be correct for nearly any language
2974 * (if not, the correct fix would be to the Pango text boundary
2977 * Return value: %TRUE if @iter is at the start of a sentence.
2980 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
2982 return test_log_attrs (iter, is_sentence_start_func);
2986 * gtk_text_iter_ends_sentence:
2987 * @iter: a #GtkTextIter
2989 * Determines whether @iter ends a sentence. Sentence boundaries are
2990 * determined by Pango and should be correct for nearly any language
2991 * (if not, the correct fix would be to the Pango text boundary
2994 * Return value: %TRUE if @iter is at the end of a sentence.
2997 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
2999 return test_log_attrs (iter, is_sentence_end_func);
3003 * gtk_text_iter_inside_sentence:
3004 * @iter: a #GtkTextIter
3006 * Determines whether @iter is inside a sentence (as opposed to in
3007 * between two sentences, e.g. after a period and before the first
3008 * letter of the next sentence). Sentence boundaries are determined
3009 * by Pango and should be correct for nearly any language (if not, the
3010 * correct fix would be to the Pango text boundary algorithms).
3012 * Return value: %TRUE if @iter is inside a sentence.
3015 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3017 return test_log_attrs (iter, inside_sentence_func);
3021 * gtk_text_iter_forward_sentence_end:
3022 * @iter: a #GtkTextIter
3024 * Moves forward to the next sentence end. (If @iter is at the end of
3025 * a sentence, moves to the next end of sentence.) Sentence
3026 * boundaries are determined by Pango and should be correct for nearly
3027 * any language (if not, the correct fix would be to the Pango text
3028 * boundary algorithms).
3030 * Return value: %TRUE if @iter moved and is not the end iterator
3033 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3035 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3039 * gtk_text_iter_backward_sentence_start:
3040 * @iter: a #GtkTextIter
3042 * Moves backward to the next sentence start; if @iter is already at
3043 * the start of a sentence, moves backward to the next one. Sentence
3044 * boundaries are determined by Pango and should be correct for nearly
3045 * any language (if not, the correct fix would be to the Pango text
3046 * boundary algorithms).
3048 * Return value: %TRUE if @iter moved and is not the end iterator
3051 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3053 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3056 /* FIXME a loop around a truly slow function means
3057 * a truly spectacularly slow function.
3060 * gtk_text_iter_forward_sentence_ends:
3061 * @iter: a #GtkTextIter
3062 * @count: number of sentences to move
3064 * Calls gtk_text_iter_forward_sentence_end() up to @count times.
3066 * Return value: %TRUE if @iter moved and is not the end iterator
3069 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3072 g_return_val_if_fail (iter != NULL, FALSE);
3078 return gtk_text_iter_backward_sentence_starts (iter, -count);
3080 if (!gtk_text_iter_forward_sentence_end (iter))
3086 if (!gtk_text_iter_forward_sentence_end (iter))
3094 * gtk_text_iter_forward_sentence_ends:
3095 * @iter: a #GtkTextIter
3096 * @count: number of sentences to move
3098 * Calls gtk_text_iter_backward_sentence_start() up to @count times.
3100 * Return value: %TRUE if @iter moved and is not the end iterator
3103 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3106 g_return_val_if_fail (iter != NULL, FALSE);
3109 return gtk_text_iter_forward_sentence_ends (iter, -count);
3111 if (!gtk_text_iter_backward_sentence_start (iter))
3117 if (!gtk_text_iter_backward_sentence_start (iter))
3125 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3130 gboolean already_moved_initially)
3132 if (!already_moved_initially)
3135 while (offset < (min_offset + len) &&
3136 !attrs[offset].is_cursor_position)
3139 *found_offset = offset;
3141 return offset < (min_offset + len);
3145 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3150 gboolean already_moved_initially)
3152 if (!already_moved_initially)
3155 while (offset > min_offset &&
3156 !attrs[offset].is_cursor_position)
3159 *found_offset = offset;
3161 return offset >= min_offset;
3165 is_cursor_pos_func (const PangoLogAttr *attrs,
3170 return attrs[offset].is_cursor_position;
3174 * gtk_text_iter_forward_cursor_position:
3175 * @iter: a #GtkTextIter
3177 * Moves @iter forward by a single cursor position. Cursor positions
3178 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3179 * surprisingly, there may not be a cursor position between all
3180 * characters. The most common example for European languages would be
3181 * a carriage return/newline sequence. For some Unicode characters,
3182 * the equivalent of say the letter "a" with an accent mark will be
3183 * represented as two characters, first the letter then a "combining
3184 * mark" that causes the accent to be rendered; so the cursor can't go
3185 * between those two characters. See also the #PangoLogAttr structure and
3186 * pango_break() function.
3188 * Return value: %TRUE if we moved and the new position is dereferenceable
3191 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3193 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3197 * gtk_text_iter_backward_cursor_position:
3198 * @iter: a #GtkTextIter
3200 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3202 * Return value: %TRUE if we moved and the new position is dereferenceable
3205 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3207 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3211 * gtk_text_iter_forward_cursor_positions:
3212 * @iter: a #GtkTextIter
3213 * @count: number of positions to move
3215 * Moves up to @count cursor positions. See
3216 * gtk_text_iter_forward_cursor_position() for details.
3218 * Return value: %TRUE if we moved and the new position is dereferenceable
3221 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3224 g_return_val_if_fail (iter != NULL, FALSE);
3230 return gtk_text_iter_backward_cursor_positions (iter, -count);
3232 if (!gtk_text_iter_forward_cursor_position (iter))
3238 if (!gtk_text_iter_forward_cursor_position (iter))
3246 * gtk_text_iter_backward_cursor_positions:
3247 * @iter: a #GtkTextIter
3248 * @count: number of positions to move
3250 * Moves up to @count cursor positions. See
3251 * gtk_text_iter_forward_cursor_position() for details.
3253 * Return value: %TRUE if we moved and the new position is dereferenceable
3256 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3259 g_return_val_if_fail (iter != NULL, FALSE);
3265 return gtk_text_iter_forward_cursor_positions (iter, -count);
3267 if (!gtk_text_iter_backward_cursor_position (iter))
3273 if (!gtk_text_iter_backward_cursor_position (iter))
3281 * gtk_text_iter_is_cursor_position:
3282 * @iter: a #GtkTextIter
3284 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3285 * pango_break() for details on what a cursor position is.
3287 * Return value: %TRUE if the cursor can be placed at @iter
3290 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3292 return test_log_attrs (iter, is_cursor_pos_func);
3296 * gtk_text_iter_set_line_offset:
3297 * @iter: a #GtkTextIter
3298 * @char_on_line: a character offset relative to the start of @iter's current line
3300 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3301 * (not byte) offset. The given character offset must be less than or
3302 * equal to the number of characters in the line; if equal, @iter
3303 * moves to the start of the next line. See
3304 * gtk_text_iter_set_line_index() if you have a byte index rather than
3305 * a character offset.
3309 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3312 GtkTextRealIter *real;
3315 g_return_if_fail (iter != NULL);
3317 real = gtk_text_iter_make_surreal (iter);
3322 check_invariants (iter);
3324 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3326 g_return_if_fail (char_on_line <= chars_in_line);
3328 if (char_on_line < chars_in_line)
3329 iter_set_from_char_offset (real, real->line, char_on_line);
3331 gtk_text_iter_forward_line (iter); /* set to start of next line */
3333 check_invariants (iter);
3337 * gtk_text_iter_set_line_index:
3338 * @iter: a #GtkTextIter
3339 * @byte_on_line: a byte index relative to the start of @iter's current line
3341 * Same as gtk_text_iter_set_line_offset(), but works with a
3342 * <emphasis>byte</emphasis> index. The given byte index must be at
3343 * the start of a character, it can't be in the middle of a UTF-8
3344 * encoded character.
3348 gtk_text_iter_set_line_index (GtkTextIter *iter,
3351 GtkTextRealIter *real;
3354 g_return_if_fail (iter != NULL);
3356 real = gtk_text_iter_make_surreal (iter);
3361 check_invariants (iter);
3363 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3365 g_return_if_fail (byte_on_line <= bytes_in_line);
3367 if (byte_on_line < bytes_in_line)
3368 iter_set_from_byte_offset (real, real->line, byte_on_line);
3370 gtk_text_iter_forward_line (iter);
3372 if (real->segment->type == >k_text_char_type &&
3373 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3374 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3375 "character; this will crash the text buffer. "
3376 "Byte indexes must refer to the start of a character.",
3377 G_STRLOC, byte_on_line);
3379 check_invariants (iter);
3384 * gtk_text_iter_set_visible_line_offset:
3385 * @iter: a #GtkTextIter
3386 * @char_on_line: a character offset
3388 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3389 * characters, i.e. text with a tag making it invisible is not
3390 * counted in the offset.
3393 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3396 gint chars_seen = 0;
3399 g_return_if_fail (iter != NULL);
3403 /* For now we use a ludicrously slow implementation */
3404 while (chars_seen < char_on_line)
3406 if (!_gtk_text_btree_char_is_invisible (&pos))
3409 if (!gtk_text_iter_forward_char (&pos))
3412 if (chars_seen == char_on_line)
3416 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3419 gtk_text_iter_forward_line (iter);
3423 bytes_in_char (GtkTextIter *iter)
3425 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3429 * gtk_text_iter_set_visible_line_index:
3430 * @iter: a #GtkTextIter
3431 * @byte_on_line: a byte index
3433 * Like gtk_text_iter_set_line_index(), but the index is in visible
3434 * bytes, i.e. text with a tag making it invisible is not counted
3438 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3441 gint bytes_seen = 0;
3444 g_return_if_fail (iter != NULL);
3448 /* For now we use a ludicrously slow implementation */
3449 while (bytes_seen < byte_on_line)
3451 if (!_gtk_text_btree_char_is_invisible (&pos))
3452 bytes_seen += bytes_in_char (&pos);
3454 if (!gtk_text_iter_forward_char (&pos))
3457 if (bytes_seen >= byte_on_line)
3461 if (bytes_seen > byte_on_line)
3462 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3463 "character; this will crash the text buffer. "
3464 "Byte indexes must refer to the start of a character.",
3465 G_STRLOC, byte_on_line);
3467 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3470 gtk_text_iter_forward_line (iter);
3474 * gtk_text_iter_set_line:
3475 * @iter: a #GtkTextIter
3476 * @line_number: line number (counted from 0)
3478 * Moves iterator @iter to the start of the line @line_number.
3482 gtk_text_iter_set_line (GtkTextIter *iter,
3487 GtkTextRealIter *real;
3489 g_return_if_fail (iter != NULL);
3491 real = gtk_text_iter_make_surreal (iter);
3496 check_invariants (iter);
3498 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3500 iter_set_from_char_offset (real, line, 0);
3502 /* We might as well cache this, since we know it. */
3503 real->cached_line_number = real_line;
3505 check_invariants (iter);
3509 * gtk_text_iter_set_offset:
3510 * @iter: a #GtkTextIter
3511 * @char_offset: a character number
3513 * Sets @iter to point to @char_offset. @char_offset counts from the start
3514 * of the entire text buffer, starting with 0.
3518 gtk_text_iter_set_offset (GtkTextIter *iter,
3522 GtkTextRealIter *real;
3524 gint real_char_index;
3526 g_return_if_fail (iter != NULL);
3528 real = gtk_text_iter_make_surreal (iter);
3533 check_invariants (iter);
3535 if (real->cached_char_index >= 0 &&
3536 real->cached_char_index == char_offset)
3539 line = _gtk_text_btree_get_line_at_char (real->tree,
3544 iter_set_from_char_offset (real, line, real_char_index - line_start);
3546 /* Go ahead and cache this since we have it. */
3547 real->cached_char_index = real_char_index;
3549 check_invariants (iter);
3553 * gtk_text_iter_forward_to_end:
3554 * @iter: a #GtkTextIter
3556 * Moves @iter forward to the "end iterator," which points one past the last
3557 * valid character in the buffer. gtk_text_iter_get_char() called on the
3558 * end iterator returns 0, which is convenient for writing loops.
3562 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3564 GtkTextBuffer *buffer;
3565 GtkTextRealIter *real;
3567 g_return_if_fail (iter != NULL);
3569 real = gtk_text_iter_make_surreal (iter);
3574 buffer = _gtk_text_btree_get_buffer (real->tree);
3576 gtk_text_buffer_get_end_iter (buffer, iter);
3580 * gtk_text_iter_forward_to_line_end:
3581 * @iter: a #GtkTextIter
3583 * Moves the iterator to point to the paragraph delimiter characters,
3584 * which will be either a newline, a carriage return, a carriage
3585 * return/newline in sequence, or the Unicode paragraph separator
3586 * character. If the iterator is already at the paragraph delimiter
3587 * characters, moves to the paragraph delimiter characters for the
3590 * Return value: %TRUE if we moved and the new location is not the end iterator
3593 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3595 gint current_offset;
3598 g_return_val_if_fail (iter != NULL, FALSE);
3600 current_offset = gtk_text_iter_get_line_offset (iter);
3601 /* FIXME assumption that line ends in a newline; broken */
3602 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3604 if (current_offset < new_offset)
3606 /* Move to end of this line. */
3607 gtk_text_iter_set_line_offset (iter, new_offset);
3612 /* Move to end of next line. */
3613 if (gtk_text_iter_forward_line (iter))
3615 /* We don't want to move past all
3618 if (!gtk_text_iter_ends_line (iter))
3619 gtk_text_iter_forward_to_line_end (iter);
3628 * gtk_text_iter_forward_to_tag_toggle:
3629 * @iter: a #GtkTextIter
3630 * @tag: a #GtkTextTag, or NULL
3632 * Moves forward to the next toggle (on or off) of the
3633 * #GtkTextTag @tag, or to the next toggle of any tag if
3634 * @tag is NULL. If no matching tag toggles are found,
3635 * returns FALSE, otherwise TRUE. Does not return toggles
3636 * located at @iter, only toggles after @iter. Sets @iter to
3637 * the location of the toggle, or to the end of the buffer
3638 * if no toggle is found.
3640 * Return value: whether we found a tag toggle after @iter
3643 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3646 GtkTextLine *next_line;
3647 GtkTextLine *current_line;
3648 GtkTextRealIter *real;
3650 g_return_val_if_fail (iter != NULL, FALSE);
3652 real = gtk_text_iter_make_real (iter);
3657 check_invariants (iter);
3659 current_line = real->line;
3660 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3663 while (_gtk_text_iter_forward_indexable_segment (iter))
3665 /* If we went forward to a line that couldn't contain a toggle
3666 for the tag, then skip forward to a line that could contain
3667 it. This potentially skips huge hunks of the tree, so we
3668 aren't a purely linear search. */
3669 if (real->line != current_line)
3671 if (next_line == NULL)
3673 /* End of search. Set to end of buffer. */
3674 _gtk_text_btree_get_end_iter (real->tree, iter);
3678 if (real->line != next_line)
3679 iter_set_from_byte_offset (real, next_line, 0);
3681 current_line = real->line;
3682 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3687 if (gtk_text_iter_toggles_tag (iter, tag))
3689 /* If there's a toggle here, it isn't indexable so
3690 any_segment can't be the indexable segment. */
3691 g_assert (real->any_segment != real->segment);
3696 /* Check end iterator for tags */
3697 if (gtk_text_iter_toggles_tag (iter, tag))
3699 /* If there's a toggle here, it isn't indexable so
3700 any_segment can't be the indexable segment. */
3701 g_assert (real->any_segment != real->segment);
3705 /* Reached end of buffer */
3710 * gtk_text_iter_backward_to_tag_toggle:
3711 * @iter: a #GtkTextIter
3712 * @tag: a #GtkTextTag, or NULL
3714 * Moves backward to the next toggle (on or off) of the
3715 * #GtkTextTag @tag, or to the next toggle of any tag if
3716 * @tag is NULL. If no matching tag toggles are found,
3717 * returns FALSE, otherwise TRUE. Does not return toggles
3718 * located at @iter, only toggles before @iter. Sets @iter
3719 * to the location of the toggle, or the start of the buffer
3720 * if no toggle is found.
3722 * Return value: whether we found a tag toggle before @iter
3725 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3728 GtkTextLine *prev_line;
3729 GtkTextLine *current_line;
3730 GtkTextRealIter *real;
3732 g_return_val_if_fail (iter != NULL, FALSE);
3734 real = gtk_text_iter_make_real (iter);
3739 check_invariants (iter);
3741 current_line = real->line;
3742 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3746 /* If we're at segment start, go to the previous segment;
3747 * if mid-segment, snap to start of current segment.
3749 if (is_segment_start (real))
3751 if (!_gtk_text_iter_backward_indexable_segment (iter))
3756 ensure_char_offsets (real);
3758 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3764 /* If we went backward to a line that couldn't contain a toggle
3765 * for the tag, then skip backward further to a line that
3766 * could contain it. This potentially skips huge hunks of the
3767 * tree, so we aren't a purely linear search.
3769 if (real->line != current_line)
3771 if (prev_line == NULL)
3773 /* End of search. Set to start of buffer. */
3774 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3778 if (real->line != prev_line)
3780 /* Set to last segment in prev_line (could do this
3783 iter_set_from_byte_offset (real, prev_line, 0);
3785 while (!at_last_indexable_segment (real))
3786 _gtk_text_iter_forward_indexable_segment (iter);
3789 current_line = real->line;
3790 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3795 if (gtk_text_iter_toggles_tag (iter, tag))
3797 /* If there's a toggle here, it isn't indexable so
3798 * any_segment can't be the indexable segment.
3800 g_assert (real->any_segment != real->segment);
3804 while (_gtk_text_iter_backward_indexable_segment (iter));
3806 /* Reached front of buffer */
3811 matches_pred (GtkTextIter *iter,
3812 GtkTextCharPredicate pred,
3817 ch = gtk_text_iter_get_char (iter);
3819 return (*pred) (ch, user_data);
3823 * gtk_text_iter_forward_find_char:
3824 * @iter: a #GtkTextIter
3825 * @pred: a function to be called on each character
3826 * @user_data: user data for @pred
3827 * @limit: search limit, or %NULL for none
3829 * Advances @iter, calling @pred on each character. If
3830 * @pred returns %TRUE, returns %TRUE and stops scanning.
3831 * If @pred never returns %TRUE, @iter is set to @limit if
3832 * @limit is non-%NULL, otherwise to the end iterator.
3834 * Return value: whether a match was found
3837 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3838 GtkTextCharPredicate pred,
3840 const GtkTextIter *limit)
3842 g_return_val_if_fail (iter != NULL, FALSE);
3843 g_return_val_if_fail (pred != NULL, FALSE);
3846 gtk_text_iter_compare (iter, limit) >= 0)
3849 while ((limit == NULL ||
3850 !gtk_text_iter_equal (limit, iter)) &&
3851 gtk_text_iter_forward_char (iter))
3853 if (matches_pred (iter, pred, user_data))
3861 * gtk_text_iter_backward_find_char:
3862 * @iter: a #GtkTextIter
3863 * @pred: function to be called on each character
3864 * @user_data: user data for @pred
3865 * @limit: search limit, or %NULL for none
3867 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
3869 * Return value: whether a match was found
3872 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3873 GtkTextCharPredicate pred,
3875 const GtkTextIter *limit)
3877 g_return_val_if_fail (iter != NULL, FALSE);
3878 g_return_val_if_fail (pred != NULL, FALSE);
3881 gtk_text_iter_compare (iter, limit) <= 0)
3884 while ((limit == NULL ||
3885 !gtk_text_iter_equal (limit, iter)) &&
3886 gtk_text_iter_backward_char (iter))
3888 if (matches_pred (iter, pred, user_data))
3896 forward_chars_with_skipping (GtkTextIter *iter,
3898 gboolean skip_invisible,
3899 gboolean skip_nontext)
3904 g_return_if_fail (count >= 0);
3910 gboolean ignored = FALSE;
3913 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3918 _gtk_text_btree_char_is_invisible (iter))
3921 gtk_text_iter_forward_char (iter);
3929 lines_match (const GtkTextIter *start,
3930 const gchar **lines,
3931 gboolean visible_only,
3933 GtkTextIter *match_start,
3934 GtkTextIter *match_end)
3941 if (*lines == NULL || **lines == '\0')
3944 *match_start = *start;
3947 *match_end = *start;
3952 gtk_text_iter_forward_line (&next);
3954 /* No more text in buffer, but *lines is nonempty */
3955 if (gtk_text_iter_equal (start, &next))
3963 line_text = gtk_text_iter_get_visible_slice (start, &next);
3965 line_text = gtk_text_iter_get_slice (start, &next);
3970 line_text = gtk_text_iter_get_visible_text (start, &next);
3972 line_text = gtk_text_iter_get_text (start, &next);
3975 if (match_start) /* if this is the first line we're matching */
3976 found = strstr (line_text, *lines);
3979 /* If it's not the first line, we have to match from the
3980 * start of the line.
3982 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
3994 /* Get offset to start of search string */
3995 offset = g_utf8_strlen (line_text, found - line_text);
3999 /* If match start needs to be returned, set it to the
4000 * start of the search string.
4004 *match_start = next;
4006 forward_chars_with_skipping (match_start, offset,
4007 visible_only, !slice);
4010 /* Go to end of search string */
4011 offset += g_utf8_strlen (*lines, -1);
4013 forward_chars_with_skipping (&next, offset,
4014 visible_only, !slice);
4023 /* pass NULL for match_start, since we don't need to find the
4026 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4029 /* strsplit () that retains the delimiter as part of the string. */
4031 strbreakup (const char *string,
4032 const char *delimiter,
4035 GSList *string_list = NULL, *slist;
4036 gchar **str_array, *s;
4039 g_return_val_if_fail (string != NULL, NULL);
4040 g_return_val_if_fail (delimiter != NULL, NULL);
4043 max_tokens = G_MAXINT;
4045 s = strstr (string, delimiter);
4048 guint delimiter_len = strlen (delimiter);
4055 len = s - string + delimiter_len;
4056 new_string = g_new (gchar, len + 1);
4057 strncpy (new_string, string, len);
4058 new_string[len] = 0;
4059 string_list = g_slist_prepend (string_list, new_string);
4061 string = s + delimiter_len;
4062 s = strstr (string, delimiter);
4064 while (--max_tokens && s);
4069 string_list = g_slist_prepend (string_list, g_strdup (string));
4072 str_array = g_new (gchar*, n);
4076 str_array[i--] = NULL;
4077 for (slist = string_list; slist; slist = slist->next)
4078 str_array[i--] = slist->data;
4080 g_slist_free (string_list);
4086 * gtk_text_iter_forward_search:
4087 * @iter: start of search
4088 * @str: a search string
4089 * @visible_only: if %TRUE, search only visible text
4090 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4091 * @match_start: return location for start of match, or %NULL
4092 * @match_end: return location for end of match, or %NULL
4093 * @limit: bound for the search, or %NULL for the end of the buffer
4095 * Searches forward for @str. Any match is returned as the range @match_start,
4096 * @match_end. If you specify @visible_only or @slice, the match may have
4097 * invisible text, pixbufs, or child widgets interspersed in @str.
4099 * Return value: whether a match was found
4102 gtk_text_iter_forward_search (const GtkTextIter *iter,
4104 gboolean visible_only,
4106 GtkTextIter *match_start,
4107 GtkTextIter *match_end,
4108 const GtkTextIter *limit)
4110 gchar **lines = NULL;
4112 gboolean retval = FALSE;
4115 g_return_val_if_fail (iter != NULL, FALSE);
4116 g_return_val_if_fail (str != NULL, FALSE);
4119 gtk_text_iter_compare (iter, limit) >= 0)
4124 /* If we can move one char, return the empty string there */
4127 if (gtk_text_iter_forward_char (&match))
4130 gtk_text_iter_equal (&match, limit))
4134 *match_start = match;
4143 /* locate all lines */
4145 lines = strbreakup (str, "\n", -1);
4151 /* This loop has an inefficient worst-case, where
4152 * gtk_text_iter_get_text () is called repeatedly on
4158 gtk_text_iter_compare (&search, limit) >= 0)
4161 if (lines_match (&search, (const gchar**)lines,
4162 visible_only, slice, &match, &end))
4164 if (limit == NULL ||
4166 gtk_text_iter_compare (&end, limit) < 0))
4171 *match_start = match;
4180 while (gtk_text_iter_forward_line (&search));
4182 g_strfreev ((gchar**)lines);
4188 vectors_equal_ignoring_trailing (gchar **vec1,
4191 /* Ignores trailing chars in vec2's last line */
4200 if (strcmp (*i1, *i2) != 0)
4202 if (*(i2 + 1) == NULL) /* if this is the last line */
4204 gint len1 = strlen (*i1);
4205 gint len2 = strlen (*i2);
4208 strncmp (*i1, *i2, len1) == 0)
4210 /* We matched ignoring the trailing stuff in vec2 */
4235 typedef struct _LinesWindow LinesWindow;
4241 GtkTextIter first_line_start;
4242 GtkTextIter first_line_end;
4244 gboolean visible_only;
4248 lines_window_init (LinesWindow *win,
4249 const GtkTextIter *start)
4252 GtkTextIter line_start;
4253 GtkTextIter line_end;
4255 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4258 if (gtk_text_iter_is_start (start) ||
4259 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4261 /* Already at the end, or not enough lines to match */
4262 win->lines = g_new0 (gchar*, 1);
4267 line_start = *start;
4270 /* Move to start iter to start of line */
4271 gtk_text_iter_set_line_offset (&line_start, 0);
4273 if (gtk_text_iter_equal (&line_start, &line_end))
4275 /* we were already at the start; so go back one line */
4276 gtk_text_iter_backward_line (&line_start);
4279 win->first_line_start = line_start;
4280 win->first_line_end = line_end;
4282 win->lines = g_new0 (gchar*, win->n_lines + 1);
4284 i = win->n_lines - 1;
4291 if (win->visible_only)
4292 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4294 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4298 if (win->visible_only)
4299 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4301 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4304 win->lines[i] = line_text;
4306 line_end = line_start;
4307 gtk_text_iter_backward_line (&line_start);
4314 lines_window_back (LinesWindow *win)
4316 GtkTextIter new_start;
4319 new_start = win->first_line_start;
4321 if (!gtk_text_iter_backward_line (&new_start))
4325 win->first_line_start = new_start;
4326 win->first_line_end = new_start;
4328 gtk_text_iter_forward_line (&win->first_line_end);
4333 if (win->visible_only)
4334 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4335 &win->first_line_end);
4337 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4338 &win->first_line_end);
4342 if (win->visible_only)
4343 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4344 &win->first_line_end);
4346 line_text = gtk_text_iter_get_text (&win->first_line_start,
4347 &win->first_line_end);
4350 /* Move lines to make room for first line. */
4351 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4353 *win->lines = line_text;
4355 /* Free old last line and NULL-terminate */
4356 g_free (win->lines[win->n_lines]);
4357 win->lines[win->n_lines] = NULL;
4363 lines_window_free (LinesWindow *win)
4365 g_strfreev (win->lines);
4369 my_strrstr (const gchar *haystack,
4370 const gchar *needle)
4372 /* FIXME GLib should have a nice implementation in it, this
4376 gint haystack_len = strlen (haystack);
4377 gint needle_len = strlen (needle);
4378 const gchar *needle_end = needle + needle_len;
4379 const gchar *haystack_rend = haystack - 1;
4380 const gchar *needle_rend = needle - 1;
4383 p = haystack + haystack_len;
4384 while (p != haystack)
4386 const gchar *n = needle_end - 1;
4387 const gchar *s = p - 1;
4388 while (s != haystack_rend &&
4396 if (n == needle_rend)
4406 * gtk_text_iter_backward_search:
4407 * @iter: a #GtkTextIter where the search begins
4408 * @str: search string
4409 * @visible_only: if %TRUE search only visible text
4410 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4411 * @match_start: return location for start of match, or %NULL
4412 * @match_end: return location for end of match, or %NULL
4413 * @limit: location of last possible @match_start, or %NULL for start of buffer
4415 * Same as gtk_text_iter_forward_search(), but moves backward.
4417 * Return value: whether a match was found
4420 gtk_text_iter_backward_search (const GtkTextIter *iter,
4422 gboolean visible_only,
4424 GtkTextIter *match_start,
4425 GtkTextIter *match_end,
4426 const GtkTextIter *limit)
4428 gchar **lines = NULL;
4432 gboolean retval = FALSE;
4434 g_return_val_if_fail (iter != NULL, FALSE);
4435 g_return_val_if_fail (str != NULL, FALSE);
4438 gtk_text_iter_compare (limit, iter) > 0)
4443 /* If we can move one char, return the empty string there */
4444 GtkTextIter match = *iter;
4446 if (limit && gtk_text_iter_equal (limit, &match))
4449 if (gtk_text_iter_backward_char (&match))
4452 *match_start = match;
4461 /* locate all lines */
4463 lines = strbreakup (str, "\n", -1);
4473 win.n_lines = n_lines;
4475 win.visible_only = visible_only;
4477 lines_window_init (&win, iter);
4479 if (*win.lines == NULL)
4484 gchar *first_line_match;
4487 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4489 /* We're now before the search limit, abort. */
4493 /* If there are multiple lines, the first line will
4494 * end in '\n', so this will only match at the
4495 * end of the first line, which is correct.
4497 first_line_match = my_strrstr (*win.lines, *lines);
4499 if (first_line_match &&
4500 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4505 GtkTextIter start_tmp;
4507 /* Offset to start of search string */
4508 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4510 next = win.first_line_start;
4512 forward_chars_with_skipping (&start_tmp, offset,
4513 visible_only, !slice);
4516 gtk_text_iter_compare (limit, &start_tmp) > 0)
4517 goto out; /* match was bogus */
4520 *match_start = start_tmp;
4522 /* Go to end of search string */
4526 offset += g_utf8_strlen (*l, -1);
4530 forward_chars_with_skipping (&next, offset,
4531 visible_only, !slice);
4540 while (lines_window_back (&win));
4543 lines_window_free (&win);
4554 * gtk_text_iter_equal:
4555 * @lhs: a #GtkTextIter
4556 * @rhs: another #GtkTextIter
4558 * Tests whether two iterators are equal, using the fastest possible
4559 * mechanism. This function is very fast; you can expect it to perform
4560 * better than e.g. getting the character offset for each iterator and
4561 * comparing the offsets yourself. Also, it's a bit faster than
4562 * gtk_text_iter_compare().
4564 * Return value: %TRUE if the iterators point to the same place in the buffer
4567 gtk_text_iter_equal (const GtkTextIter *lhs,
4568 const GtkTextIter *rhs)
4570 GtkTextRealIter *real_lhs;
4571 GtkTextRealIter *real_rhs;
4573 real_lhs = (GtkTextRealIter*)lhs;
4574 real_rhs = (GtkTextRealIter*)rhs;
4576 check_invariants (lhs);
4577 check_invariants (rhs);
4579 if (real_lhs->line != real_rhs->line)
4581 else if (real_lhs->line_byte_offset >= 0 &&
4582 real_rhs->line_byte_offset >= 0)
4583 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4586 /* the ensure_char_offsets () calls do nothing if the char offsets
4587 are already up-to-date. */
4588 ensure_char_offsets (real_lhs);
4589 ensure_char_offsets (real_rhs);
4590 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4595 * gtk_text_iter_compare:
4596 * @lhs: a #GtkTextIter
4597 * @rhs: another #GtkTextIter
4599 * A qsort()-style function that returns negative if @lhs is less than
4600 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4601 * Ordering is in character offset order, i.e. the first character in the buffer
4602 * is less than the second character in the buffer.
4604 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4607 gtk_text_iter_compare (const GtkTextIter *lhs,
4608 const GtkTextIter *rhs)
4610 GtkTextRealIter *real_lhs;
4611 GtkTextRealIter *real_rhs;
4613 real_lhs = gtk_text_iter_make_surreal (lhs);
4614 real_rhs = gtk_text_iter_make_surreal (rhs);
4616 if (real_lhs == NULL ||
4618 return -1; /* why not */
4620 check_invariants (lhs);
4621 check_invariants (rhs);
4623 if (real_lhs->line == real_rhs->line)
4625 gint left_index, right_index;
4627 if (real_lhs->line_byte_offset >= 0 &&
4628 real_rhs->line_byte_offset >= 0)
4630 left_index = real_lhs->line_byte_offset;
4631 right_index = real_rhs->line_byte_offset;
4635 /* the ensure_char_offsets () calls do nothing if
4636 the offsets are already up-to-date. */
4637 ensure_char_offsets (real_lhs);
4638 ensure_char_offsets (real_rhs);
4639 left_index = real_lhs->line_char_offset;
4640 right_index = real_rhs->line_char_offset;
4643 if (left_index < right_index)
4645 else if (left_index > right_index)
4654 line1 = gtk_text_iter_get_line (lhs);
4655 line2 = gtk_text_iter_get_line (rhs);
4658 else if (line1 > line2)
4666 * gtk_text_iter_in_range:
4667 * @iter: a #GtkTextIter
4668 * @start: start of range
4669 * @end: end of range
4671 * @start and @end must be in order, unlike most text buffer
4672 * functions, for efficiency reasons. The function returns %TRUE if
4673 * @iter falls in the range [@start, @end).
4675 * Return value: %TRUE if @iter is in the range
4678 gtk_text_iter_in_range (const GtkTextIter *iter,
4679 const GtkTextIter *start,
4680 const GtkTextIter *end)
4682 return gtk_text_iter_compare (iter, start) >= 0 &&
4683 gtk_text_iter_compare (iter, end) < 0;
4687 * gtk_text_iter_order:
4688 * @first: a #GtkTextIter
4689 * @second: another #GtkTextIter
4691 * Swaps the value of @first and @second if @second comes before
4692 * @first in the buffer. That is, ensures that @first and @second are
4693 * in sequence. Most text buffer functions that take a range call this
4694 * automatically on your behalf, so there's no real reason to call it yourself
4695 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4696 * that expect a pre-sorted range.
4700 gtk_text_iter_order (GtkTextIter *first,
4701 GtkTextIter *second)
4703 g_return_if_fail (first != NULL);
4704 g_return_if_fail (second != NULL);
4706 if (gtk_text_iter_compare (first, second) > 0)
4717 * Init iterators from the BTree
4721 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4725 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4726 gint real_char_index;
4730 g_return_if_fail (iter != NULL);
4731 g_return_if_fail (tree != NULL);
4733 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4734 &line_start, &real_char_index);
4736 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4738 real->cached_char_index = real_char_index;
4740 check_invariants (iter);
4744 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4749 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4753 g_return_if_fail (iter != NULL);
4754 g_return_if_fail (tree != NULL);
4756 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4758 iter_init_from_char_offset (iter, tree, line, char_on_line);
4760 /* We might as well cache this, since we know it. */
4761 real->cached_line_number = real_line;
4763 check_invariants (iter);
4767 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4772 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4776 g_return_if_fail (iter != NULL);
4777 g_return_if_fail (tree != NULL);
4779 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4781 iter_init_from_byte_offset (iter, tree, line, byte_index);
4783 /* We might as well cache this, since we know it. */
4784 real->cached_line_number = real_line;
4786 check_invariants (iter);
4790 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4795 g_return_if_fail (iter != NULL);
4796 g_return_if_fail (tree != NULL);
4797 g_return_if_fail (line != NULL);
4799 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4801 check_invariants (iter);
4805 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4811 g_return_val_if_fail (iter != NULL, FALSE);
4812 g_return_val_if_fail (tree != NULL, FALSE);
4814 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4818 /* Set iter to last in tree */
4819 _gtk_text_btree_get_end_iter (tree, iter);
4820 check_invariants (iter);
4825 iter_init_from_byte_offset (iter, tree, line, 0);
4826 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4827 check_invariants (iter);
4833 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4837 g_return_val_if_fail (iter != NULL, FALSE);
4838 g_return_val_if_fail (tree != NULL, FALSE);
4840 _gtk_text_btree_get_end_iter (tree, iter);
4841 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4842 check_invariants (iter);
4848 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4850 const gchar *mark_name)
4854 g_return_val_if_fail (iter != NULL, FALSE);
4855 g_return_val_if_fail (tree != NULL, FALSE);
4857 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4863 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4864 check_invariants (iter);
4870 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4874 GtkTextLineSegment *seg;
4876 g_return_if_fail (iter != NULL);
4877 g_return_if_fail (tree != NULL);
4878 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4880 seg = mark->segment;
4882 iter_init_from_segment (iter, tree,
4883 seg->body.mark.line, seg);
4884 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4885 check_invariants (iter);
4889 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4891 GtkTextChildAnchor *anchor)
4893 GtkTextLineSegment *seg;
4895 g_return_if_fail (iter != NULL);
4896 g_return_if_fail (tree != NULL);
4897 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4899 seg = anchor->segment;
4901 iter_init_from_segment (iter, tree,
4902 seg->body.child.line, seg);
4903 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4904 check_invariants (iter);
4908 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
4911 g_return_if_fail (iter != NULL);
4912 g_return_if_fail (tree != NULL);
4914 _gtk_text_btree_get_iter_at_char (tree,
4916 _gtk_text_btree_char_count (tree));
4917 check_invariants (iter);
4921 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
4923 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4925 g_return_if_fail (iter != NULL);
4927 if (real->chars_changed_stamp != _gtk_text_btree_get_chars_changed_stamp (real->tree))
4928 g_print (" %20s: <invalidated iterator>\n", desc);
4931 check_invariants (iter);
4932 g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
4934 gtk_text_iter_get_line (iter),
4935 gtk_text_iter_get_offset (iter),
4936 gtk_text_iter_get_line_offset (iter),
4937 gtk_text_iter_get_line_index (iter));
4938 check_invariants (iter);
4943 _gtk_text_iter_check (const GtkTextIter *iter)
4945 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
4946 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
4947 GtkTextLineSegment *byte_segment = NULL;
4948 GtkTextLineSegment *byte_any_segment = NULL;
4949 GtkTextLineSegment *char_segment = NULL;
4950 GtkTextLineSegment *char_any_segment = NULL;
4951 gboolean segments_updated;
4953 /* This function checks our class invariants for the Iter class. */
4955 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
4957 if (real->chars_changed_stamp !=
4958 _gtk_text_btree_get_chars_changed_stamp (real->tree))
4959 g_error ("iterator check failed: invalid iterator");
4961 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
4962 g_error ("iterator check failed: both char and byte offsets are invalid");
4964 segments_updated = (real->segments_changed_stamp ==
4965 _gtk_text_btree_get_segments_changed_stamp (real->tree));
4968 printf ("checking iter, segments %s updated, byte %d char %d\n",
4969 segments_updated ? "are" : "aren't",
4970 real->line_byte_offset,
4971 real->line_char_offset);
4974 if (segments_updated)
4976 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
4977 g_error ("iterator check failed: both char and byte segment offsets are invalid");
4979 if (real->segment->char_count == 0)
4980 g_error ("iterator check failed: segment is not indexable.");
4982 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
4983 g_error ("segment char offset is not properly up-to-date");
4985 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
4986 g_error ("segment byte offset is not properly up-to-date");
4988 if (real->segment_byte_offset >= 0 &&
4989 real->segment_byte_offset >= real->segment->byte_count)
4990 g_error ("segment byte offset is too large.");
4992 if (real->segment_char_offset >= 0 &&
4993 real->segment_char_offset >= real->segment->char_count)
4994 g_error ("segment char offset is too large.");
4997 if (real->line_byte_offset >= 0)
4999 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5000 &byte_segment, &byte_any_segment,
5001 &seg_byte_offset, &line_byte_offset);
5003 if (line_byte_offset != real->line_byte_offset)
5004 g_error ("wrong byte offset was stored in iterator");
5006 if (segments_updated)
5008 if (real->segment != byte_segment)
5009 g_error ("wrong segment was stored in iterator");
5011 if (real->any_segment != byte_any_segment)
5012 g_error ("wrong any_segment was stored in iterator");
5014 if (seg_byte_offset != real->segment_byte_offset)
5015 g_error ("wrong segment byte offset was stored in iterator");
5017 if (byte_segment->type == >k_text_char_type)
5020 p = byte_segment->body.chars + seg_byte_offset;
5022 if (!gtk_text_byte_begins_utf8_char (p))
5023 g_error ("broken iterator byte index pointed into the middle of a character");
5028 if (real->line_char_offset >= 0)
5030 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5031 &char_segment, &char_any_segment,
5032 &seg_char_offset, &line_char_offset);
5034 if (line_char_offset != real->line_char_offset)
5035 g_error ("wrong char offset was stored in iterator");
5037 if (segments_updated)
5039 if (real->segment != char_segment)
5040 g_error ("wrong segment was stored in iterator");
5042 if (real->any_segment != char_any_segment)
5043 g_error ("wrong any_segment was stored in iterator");
5045 if (seg_char_offset != real->segment_char_offset)
5046 g_error ("wrong segment char offset was stored in iterator");
5048 if (char_segment->type == >k_text_char_type)
5051 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5054 /* hmm, not likely to happen eh */
5055 if (!gtk_text_byte_begins_utf8_char (p))
5056 g_error ("broken iterator char offset pointed into the middle of a character");
5061 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5063 if (byte_segment != char_segment)
5064 g_error ("char and byte offsets did not point to the same segment");
5066 if (byte_any_segment != char_any_segment)
5067 g_error ("char and byte offsets did not point to the same any segment");
5069 /* Make sure the segment offsets are equivalent, if it's a char
5071 if (char_segment->type == >k_text_char_type)
5073 gint byte_offset = 0;
5074 gint char_offset = 0;
5075 while (char_offset < seg_char_offset)
5077 const char * start = char_segment->body.chars + byte_offset;
5078 byte_offset += g_utf8_next_char (start) - start;
5082 if (byte_offset != seg_byte_offset)
5083 g_error ("byte offset did not correspond to char offset");
5086 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5088 if (char_offset != seg_char_offset)
5089 g_error ("char offset did not correspond to byte offset");
5091 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5092 g_error ("byte index for iterator does not index the start of a character");
5096 if (real->cached_line_number >= 0)
5100 should_be = _gtk_text_line_get_number (real->line);
5101 if (real->cached_line_number != should_be)
5102 g_error ("wrong line number was cached");
5105 if (real->cached_char_index >= 0)
5107 if (real->line_char_offset >= 0) /* only way we can check it
5108 efficiently, not a real
5113 char_index = _gtk_text_line_char_index (real->line);
5114 char_index += real->line_char_offset;
5116 if (real->cached_char_index != char_index)
5117 g_error ("wrong char index was cached");