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;
1388 values = gtk_text_attributes_new ();
1390 gtk_text_iter_get_attributes (iter, values);
1392 retval = g_strdup (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.
1633 * gtk_text_iter_get_attributes () will modify @values, applying the
1634 * effects of any tags present at @iter. If any tags affected @values,
1635 * the function returns TRUE.
1637 * Return value: TRUE if @values was modified
1640 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1641 GtkTextAttributes *values)
1646 /* Get the tags at this spot */
1647 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1649 /* No tags, use default style */
1650 if (tags == NULL || tag_count == 0)
1658 /* Sort tags in ascending order of priority */
1659 _gtk_text_tag_array_sort (tags, tag_count);
1661 _gtk_text_attributes_fill_from_tags (values,
1671 * Increments/decrements
1674 /* The return value of this indicates WHETHER WE MOVED.
1675 * The return value of public functions indicates
1676 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1679 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1681 GtkTextLine *new_line;
1683 new_line = _gtk_text_line_next (real->line);
1685 g_assert (new_line != real->line);
1687 if (new_line != NULL)
1689 real->line = new_line;
1691 real->line_byte_offset = 0;
1692 real->line_char_offset = 0;
1694 real->segment_byte_offset = 0;
1695 real->segment_char_offset = 0;
1697 /* Find first segments in new line */
1698 real->any_segment = real->line->segments;
1699 real->segment = real->any_segment;
1700 while (real->segment->char_count == 0)
1701 real->segment = real->segment->next;
1707 /* There is no way to move forward; we were already
1708 at the "end" index. (the end index is the last
1709 line pointer, segment_byte_offset of 0) */
1711 g_assert (real->line_char_offset == 0 ||
1712 real->line_byte_offset == 0);
1714 /* The only indexable segment allowed on the bogus
1715 line at the end is a single char segment containing
1717 if (real->segments_changed_stamp ==
1718 _gtk_text_btree_get_segments_changed_stamp (real->tree))
1720 g_assert (real->segment->type == >k_text_char_type);
1721 g_assert (real->segment->char_count == 1);
1723 /* We leave real->line as-is */
1730 /* The return value of this indicates WHETHER WE MOVED.
1731 * The return value of public functions indicates
1732 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1735 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1737 GtkTextLine *new_line;
1739 new_line = _gtk_text_line_previous (real->line);
1741 g_assert (new_line != real->line);
1743 if (new_line != NULL)
1745 real->line = new_line;
1747 real->line_byte_offset = 0;
1748 real->line_char_offset = 0;
1750 real->segment_byte_offset = 0;
1751 real->segment_char_offset = 0;
1753 /* Find first segments in new line */
1754 real->any_segment = real->line->segments;
1755 real->segment = real->any_segment;
1756 while (real->segment->char_count == 0)
1757 real->segment = real->segment->next;
1763 /* There is no way to move backward; we were already
1764 at the first line. */
1766 /* We leave real->line as-is */
1768 /* Note that we didn't clamp to the start of the first line. */
1774 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1778 forward_char (GtkTextRealIter *real)
1780 GtkTextIter *iter = (GtkTextIter*)real;
1782 check_invariants ((GtkTextIter*)real);
1784 ensure_char_offsets (real);
1786 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1788 /* Need to move to the next segment; if no next segment,
1789 need to move to next line. */
1790 return _gtk_text_iter_forward_indexable_segment (iter);
1794 /* Just moving within a segment. Keep byte count
1795 up-to-date, if it was already up-to-date. */
1797 g_assert (real->segment->type == >k_text_char_type);
1799 if (real->line_byte_offset >= 0)
1802 const char * start =
1803 real->segment->body.chars + real->segment_byte_offset;
1805 bytes = g_utf8_next_char (start) - start;
1807 real->line_byte_offset += bytes;
1808 real->segment_byte_offset += bytes;
1810 g_assert (real->segment_byte_offset < real->segment->byte_count);
1813 real->line_char_offset += 1;
1814 real->segment_char_offset += 1;
1816 adjust_char_index (real, 1);
1818 g_assert (real->segment_char_offset < real->segment->char_count);
1820 /* We moved into the middle of a segment, so the any_segment
1821 must now be the segment we're in the middle of. */
1822 real->any_segment = real->segment;
1824 check_invariants ((GtkTextIter*)real);
1826 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1834 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1836 /* Need to move to the next segment; if no next segment,
1837 need to move to next line. */
1838 GtkTextLineSegment *seg;
1839 GtkTextLineSegment *any_seg;
1840 GtkTextRealIter *real;
1844 g_return_val_if_fail (iter != NULL, FALSE);
1846 real = gtk_text_iter_make_real (iter);
1851 check_invariants (iter);
1853 if (real->line_char_offset >= 0)
1855 chars_skipped = real->segment->char_count - real->segment_char_offset;
1856 g_assert (chars_skipped > 0);
1861 if (real->line_byte_offset >= 0)
1863 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1864 g_assert (bytes_skipped > 0);
1869 /* Get first segment of any kind */
1870 any_seg = real->segment->next;
1871 /* skip non-indexable segments, if any */
1873 while (seg != NULL && seg->char_count == 0)
1878 real->any_segment = any_seg;
1879 real->segment = seg;
1881 if (real->line_byte_offset >= 0)
1883 g_assert (bytes_skipped > 0);
1884 real->segment_byte_offset = 0;
1885 real->line_byte_offset += bytes_skipped;
1888 if (real->line_char_offset >= 0)
1890 g_assert (chars_skipped > 0);
1891 real->segment_char_offset = 0;
1892 real->line_char_offset += chars_skipped;
1893 adjust_char_index (real, chars_skipped);
1896 check_invariants (iter);
1902 /* End of the line */
1903 if (forward_line_leaving_caches_unmodified (real))
1905 adjust_line_number (real, 1);
1906 if (real->line_char_offset >= 0)
1907 adjust_char_index (real, chars_skipped);
1909 g_assert (real->line_byte_offset == 0);
1910 g_assert (real->line_char_offset == 0);
1911 g_assert (real->segment_byte_offset == 0);
1912 g_assert (real->segment_char_offset == 0);
1913 g_assert (gtk_text_iter_starts_line (iter));
1915 check_invariants (iter);
1917 if (gtk_text_iter_is_end (iter))
1926 check_invariants (iter);
1934 at_last_indexable_segment (GtkTextRealIter *real)
1936 GtkTextLineSegment *seg;
1938 /* Return TRUE if there are no indexable segments after
1942 seg = real->segment->next;
1945 if (seg->char_count > 0)
1952 /* Goes back to the start of the next segment, even if
1953 * we're not at the start of the current segment (always
1954 * ends up on a different segment if it returns TRUE)
1957 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1959 /* Move to the start of the previous segment; if no previous
1960 * segment, to the last segment in the previous line. This is
1961 * inherently a bit inefficient due to the singly-linked list and
1962 * tree nodes, but we can't afford the RAM for doubly-linked.
1964 GtkTextRealIter *real;
1965 GtkTextLineSegment *seg;
1966 GtkTextLineSegment *any_seg;
1967 GtkTextLineSegment *prev_seg;
1968 GtkTextLineSegment *prev_any_seg;
1972 g_return_val_if_fail (iter != NULL, FALSE);
1974 real = gtk_text_iter_make_real (iter);
1979 check_invariants (iter);
1981 /* Find first segments in line */
1982 any_seg = real->line->segments;
1984 while (seg->char_count == 0)
1987 if (seg == real->segment)
1989 /* Could probably do this case faster by hand-coding the
1993 /* We were already at the start of a line;
1994 * go back to the previous line.
1996 if (gtk_text_iter_backward_line (iter))
1998 /* Go forward to last indexable segment in line. */
1999 while (!at_last_indexable_segment (real))
2000 _gtk_text_iter_forward_indexable_segment (iter);
2002 check_invariants (iter);
2007 return FALSE; /* We were at the start of the first line. */
2010 /* We must be in the middle of a line; so find the indexable
2011 * segment just before our current segment.
2013 g_assert (seg != real->segment);
2014 while (seg != real->segment)
2017 prev_any_seg = any_seg;
2019 any_seg = seg->next;
2021 while (seg->char_count == 0)
2025 g_assert (prev_seg != NULL);
2026 g_assert (prev_any_seg != NULL);
2027 g_assert (prev_seg->char_count > 0);
2029 /* We skipped the entire previous segment, plus any
2030 * chars we were into the current segment.
2032 if (real->segment_byte_offset >= 0)
2033 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2037 if (real->segment_char_offset >= 0)
2038 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2042 real->segment = prev_seg;
2043 real->any_segment = prev_any_seg;
2044 real->segment_byte_offset = 0;
2045 real->segment_char_offset = 0;
2047 if (bytes_skipped >= 0)
2049 if (real->line_byte_offset >= 0)
2051 real->line_byte_offset -= bytes_skipped;
2052 g_assert (real->line_byte_offset >= 0);
2056 real->line_byte_offset = -1;
2058 if (chars_skipped >= 0)
2060 if (real->line_char_offset >= 0)
2062 real->line_char_offset -= chars_skipped;
2063 g_assert (real->line_char_offset >= 0);
2066 if (real->cached_char_index >= 0)
2068 real->cached_char_index -= chars_skipped;
2069 g_assert (real->cached_char_index >= 0);
2074 real->line_char_offset = -1;
2075 real->cached_char_index = -1;
2078 /* line number is unchanged. */
2080 check_invariants (iter);
2086 * gtk_text_iter_forward_char:
2087 * @iter: an iterator
2089 * Moves @iter forward by one character offset. Note that images
2090 * embedded in the buffer occupy 1 character slot, so
2091 * gtk_text_iter_forward_char () may actually move onto an image instead
2092 * of a character, if you have images in your buffer. If @iter is the
2093 * end iterator or one character before it, @iter will now point at
2094 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2095 * convenience when writing loops.
2097 * Return value: whether the new position is the end iterator
2100 gtk_text_iter_forward_char (GtkTextIter *iter)
2102 GtkTextRealIter *real;
2104 g_return_val_if_fail (iter != NULL, FALSE);
2106 real = gtk_text_iter_make_real (iter);
2112 check_invariants (iter);
2113 return forward_char (real);
2118 * gtk_text_iter_backward_char:
2119 * @iter: an iterator
2121 * Moves backward by one character offset. Returns TRUE if movement
2122 * was possible; if @iter was the first in the buffer (character
2123 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2126 * Return value: whether movement was possible
2129 gtk_text_iter_backward_char (GtkTextIter *iter)
2131 g_return_val_if_fail (iter != NULL, FALSE);
2133 check_invariants (iter);
2135 return gtk_text_iter_backward_chars (iter, 1);
2139 Definitely we should try to linear scan as often as possible for
2140 movement within a single line, because we can't use the BTree to
2141 speed within-line searches up; for movement between lines, we would
2142 like to avoid the linear scan probably.
2144 Instead of using this constant, it might be nice to cache the line
2145 length in the iterator and linear scan if motion is within a single
2148 I guess you'd have to profile the various approaches.
2150 #define MAX_LINEAR_SCAN 150
2154 * gtk_text_iter_forward_chars:
2155 * @iter: an iterator
2156 * @count: number of characters to move, may be negative
2158 * Moves @count characters if possible (if @count would move past the
2159 * start or end of the buffer, moves to the start or end of the
2160 * buffer). The return value indicates whether the new position of
2161 * @iter is different from its original position, and dereferenceable
2162 * (the last iterator in the buffer is not dereferenceable). If @count
2163 * is 0, the function does nothing and returns FALSE.
2165 * Return value: whether @iter moved and is dereferenceable
2168 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2170 GtkTextRealIter *real;
2172 g_return_val_if_fail (iter != NULL, FALSE);
2174 real = gtk_text_iter_make_real (iter);
2178 else if (count == 0)
2181 return gtk_text_iter_backward_chars (iter, 0 - count);
2182 else if (count < MAX_LINEAR_SCAN)
2184 check_invariants (iter);
2188 if (!forward_char (real))
2193 return forward_char (real);
2197 gint current_char_index;
2198 gint new_char_index;
2200 check_invariants (iter);
2202 current_char_index = gtk_text_iter_get_offset (iter);
2204 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2205 return FALSE; /* can't move forward */
2207 new_char_index = current_char_index + count;
2208 gtk_text_iter_set_offset (iter, new_char_index);
2210 check_invariants (iter);
2212 /* Return FALSE if we're on the non-dereferenceable end
2215 if (gtk_text_iter_is_end (iter))
2223 * gtk_text_iter_backward_chars:
2224 * @iter: an iterator
2225 * @count: number of characters to move
2227 * Moves @count characters backward, if possible (if @count would move
2228 * past the start or end of the buffer, moves to the start or end of
2229 * the buffer). The return value indicates whether the iterator moved
2230 * onto a dereferenceable position; if the iterator didn't move, or
2231 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2232 * the function does nothing and returns FALSE.
2234 * Return value: whether @iter moved and is dereferenceable
2238 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2240 GtkTextRealIter *real;
2242 g_return_val_if_fail (iter != NULL, FALSE);
2244 real = gtk_text_iter_make_real (iter);
2248 else if (count == 0)
2251 return gtk_text_iter_forward_chars (iter, 0 - count);
2253 ensure_char_offsets (real);
2254 check_invariants (iter);
2256 if (count <= real->segment_char_offset)
2258 /* Optimize the within-segment case */
2259 g_assert (real->segment->char_count > 0);
2260 g_assert (real->segment->type == >k_text_char_type);
2262 real->segment_char_offset -= count;
2263 g_assert (real->segment_char_offset >= 0);
2265 if (real->line_byte_offset >= 0)
2267 gint new_byte_offset;
2270 new_byte_offset = 0;
2272 while (i < real->segment_char_offset)
2274 const char * start = real->segment->body.chars + new_byte_offset;
2275 new_byte_offset += g_utf8_next_char (start) - start;
2280 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2281 real->segment_byte_offset = new_byte_offset;
2284 real->line_char_offset -= count;
2286 adjust_char_index (real, 0 - count);
2288 check_invariants (iter);
2294 /* We need to go back into previous segments. For now,
2295 * just keep this really simple. FIXME
2296 * use backward_indexable_segment.
2298 if (TRUE || count > MAX_LINEAR_SCAN)
2300 gint current_char_index;
2301 gint new_char_index;
2303 current_char_index = gtk_text_iter_get_offset (iter);
2305 if (current_char_index == 0)
2306 return FALSE; /* can't move backward */
2308 new_char_index = current_char_index - count;
2309 if (new_char_index < 0)
2311 gtk_text_iter_set_offset (iter, new_char_index);
2313 check_invariants (iter);
2319 /* FIXME backward_indexable_segment here */
2328 /* These two can't be implemented efficiently (always have to use
2329 * a linear scan, since that's the only way to find all the non-text
2334 * gtk_text_iter_forward_text_chars:
2335 * @iter: a #GtkTextIter
2336 * @count: number of chars to move
2338 * Moves forward by @count text characters (pixbufs, widgets,
2339 * etc. do not count as characters for this). Equivalent to moving
2340 * through the results of gtk_text_iter_get_text (), rather than
2341 * gtk_text_iter_get_slice ().
2343 * Return value: whether @iter moved and is dereferenceable
2346 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2355 * gtk_text_iter_forward_text_chars:
2356 * @iter: a #GtkTextIter
2357 * @count: number of chars to move
2359 * Moves backward by @count text characters (pixbufs, widgets,
2360 * etc. do not count as characters for this). Equivalent to moving
2361 * through the results of gtk_text_iter_get_text (), rather than
2362 * gtk_text_iter_get_slice ().
2364 * Return value: whether @iter moved and is dereferenceable
2367 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2376 * gtk_text_iter_forward_line:
2377 * @iter: an iterator
2379 * Moves @iter to the start of the next line. Returns TRUE if there
2380 * was a next line to move to, and FALSE if @iter was simply moved to
2381 * the end of the buffer and is now not dereferenceable, or if @iter was
2382 * already at the end of the buffer.
2384 * Return value: whether @iter can be dereferenced
2387 gtk_text_iter_forward_line (GtkTextIter *iter)
2389 GtkTextRealIter *real;
2391 g_return_val_if_fail (iter != NULL, FALSE);
2393 real = gtk_text_iter_make_real (iter);
2398 check_invariants (iter);
2400 if (forward_line_leaving_caches_unmodified (real))
2402 invalidate_char_index (real);
2403 adjust_line_number (real, 1);
2405 check_invariants (iter);
2407 if (gtk_text_iter_is_end (iter))
2414 check_invariants (iter);
2420 * gtk_text_iter_backward_line:
2421 * @iter: an iterator
2423 * Moves @iter to the start of the previous line. Returns TRUE if
2424 * @iter could be moved; i.e. if @iter was at character offset 0, this
2425 * function returns FALSE. Therefore if @iter was already on line 0,
2426 * but not at the start of the line, @iter is snapped to the start of
2427 * the line and the function returns TRUE. (Note that this implies that
2428 * in a loop calling this function, the line number may not change on
2429 * every iteration, if your first iteration is on line 0.)
2431 * Return value: whether @iter moved
2434 gtk_text_iter_backward_line (GtkTextIter *iter)
2436 GtkTextLine *new_line;
2437 GtkTextRealIter *real;
2438 gboolean offset_will_change;
2441 g_return_val_if_fail (iter != NULL, FALSE);
2443 real = gtk_text_iter_make_real (iter);
2448 check_invariants (iter);
2450 new_line = _gtk_text_line_previous (real->line);
2452 offset_will_change = FALSE;
2453 if (real->line_char_offset > 0)
2454 offset_will_change = TRUE;
2456 if (new_line != NULL)
2458 real->line = new_line;
2460 adjust_line_number (real, -1);
2464 if (!offset_will_change)
2468 invalidate_char_index (real);
2470 real->line_byte_offset = 0;
2471 real->line_char_offset = 0;
2473 real->segment_byte_offset = 0;
2474 real->segment_char_offset = 0;
2476 /* Find first segment in line */
2477 real->any_segment = real->line->segments;
2478 real->segment = _gtk_text_line_byte_to_segment (real->line,
2481 g_assert (offset == 0);
2483 /* Note that if we are on the first line, we snap to the start of
2484 * the first line and return TRUE, so TRUE means the iterator
2485 * changed, not that the line changed; this is maybe a bit
2486 * weird. I'm not sure there's an obvious right thing to do though.
2489 check_invariants (iter);
2495 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2498 return gtk_text_iter_backward_lines (iter, 0 - count);
2499 else if (count == 0)
2501 else if (count == 1)
2503 check_invariants (iter);
2504 return gtk_text_iter_forward_line (iter);
2510 old_line = gtk_text_iter_get_line (iter);
2512 gtk_text_iter_set_line (iter, old_line + count);
2514 check_invariants (iter);
2516 /* return whether it moved, and is dereferenceable. */
2518 (gtk_text_iter_get_line (iter) != old_line) &&
2519 !gtk_text_iter_is_end (iter);
2524 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2527 return gtk_text_iter_forward_lines (iter, 0 - count);
2528 else if (count == 0)
2530 else if (count == 1)
2532 return gtk_text_iter_backward_line (iter);
2538 old_line = gtk_text_iter_get_line (iter);
2540 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2542 return (gtk_text_iter_get_line (iter) != old_line);
2546 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2551 gboolean already_moved_initially);
2553 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2561 find_word_end_func (const PangoLogAttr *attrs,
2566 gboolean already_moved_initially)
2568 if (!already_moved_initially)
2571 /* Find end of next word */
2572 while (offset < min_offset + len &&
2573 !attrs[offset].is_word_end)
2576 *found_offset = offset;
2578 return offset < min_offset + len;
2582 is_word_end_func (const PangoLogAttr *attrs,
2587 return attrs[offset].is_word_end;
2591 find_word_start_func (const PangoLogAttr *attrs,
2596 gboolean already_moved_initially)
2598 if (!already_moved_initially)
2601 /* Find start of prev word */
2602 while (offset >= min_offset &&
2603 !attrs[offset].is_word_start)
2606 *found_offset = offset;
2608 return offset >= min_offset;
2612 is_word_start_func (const PangoLogAttr *attrs,
2617 return attrs[offset].is_word_start;
2621 inside_word_func (const PangoLogAttr *attrs,
2626 /* Find next word start or end */
2627 while (offset >= min_offset &&
2628 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2631 return attrs[offset].is_word_start;
2634 /* Sentence funcs */
2637 find_sentence_end_func (const PangoLogAttr *attrs,
2642 gboolean already_moved_initially)
2644 if (!already_moved_initially)
2647 /* Find end of next sentence */
2648 while (offset < min_offset + len &&
2649 !attrs[offset].is_sentence_end)
2652 *found_offset = offset;
2654 return offset < min_offset + len;
2658 is_sentence_end_func (const PangoLogAttr *attrs,
2663 return attrs[offset].is_sentence_end;
2667 find_sentence_start_func (const PangoLogAttr *attrs,
2672 gboolean already_moved_initially)
2674 if (!already_moved_initially)
2677 /* Find start of prev sentence */
2678 while (offset >= min_offset &&
2679 !attrs[offset].is_sentence_start)
2682 *found_offset = offset;
2684 return offset >= min_offset;
2688 is_sentence_start_func (const PangoLogAttr *attrs,
2693 return attrs[offset].is_sentence_start;
2697 inside_sentence_func (const PangoLogAttr *attrs,
2702 /* Find next sentence start or end */
2703 while (offset >= min_offset &&
2704 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2707 return attrs[offset].is_sentence_start;
2711 test_log_attrs (const GtkTextIter *iter,
2712 TestLogAttrFunc func)
2715 const PangoLogAttr *attrs;
2717 gboolean result = FALSE;
2719 g_return_val_if_fail (iter != NULL, FALSE);
2721 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2724 offset = gtk_text_iter_get_line_offset (iter);
2726 g_assert (char_len > 0);
2728 if (offset < char_len)
2729 result = (* func) (attrs, offset, 0, char_len);
2735 find_line_log_attrs (const GtkTextIter *iter,
2736 FindLogAttrFunc func,
2738 gboolean already_moved_initially)
2741 const PangoLogAttr *attrs;
2743 gboolean result = FALSE;
2745 g_return_val_if_fail (iter != NULL, FALSE);
2747 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2750 offset = gtk_text_iter_get_line_offset (iter);
2752 g_assert (char_len > 0);
2754 if (offset < char_len)
2755 result = (* func) (attrs, offset, 0, char_len, found_offset,
2756 already_moved_initially);
2761 /* FIXME this function is very, very gratuitously slow */
2763 find_by_log_attrs (GtkTextIter *iter,
2764 FindLogAttrFunc func,
2766 gboolean already_moved_initially)
2770 gboolean found = FALSE;
2772 g_return_val_if_fail (iter != NULL, FALSE);
2776 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2782 if (gtk_text_iter_forward_line (iter))
2783 return find_by_log_attrs (iter, func, forward,
2790 /* go to end of previous line */
2791 gtk_text_iter_set_line_offset (iter, 0);
2793 if (gtk_text_iter_backward_char (iter))
2794 return find_by_log_attrs (iter, func, forward,
2802 gtk_text_iter_set_line_offset (iter, offset);
2805 !gtk_text_iter_equal (iter, &orig) &&
2806 !gtk_text_iter_is_end (iter);
2811 * gtk_text_iter_forward_word_end:
2812 * @iter: a #GtkTextIter
2814 * Moves forward to the next word end. (If @iter is currently on a
2815 * word end, moves forward to the next one after that.) Word breaks
2816 * are determined by Pango and should be correct for nearly any
2817 * language (if not, the correct fix would be to the Pango word break
2820 * Return value: %TRUE if @iter moved and is not the end iterator
2823 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2825 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2829 * gtk_text_iter_forward_word_end:
2830 * @iter: a #GtkTextIter
2832 * Moves backward to the next word start. (If @iter is currently on a
2833 * word start, moves backward to the next one after that.) Word breaks
2834 * are determined by Pango and should be correct for nearly any
2835 * language (if not, the correct fix would be to the Pango word break
2838 * Return value: %TRUE if @iter moved and is not the end iterator
2841 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2843 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2846 /* FIXME a loop around a truly slow function means
2847 * a truly spectacularly slow function.
2851 * gtk_text_iter_forward_word_ends:
2852 * @iter: a #GtkTextIter
2853 * @count: number of times to move
2855 * Calls gtk_text_iter_forward_word_end() up to @count times.
2857 * Return value: %TRUE if @iter moved and is not the end iterator
2860 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2863 g_return_val_if_fail (iter != NULL, FALSE);
2869 return gtk_text_iter_backward_word_starts (iter, -count);
2871 if (!gtk_text_iter_forward_word_end (iter))
2877 if (!gtk_text_iter_forward_word_end (iter))
2885 * gtk_text_iter_backward_word_starts
2886 * @iter: a #GtkTextIter
2887 * @count: number of times to move
2889 * Calls gtk_text_iter_backward_word_starts() up to @count times.
2891 * Return value: %TRUE if @iter moved and is not the end iterator
2894 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2897 g_return_val_if_fail (iter != NULL, FALSE);
2900 return gtk_text_iter_forward_word_ends (iter, -count);
2902 if (!gtk_text_iter_backward_word_start (iter))
2908 if (!gtk_text_iter_backward_word_start (iter))
2916 * gtk_text_iter_starts_word:
2917 * @iter: a #GtkTextIter
2919 * Determines whether @iter begins a natural-language word. Word
2920 * breaks are determined by Pango and should be correct for nearly any
2921 * language (if not, the correct fix would be to the Pango word break
2924 * Return value: %TRUE if @iter is at the start of a word
2927 gtk_text_iter_starts_word (const GtkTextIter *iter)
2929 return test_log_attrs (iter, is_word_start_func);
2933 * gtk_text_iter_ends_word:
2934 * @iter: a #GtkTextIter
2936 * Determines whether @iter ends a natural-language word. Word breaks
2937 * are determined by Pango and should be correct for nearly any
2938 * language (if not, the correct fix would be to the Pango word break
2941 * Return value: %TRUE if @iter is at the end of a word
2944 gtk_text_iter_ends_word (const GtkTextIter *iter)
2946 return test_log_attrs (iter, is_word_end_func);
2950 * gtk_text_iter_inside_word:
2951 * @iter: a #GtkTextIter
2953 * Determines whether @iter is inside a natural-language word (as
2954 * opposed to say inside some whitespace). Word breaks are determined
2955 * by Pango and should be correct for nearly any language (if not, the
2956 * correct fix would be to the Pango word break algorithms).
2958 * Return value: %TRUE if @iter is inside a word
2961 gtk_text_iter_inside_word (const GtkTextIter *iter)
2963 return test_log_attrs (iter, inside_word_func);
2967 * gtk_text_iter_starts_sentence:
2968 * @iter: a #GtkTextIter
2970 * Determines whether @iter begins a sentence. Sentence boundaries are
2971 * determined by Pango and should be correct for nearly any language
2972 * (if not, the correct fix would be to the Pango text boundary
2975 * Return value: %TRUE if @iter is at the start of a sentence.
2978 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
2980 return test_log_attrs (iter, is_sentence_start_func);
2984 * gtk_text_iter_ends_sentence:
2985 * @iter: a #GtkTextIter
2987 * Determines whether @iter ends a sentence. Sentence boundaries are
2988 * determined by Pango and should be correct for nearly any language
2989 * (if not, the correct fix would be to the Pango text boundary
2992 * Return value: %TRUE if @iter is at the end of a sentence.
2995 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
2997 return test_log_attrs (iter, is_sentence_end_func);
3001 * gtk_text_iter_inside_sentence:
3002 * @iter: a #GtkTextIter
3004 * Determines whether @iter is inside a sentence (as opposed to in
3005 * between two sentences, e.g. after a period and before the first
3006 * letter of the next sentence). Sentence boundaries are determined
3007 * by Pango and should be correct for nearly any language (if not, the
3008 * correct fix would be to the Pango text boundary algorithms).
3010 * Return value: %TRUE if @iter is inside a sentence.
3013 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3015 return test_log_attrs (iter, inside_sentence_func);
3019 * gtk_text_iter_forward_sentence_end:
3020 * @iter: a #GtkTextIter
3022 * Moves forward to the next sentence end. (If @iter is at the end of
3023 * a sentence, moves to the next end of sentence.) Sentence
3024 * boundaries are determined by Pango and should be correct for nearly
3025 * any language (if not, the correct fix would be to the Pango text
3026 * boundary algorithms).
3028 * Return value: %TRUE if @iter moved and is not the end iterator
3031 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3033 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3037 * gtk_text_iter_backward_sentence_start:
3038 * @iter: a #GtkTextIter
3040 * Moves backward to the next sentence start; if @iter is already at
3041 * the start of a sentence, moves backward to the next one. Sentence
3042 * boundaries are determined by Pango and should be correct for nearly
3043 * any language (if not, the correct fix would be to the Pango text
3044 * boundary algorithms).
3046 * Return value: %TRUE if @iter moved and is not the end iterator
3049 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3051 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3054 /* FIXME a loop around a truly slow function means
3055 * a truly spectacularly slow function.
3058 * gtk_text_iter_forward_sentence_ends:
3059 * @iter: a #GtkTextIter
3060 * @count: number of sentences to move
3062 * Calls gtk_text_iter_forward_sentence_end() up to @count times.
3064 * Return value: %TRUE if @iter moved and is not the end iterator
3067 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3070 g_return_val_if_fail (iter != NULL, FALSE);
3076 return gtk_text_iter_backward_sentence_starts (iter, -count);
3078 if (!gtk_text_iter_forward_sentence_end (iter))
3084 if (!gtk_text_iter_forward_sentence_end (iter))
3092 * gtk_text_iter_forward_sentence_ends:
3093 * @iter: a #GtkTextIter
3094 * @count: number of sentences to move
3096 * Calls gtk_text_iter_backward_sentence_start() up to @count times.
3098 * Return value: %TRUE if @iter moved and is not the end iterator
3101 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3104 g_return_val_if_fail (iter != NULL, FALSE);
3107 return gtk_text_iter_forward_sentence_ends (iter, -count);
3109 if (!gtk_text_iter_backward_sentence_start (iter))
3115 if (!gtk_text_iter_backward_sentence_start (iter))
3123 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3128 gboolean already_moved_initially)
3130 if (!already_moved_initially)
3133 while (offset < (min_offset + len) &&
3134 !attrs[offset].is_cursor_position)
3137 *found_offset = offset;
3139 return offset < (min_offset + len);
3143 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3148 gboolean already_moved_initially)
3150 if (!already_moved_initially)
3153 while (offset > min_offset &&
3154 !attrs[offset].is_cursor_position)
3157 *found_offset = offset;
3159 return offset >= min_offset;
3163 is_cursor_pos_func (const PangoLogAttr *attrs,
3168 return attrs[offset].is_cursor_position;
3172 * gtk_text_iter_forward_cursor_position:
3173 * @iter: a #GtkTextIter
3175 * Moves @iter forward by a single cursor position. Cursor positions
3176 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3177 * surprisingly, there may not be a cursor position between all
3178 * characters. The most common example for European languages would be
3179 * a carriage return/newline sequence. For some Unicode characters,
3180 * the equivalent of say the letter "a" with an accent mark will be
3181 * represented as two characters, first the letter then a "combining
3182 * mark" that causes the accent to be rendered; so the cursor can't go
3183 * between those two characters. See also the #PangoLogAttr structure and
3184 * pango_break() function.
3186 * Return value: %TRUE if we moved and the new position is dereferenceable
3189 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3191 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3195 * gtk_text_iter_backward_cursor_position:
3196 * @iter: a #GtkTextIter
3198 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3200 * Return value: %TRUE if we moved and the new position is dereferenceable
3203 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3205 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3209 * gtk_text_iter_forward_cursor_positions:
3210 * @iter: a #GtkTextIter
3211 * @count: number of positions to move
3213 * Moves up to @count cursor positions. See
3214 * gtk_text_iter_forward_cursor_position() for details.
3216 * Return value: %TRUE if we moved and the new position is dereferenceable
3219 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3222 g_return_val_if_fail (iter != NULL, FALSE);
3228 return gtk_text_iter_backward_cursor_positions (iter, -count);
3230 if (!gtk_text_iter_forward_cursor_position (iter))
3236 if (!gtk_text_iter_forward_cursor_position (iter))
3244 * gtk_text_iter_backward_cursor_positions:
3245 * @iter: a #GtkTextIter
3246 * @count: number of positions to move
3248 * Moves up to @count cursor positions. See
3249 * gtk_text_iter_forward_cursor_position() for details.
3251 * Return value: %TRUE if we moved and the new position is dereferenceable
3254 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3257 g_return_val_if_fail (iter != NULL, FALSE);
3263 return gtk_text_iter_forward_cursor_positions (iter, -count);
3265 if (!gtk_text_iter_backward_cursor_position (iter))
3271 if (!gtk_text_iter_backward_cursor_position (iter))
3279 * gtk_text_iter_is_cursor_position:
3280 * @iter: a #GtkTextIter
3282 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3283 * pango_break() for details on what a cursor position is.
3285 * Return value: %TRUE if the cursor can be placed at @iter
3288 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3290 return test_log_attrs (iter, is_cursor_pos_func);
3294 * gtk_text_iter_set_line_offset:
3295 * @iter: a #GtkTextIter
3296 * @char_on_line: a character offset relative to the start of @iter's current line
3298 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3299 * (not byte) offset. The given character offset must be less than or
3300 * equal to the number of characters in the line; if equal, @iter
3301 * moves to the start of the next line. See
3302 * gtk_text_iter_set_line_index() if you have a byte index rather than
3303 * a character offset.
3307 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3310 GtkTextRealIter *real;
3313 g_return_if_fail (iter != NULL);
3315 real = gtk_text_iter_make_surreal (iter);
3320 check_invariants (iter);
3322 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3324 g_return_if_fail (char_on_line <= chars_in_line);
3326 if (char_on_line < chars_in_line)
3327 iter_set_from_char_offset (real, real->line, char_on_line);
3329 gtk_text_iter_forward_line (iter); /* set to start of next line */
3331 check_invariants (iter);
3335 * gtk_text_iter_set_line_index:
3336 * @iter: a #GtkTextIter
3337 * @byte_on_line: a byte index relative to the start of @iter's current line
3339 * Same as gtk_text_iter_set_line_offset(), but works with a
3340 * <emphasis>byte</emphasis> index. The given byte index must be at
3341 * the start of a character, it can't be in the middle of a UTF-8
3342 * encoded character.
3346 gtk_text_iter_set_line_index (GtkTextIter *iter,
3349 GtkTextRealIter *real;
3352 g_return_if_fail (iter != NULL);
3354 real = gtk_text_iter_make_surreal (iter);
3359 check_invariants (iter);
3361 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3363 g_return_if_fail (byte_on_line <= bytes_in_line);
3365 if (byte_on_line < bytes_in_line)
3366 iter_set_from_byte_offset (real, real->line, byte_on_line);
3368 gtk_text_iter_forward_line (iter);
3370 if (real->segment->type == >k_text_char_type &&
3371 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3372 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3373 "character; this will crash the text buffer. "
3374 "Byte indexes must refer to the start of a character.",
3375 G_STRLOC, byte_on_line);
3377 check_invariants (iter);
3382 * gtk_text_iter_set_visible_line_offset:
3383 * @iter: a #GtkTextIter
3384 * @char_on_line: a character offset
3386 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3387 * characters, i.e. text with a tag making it invisible is not
3388 * counted in the offset.
3391 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3394 gint chars_seen = 0;
3397 g_return_if_fail (iter != NULL);
3401 /* For now we use a ludicrously slow implementation */
3402 while (chars_seen < char_on_line)
3404 if (!_gtk_text_btree_char_is_invisible (&pos))
3407 if (!gtk_text_iter_forward_char (&pos))
3410 if (chars_seen == char_on_line)
3414 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3417 gtk_text_iter_forward_line (iter);
3421 bytes_in_char (GtkTextIter *iter)
3423 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3427 * gtk_text_iter_set_visible_line_index:
3428 * @iter: a #GtkTextIter
3429 * @byte_on_line: a byte index
3431 * Like gtk_text_iter_set_line_index(), but the index is in visible
3432 * bytes, i.e. text with a tag making it invisible is not counted
3436 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3439 gint bytes_seen = 0;
3442 g_return_if_fail (iter != NULL);
3446 /* For now we use a ludicrously slow implementation */
3447 while (bytes_seen < byte_on_line)
3449 if (!_gtk_text_btree_char_is_invisible (&pos))
3450 bytes_seen += bytes_in_char (&pos);
3452 if (!gtk_text_iter_forward_char (&pos))
3455 if (bytes_seen >= byte_on_line)
3459 if (bytes_seen > byte_on_line)
3460 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3461 "character; this will crash the text buffer. "
3462 "Byte indexes must refer to the start of a character.",
3463 G_STRLOC, byte_on_line);
3465 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3468 gtk_text_iter_forward_line (iter);
3472 * gtk_text_iter_set_line:
3473 * @iter: a #GtkTextIter
3474 * @line_number: line number (counted from 0)
3476 * Moves iterator @iter to the start of the line @line_number.
3480 gtk_text_iter_set_line (GtkTextIter *iter,
3485 GtkTextRealIter *real;
3487 g_return_if_fail (iter != NULL);
3489 real = gtk_text_iter_make_surreal (iter);
3494 check_invariants (iter);
3496 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3498 iter_set_from_char_offset (real, line, 0);
3500 /* We might as well cache this, since we know it. */
3501 real->cached_line_number = real_line;
3503 check_invariants (iter);
3507 * gtk_text_iter_set_offset:
3508 * @iter: a #GtkTextIter
3509 * @char_offset: a character number
3511 * Sets @iter to point to @char_offset. @char_offset counts from the start
3512 * of the entire text buffer, starting with 0.
3516 gtk_text_iter_set_offset (GtkTextIter *iter,
3520 GtkTextRealIter *real;
3522 gint real_char_index;
3524 g_return_if_fail (iter != NULL);
3526 real = gtk_text_iter_make_surreal (iter);
3531 check_invariants (iter);
3533 if (real->cached_char_index >= 0 &&
3534 real->cached_char_index == char_offset)
3537 line = _gtk_text_btree_get_line_at_char (real->tree,
3542 iter_set_from_char_offset (real, line, real_char_index - line_start);
3544 /* Go ahead and cache this since we have it. */
3545 real->cached_char_index = real_char_index;
3547 check_invariants (iter);
3551 * gtk_text_iter_forward_to_end:
3552 * @iter: a #GtkTextIter
3554 * Moves @iter forward to the "end iterator," which points one past the last
3555 * valid character in the buffer. gtk_text_iter_get_char() called on the
3556 * end iterator returns 0, which is convenient for writing loops.
3560 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3562 GtkTextBuffer *buffer;
3563 GtkTextRealIter *real;
3565 g_return_if_fail (iter != NULL);
3567 real = gtk_text_iter_make_surreal (iter);
3572 buffer = _gtk_text_btree_get_buffer (real->tree);
3574 gtk_text_buffer_get_end_iter (buffer, iter);
3578 * gtk_text_iter_forward_to_line_end:
3579 * @iter: a #GtkTextIter
3581 * Moves the iterator to point to the paragraph delimiter characters,
3582 * which will be either a newline, a carriage return, a carriage
3583 * return/newline in sequence, or the Unicode paragraph separator
3584 * character. If the iterator is already at the paragraph delimiter
3585 * characters, moves to the paragraph delimiter characters for the
3588 * Return value: %TRUE if we moved and the new location is not the end iterator
3591 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3593 gint current_offset;
3596 g_return_val_if_fail (iter != NULL, FALSE);
3598 current_offset = gtk_text_iter_get_line_offset (iter);
3599 /* FIXME assumption that line ends in a newline; broken */
3600 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3602 if (current_offset < new_offset)
3604 /* Move to end of this line. */
3605 gtk_text_iter_set_line_offset (iter, new_offset);
3610 /* Move to end of next line. */
3611 if (gtk_text_iter_forward_line (iter))
3613 /* We don't want to move past all
3616 if (!gtk_text_iter_ends_line (iter))
3617 gtk_text_iter_forward_to_line_end (iter);
3626 * gtk_text_iter_forward_to_tag_toggle:
3627 * @iter: a #GtkTextIter
3628 * @tag: a #GtkTextTag, or NULL
3630 * Moves forward to the next toggle (on or off) of the
3631 * #GtkTextTag @tag, or to the next toggle of any tag if
3632 * @tag is NULL. If no matching tag toggles are found,
3633 * returns FALSE, otherwise TRUE. Does not return toggles
3634 * located at @iter, only toggles after @iter. Sets @iter to
3635 * the location of the toggle, or to the end of the buffer
3636 * if no toggle is found.
3638 * Return value: whether we found a tag toggle after @iter
3641 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3644 GtkTextLine *next_line;
3645 GtkTextLine *current_line;
3646 GtkTextRealIter *real;
3648 g_return_val_if_fail (iter != NULL, FALSE);
3650 real = gtk_text_iter_make_real (iter);
3655 check_invariants (iter);
3657 current_line = real->line;
3658 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3661 while (_gtk_text_iter_forward_indexable_segment (iter))
3663 /* If we went forward to a line that couldn't contain a toggle
3664 for the tag, then skip forward to a line that could contain
3665 it. This potentially skips huge hunks of the tree, so we
3666 aren't a purely linear search. */
3667 if (real->line != current_line)
3669 if (next_line == NULL)
3671 /* End of search. Set to end of buffer. */
3672 _gtk_text_btree_get_end_iter (real->tree, iter);
3676 if (real->line != next_line)
3677 iter_set_from_byte_offset (real, next_line, 0);
3679 current_line = real->line;
3680 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3685 if (gtk_text_iter_toggles_tag (iter, tag))
3687 /* If there's a toggle here, it isn't indexable so
3688 any_segment can't be the indexable segment. */
3689 g_assert (real->any_segment != real->segment);
3694 /* Check end iterator for tags */
3695 if (gtk_text_iter_toggles_tag (iter, tag))
3697 /* If there's a toggle here, it isn't indexable so
3698 any_segment can't be the indexable segment. */
3699 g_assert (real->any_segment != real->segment);
3703 /* Reached end of buffer */
3708 * gtk_text_iter_backward_to_tag_toggle:
3709 * @iter: a #GtkTextIter
3710 * @tag: a #GtkTextTag, or NULL
3712 * Moves backward to the next toggle (on or off) of the
3713 * #GtkTextTag @tag, or to the next toggle of any tag if
3714 * @tag is NULL. If no matching tag toggles are found,
3715 * returns FALSE, otherwise TRUE. Does not return toggles
3716 * located at @iter, only toggles before @iter. Sets @iter
3717 * to the location of the toggle, or the start of the buffer
3718 * if no toggle is found.
3720 * Return value: whether we found a tag toggle before @iter
3723 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3726 GtkTextLine *prev_line;
3727 GtkTextLine *current_line;
3728 GtkTextRealIter *real;
3730 g_return_val_if_fail (iter != NULL, FALSE);
3732 real = gtk_text_iter_make_real (iter);
3737 check_invariants (iter);
3739 current_line = real->line;
3740 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3744 /* If we're at segment start, go to the previous segment;
3745 * if mid-segment, snap to start of current segment.
3747 if (is_segment_start (real))
3749 if (!_gtk_text_iter_backward_indexable_segment (iter))
3754 ensure_char_offsets (real);
3756 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3762 /* If we went backward to a line that couldn't contain a toggle
3763 * for the tag, then skip backward further to a line that
3764 * could contain it. This potentially skips huge hunks of the
3765 * tree, so we aren't a purely linear search.
3767 if (real->line != current_line)
3769 if (prev_line == NULL)
3771 /* End of search. Set to start of buffer. */
3772 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3776 if (real->line != prev_line)
3778 /* Set to last segment in prev_line (could do this
3781 iter_set_from_byte_offset (real, prev_line, 0);
3783 while (!at_last_indexable_segment (real))
3784 _gtk_text_iter_forward_indexable_segment (iter);
3787 current_line = real->line;
3788 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3793 if (gtk_text_iter_toggles_tag (iter, tag))
3795 /* If there's a toggle here, it isn't indexable so
3796 * any_segment can't be the indexable segment.
3798 g_assert (real->any_segment != real->segment);
3802 while (_gtk_text_iter_backward_indexable_segment (iter));
3804 /* Reached front of buffer */
3809 matches_pred (GtkTextIter *iter,
3810 GtkTextCharPredicate pred,
3815 ch = gtk_text_iter_get_char (iter);
3817 return (*pred) (ch, user_data);
3821 * gtk_text_iter_forward_find_char:
3822 * @iter: a #GtkTextIter
3823 * @pred: a function to be called on each character
3824 * @user_data: user data for @pred
3825 * @limit: search limit, or %NULL for none
3827 * Advances @iter, calling @pred on each character. If
3828 * @pred returns %TRUE, returns %TRUE and stops scanning.
3829 * If @pred never returns %TRUE, @iter is set to @limit if
3830 * @limit is non-%NULL, otherwise to the end iterator.
3832 * Return value: whether a match was found
3835 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3836 GtkTextCharPredicate pred,
3838 const GtkTextIter *limit)
3840 g_return_val_if_fail (iter != NULL, FALSE);
3841 g_return_val_if_fail (pred != NULL, FALSE);
3844 gtk_text_iter_compare (iter, limit) >= 0)
3847 while ((limit == NULL ||
3848 !gtk_text_iter_equal (limit, iter)) &&
3849 gtk_text_iter_forward_char (iter))
3851 if (matches_pred (iter, pred, user_data))
3859 * gtk_text_iter_backward_find_char:
3860 * @iter: a #GtkTextIter
3861 * @pred: function to be called on each character
3862 * @user_data: user data for @pred
3863 * @limit: search limit, or %NULL for none
3865 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
3867 * Return value: whether a match was found
3870 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3871 GtkTextCharPredicate pred,
3873 const GtkTextIter *limit)
3875 g_return_val_if_fail (iter != NULL, FALSE);
3876 g_return_val_if_fail (pred != NULL, FALSE);
3879 gtk_text_iter_compare (iter, limit) <= 0)
3882 while ((limit == NULL ||
3883 !gtk_text_iter_equal (limit, iter)) &&
3884 gtk_text_iter_backward_char (iter))
3886 if (matches_pred (iter, pred, user_data))
3894 forward_chars_with_skipping (GtkTextIter *iter,
3896 gboolean skip_invisible,
3897 gboolean skip_nontext)
3902 g_return_if_fail (count >= 0);
3908 gboolean ignored = FALSE;
3911 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3916 _gtk_text_btree_char_is_invisible (iter))
3919 gtk_text_iter_forward_char (iter);
3927 lines_match (const GtkTextIter *start,
3928 const gchar **lines,
3929 gboolean visible_only,
3931 GtkTextIter *match_start,
3932 GtkTextIter *match_end)
3939 if (*lines == NULL || **lines == '\0')
3942 *match_start = *start;
3945 *match_end = *start;
3950 gtk_text_iter_forward_line (&next);
3952 /* No more text in buffer, but *lines is nonempty */
3953 if (gtk_text_iter_equal (start, &next))
3961 line_text = gtk_text_iter_get_visible_slice (start, &next);
3963 line_text = gtk_text_iter_get_slice (start, &next);
3968 line_text = gtk_text_iter_get_visible_text (start, &next);
3970 line_text = gtk_text_iter_get_text (start, &next);
3973 if (match_start) /* if this is the first line we're matching */
3974 found = strstr (line_text, *lines);
3977 /* If it's not the first line, we have to match from the
3978 * start of the line.
3980 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
3992 /* Get offset to start of search string */
3993 offset = g_utf8_strlen (line_text, found - line_text);
3997 /* If match start needs to be returned, set it to the
3998 * start of the search string.
4002 *match_start = next;
4004 forward_chars_with_skipping (match_start, offset,
4005 visible_only, !slice);
4008 /* Go to end of search string */
4009 offset += g_utf8_strlen (*lines, -1);
4011 forward_chars_with_skipping (&next, offset,
4012 visible_only, !slice);
4021 /* pass NULL for match_start, since we don't need to find the
4024 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4027 /* strsplit () that retains the delimiter as part of the string. */
4029 strbreakup (const char *string,
4030 const char *delimiter,
4033 GSList *string_list = NULL, *slist;
4034 gchar **str_array, *s;
4037 g_return_val_if_fail (string != NULL, NULL);
4038 g_return_val_if_fail (delimiter != NULL, NULL);
4041 max_tokens = G_MAXINT;
4043 s = strstr (string, delimiter);
4046 guint delimiter_len = strlen (delimiter);
4053 len = s - string + delimiter_len;
4054 new_string = g_new (gchar, len + 1);
4055 strncpy (new_string, string, len);
4056 new_string[len] = 0;
4057 string_list = g_slist_prepend (string_list, new_string);
4059 string = s + delimiter_len;
4060 s = strstr (string, delimiter);
4062 while (--max_tokens && s);
4067 string_list = g_slist_prepend (string_list, g_strdup (string));
4070 str_array = g_new (gchar*, n);
4074 str_array[i--] = NULL;
4075 for (slist = string_list; slist; slist = slist->next)
4076 str_array[i--] = slist->data;
4078 g_slist_free (string_list);
4084 * gtk_text_iter_forward_search:
4085 * @iter: start of search
4086 * @str: a search string
4087 * @visible_only: if %TRUE, search only visible text
4088 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4089 * @match_start: return location for start of match, or %NULL
4090 * @match_end: return location for end of match, or %NULL
4091 * @limit: bound for the search, or %NULL for the end of the buffer
4093 * Searches forward for @str. Any match is returned as the range @match_start,
4094 * @match_end. If you specify @visible_only or @slice, the match may have
4095 * invisible text, pixbufs, or child widgets interspersed in @str.
4097 * Return value: whether a match was found
4100 gtk_text_iter_forward_search (const GtkTextIter *iter,
4102 gboolean visible_only,
4104 GtkTextIter *match_start,
4105 GtkTextIter *match_end,
4106 const GtkTextIter *limit)
4108 gchar **lines = NULL;
4110 gboolean retval = FALSE;
4113 g_return_val_if_fail (iter != NULL, FALSE);
4114 g_return_val_if_fail (str != NULL, FALSE);
4117 gtk_text_iter_compare (iter, limit) >= 0)
4122 /* If we can move one char, return the empty string there */
4125 if (gtk_text_iter_forward_char (&match))
4128 gtk_text_iter_equal (&match, limit))
4132 *match_start = match;
4141 /* locate all lines */
4143 lines = strbreakup (str, "\n", -1);
4149 /* This loop has an inefficient worst-case, where
4150 * gtk_text_iter_get_text () is called repeatedly on
4156 gtk_text_iter_compare (&search, limit) >= 0)
4159 if (lines_match (&search, (const gchar**)lines,
4160 visible_only, slice, &match, &end))
4162 if (limit == NULL ||
4164 gtk_text_iter_compare (&end, limit) < 0))
4169 *match_start = match;
4178 while (gtk_text_iter_forward_line (&search));
4180 g_strfreev ((gchar**)lines);
4186 vectors_equal_ignoring_trailing (gchar **vec1,
4189 /* Ignores trailing chars in vec2's last line */
4198 if (strcmp (*i1, *i2) != 0)
4200 if (*(i2 + 1) == NULL) /* if this is the last line */
4202 gint len1 = strlen (*i1);
4203 gint len2 = strlen (*i2);
4206 strncmp (*i1, *i2, len1) == 0)
4208 /* We matched ignoring the trailing stuff in vec2 */
4233 typedef struct _LinesWindow LinesWindow;
4239 GtkTextIter first_line_start;
4240 GtkTextIter first_line_end;
4242 gboolean visible_only;
4246 lines_window_init (LinesWindow *win,
4247 const GtkTextIter *start)
4250 GtkTextIter line_start;
4251 GtkTextIter line_end;
4253 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4256 if (gtk_text_iter_is_start (start) ||
4257 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4259 /* Already at the end, or not enough lines to match */
4260 win->lines = g_new0 (gchar*, 1);
4265 line_start = *start;
4268 /* Move to start iter to start of line */
4269 gtk_text_iter_set_line_offset (&line_start, 0);
4271 if (gtk_text_iter_equal (&line_start, &line_end))
4273 /* we were already at the start; so go back one line */
4274 gtk_text_iter_backward_line (&line_start);
4277 win->first_line_start = line_start;
4278 win->first_line_end = line_end;
4280 win->lines = g_new0 (gchar*, win->n_lines + 1);
4282 i = win->n_lines - 1;
4289 if (win->visible_only)
4290 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4292 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4296 if (win->visible_only)
4297 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4299 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4302 win->lines[i] = line_text;
4304 line_end = line_start;
4305 gtk_text_iter_backward_line (&line_start);
4312 lines_window_back (LinesWindow *win)
4314 GtkTextIter new_start;
4317 new_start = win->first_line_start;
4319 if (!gtk_text_iter_backward_line (&new_start))
4323 win->first_line_start = new_start;
4324 win->first_line_end = new_start;
4326 gtk_text_iter_forward_line (&win->first_line_end);
4331 if (win->visible_only)
4332 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4333 &win->first_line_end);
4335 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4336 &win->first_line_end);
4340 if (win->visible_only)
4341 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4342 &win->first_line_end);
4344 line_text = gtk_text_iter_get_text (&win->first_line_start,
4345 &win->first_line_end);
4348 /* Move lines to make room for first line. */
4349 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4351 *win->lines = line_text;
4353 /* Free old last line and NULL-terminate */
4354 g_free (win->lines[win->n_lines]);
4355 win->lines[win->n_lines] = NULL;
4361 lines_window_free (LinesWindow *win)
4363 g_strfreev (win->lines);
4367 my_strrstr (const gchar *haystack,
4368 const gchar *needle)
4370 /* FIXME GLib should have a nice implementation in it, this
4374 gint haystack_len = strlen (haystack);
4375 gint needle_len = strlen (needle);
4376 const gchar *needle_end = needle + needle_len;
4377 const gchar *haystack_rend = haystack - 1;
4378 const gchar *needle_rend = needle - 1;
4381 p = haystack + haystack_len;
4382 while (p != haystack)
4384 const gchar *n = needle_end - 1;
4385 const gchar *s = p - 1;
4386 while (s != haystack_rend &&
4394 if (n == needle_rend)
4404 * gtk_text_iter_backward_search:
4405 * @iter: a #GtkTextIter where the search begins
4406 * @str: search string
4407 * @visible_only: if %TRUE search only visible text
4408 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4409 * @match_start: return location for start of match, or %NULL
4410 * @match_end: return location for end of match, or %NULL
4411 * @limit: location of last possible @match_start, or %NULL for start of buffer
4413 * Same as gtk_text_iter_forward_search(), but moves backward.
4415 * Return value: whether a match was found
4418 gtk_text_iter_backward_search (const GtkTextIter *iter,
4420 gboolean visible_only,
4422 GtkTextIter *match_start,
4423 GtkTextIter *match_end,
4424 const GtkTextIter *limit)
4426 gchar **lines = NULL;
4430 gboolean retval = FALSE;
4432 g_return_val_if_fail (iter != NULL, FALSE);
4433 g_return_val_if_fail (str != NULL, FALSE);
4436 gtk_text_iter_compare (limit, iter) > 0)
4441 /* If we can move one char, return the empty string there */
4442 GtkTextIter match = *iter;
4444 if (limit && gtk_text_iter_equal (limit, &match))
4447 if (gtk_text_iter_backward_char (&match))
4450 *match_start = match;
4459 /* locate all lines */
4461 lines = strbreakup (str, "\n", -1);
4471 win.n_lines = n_lines;
4473 win.visible_only = visible_only;
4475 lines_window_init (&win, iter);
4477 if (*win.lines == NULL)
4482 gchar *first_line_match;
4485 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4487 /* We're now before the search limit, abort. */
4491 /* If there are multiple lines, the first line will
4492 * end in '\n', so this will only match at the
4493 * end of the first line, which is correct.
4495 first_line_match = my_strrstr (*win.lines, *lines);
4497 if (first_line_match &&
4498 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4503 GtkTextIter start_tmp;
4505 /* Offset to start of search string */
4506 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4508 next = win.first_line_start;
4510 forward_chars_with_skipping (&start_tmp, offset,
4511 visible_only, !slice);
4514 gtk_text_iter_compare (limit, &start_tmp) > 0)
4515 goto out; /* match was bogus */
4518 *match_start = start_tmp;
4520 /* Go to end of search string */
4524 offset += g_utf8_strlen (*l, -1);
4528 forward_chars_with_skipping (&next, offset,
4529 visible_only, !slice);
4538 while (lines_window_back (&win));
4541 lines_window_free (&win);
4552 * gtk_text_iter_equal:
4553 * @lhs: a #GtkTextIter
4554 * @rhs: another #GtkTextIter
4556 * Tests whether two iterators are equal, using the fastest possible
4557 * mechanism. This function is very fast; you can expect it to perform
4558 * better than e.g. getting the character offset for each iterator and
4559 * comparing the offsets yourself. Also, it's a bit faster than
4560 * gtk_text_iter_compare().
4562 * Return value: %TRUE if the iterators point to the same place in the buffer
4565 gtk_text_iter_equal (const GtkTextIter *lhs,
4566 const GtkTextIter *rhs)
4568 GtkTextRealIter *real_lhs;
4569 GtkTextRealIter *real_rhs;
4571 real_lhs = (GtkTextRealIter*)lhs;
4572 real_rhs = (GtkTextRealIter*)rhs;
4574 check_invariants (lhs);
4575 check_invariants (rhs);
4577 if (real_lhs->line != real_rhs->line)
4579 else if (real_lhs->line_byte_offset >= 0 &&
4580 real_rhs->line_byte_offset >= 0)
4581 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4584 /* the ensure_char_offsets () calls do nothing if the char offsets
4585 are already up-to-date. */
4586 ensure_char_offsets (real_lhs);
4587 ensure_char_offsets (real_rhs);
4588 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4593 * gtk_text_iter_compare:
4594 * @lhs: a #GtkTextIter
4595 * @rhs: another #GtkTextIter
4597 * A qsort()-style function that returns negative if @lhs is less than
4598 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4599 * Ordering is in character offset order, i.e. the first character in the buffer
4600 * is less than the second character in the buffer.
4602 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4605 gtk_text_iter_compare (const GtkTextIter *lhs,
4606 const GtkTextIter *rhs)
4608 GtkTextRealIter *real_lhs;
4609 GtkTextRealIter *real_rhs;
4611 real_lhs = gtk_text_iter_make_surreal (lhs);
4612 real_rhs = gtk_text_iter_make_surreal (rhs);
4614 if (real_lhs == NULL ||
4616 return -1; /* why not */
4618 check_invariants (lhs);
4619 check_invariants (rhs);
4621 if (real_lhs->line == real_rhs->line)
4623 gint left_index, right_index;
4625 if (real_lhs->line_byte_offset >= 0 &&
4626 real_rhs->line_byte_offset >= 0)
4628 left_index = real_lhs->line_byte_offset;
4629 right_index = real_rhs->line_byte_offset;
4633 /* the ensure_char_offsets () calls do nothing if
4634 the offsets are already up-to-date. */
4635 ensure_char_offsets (real_lhs);
4636 ensure_char_offsets (real_rhs);
4637 left_index = real_lhs->line_char_offset;
4638 right_index = real_rhs->line_char_offset;
4641 if (left_index < right_index)
4643 else if (left_index > right_index)
4652 line1 = gtk_text_iter_get_line (lhs);
4653 line2 = gtk_text_iter_get_line (rhs);
4656 else if (line1 > line2)
4664 * gtk_text_iter_in_range:
4665 * @iter: a #GtkTextIter
4666 * @start: start of range
4667 * @end: end of range
4669 * @start and @end must be in order, unlike most text buffer
4670 * functions, for efficiency reasons. The function returns %TRUE if
4671 * @iter falls in the range [@start, @end).
4673 * Return value: %TRUE if @iter is in the range
4676 gtk_text_iter_in_range (const GtkTextIter *iter,
4677 const GtkTextIter *start,
4678 const GtkTextIter *end)
4680 return gtk_text_iter_compare (iter, start) >= 0 &&
4681 gtk_text_iter_compare (iter, end) < 0;
4685 * gtk_text_iter_order:
4686 * @first: a #GtkTextIter
4687 * @second: another #GtkTextIter
4689 * Swaps the value of @first and @second if @second comes before
4690 * @first in the buffer. That is, ensures that @first and @second are
4691 * in sequence. Most text buffer functions that take a range call this
4692 * automatically on your behalf, so there's no real reason to call it yourself
4693 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4694 * that expect a pre-sorted range.
4698 gtk_text_iter_order (GtkTextIter *first,
4699 GtkTextIter *second)
4701 g_return_if_fail (first != NULL);
4702 g_return_if_fail (second != NULL);
4704 if (gtk_text_iter_compare (first, second) > 0)
4715 * Init iterators from the BTree
4719 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4723 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4724 gint real_char_index;
4728 g_return_if_fail (iter != NULL);
4729 g_return_if_fail (tree != NULL);
4731 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4732 &line_start, &real_char_index);
4734 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4736 real->cached_char_index = real_char_index;
4738 check_invariants (iter);
4742 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4747 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4751 g_return_if_fail (iter != NULL);
4752 g_return_if_fail (tree != NULL);
4754 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4756 iter_init_from_char_offset (iter, tree, line, char_on_line);
4758 /* We might as well cache this, since we know it. */
4759 real->cached_line_number = real_line;
4761 check_invariants (iter);
4765 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4770 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4774 g_return_if_fail (iter != NULL);
4775 g_return_if_fail (tree != NULL);
4777 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4779 iter_init_from_byte_offset (iter, tree, line, byte_index);
4781 /* We might as well cache this, since we know it. */
4782 real->cached_line_number = real_line;
4784 check_invariants (iter);
4788 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4793 g_return_if_fail (iter != NULL);
4794 g_return_if_fail (tree != NULL);
4795 g_return_if_fail (line != NULL);
4797 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4799 check_invariants (iter);
4803 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4809 g_return_val_if_fail (iter != NULL, FALSE);
4810 g_return_val_if_fail (tree != NULL, FALSE);
4812 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4816 /* Set iter to last in tree */
4817 _gtk_text_btree_get_end_iter (tree, iter);
4818 check_invariants (iter);
4823 iter_init_from_byte_offset (iter, tree, line, 0);
4824 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4825 check_invariants (iter);
4831 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4835 g_return_val_if_fail (iter != NULL, FALSE);
4836 g_return_val_if_fail (tree != NULL, FALSE);
4838 _gtk_text_btree_get_end_iter (tree, iter);
4839 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4840 check_invariants (iter);
4846 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4848 const gchar *mark_name)
4852 g_return_val_if_fail (iter != NULL, FALSE);
4853 g_return_val_if_fail (tree != NULL, FALSE);
4855 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4861 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4862 check_invariants (iter);
4868 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4872 GtkTextLineSegment *seg;
4874 g_return_if_fail (iter != NULL);
4875 g_return_if_fail (tree != NULL);
4876 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4878 seg = mark->segment;
4880 iter_init_from_segment (iter, tree,
4881 seg->body.mark.line, seg);
4882 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4883 check_invariants (iter);
4887 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4889 GtkTextChildAnchor *anchor)
4891 GtkTextLineSegment *seg;
4893 g_return_if_fail (iter != NULL);
4894 g_return_if_fail (tree != NULL);
4895 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4897 seg = anchor->segment;
4899 iter_init_from_segment (iter, tree,
4900 seg->body.child.line, seg);
4901 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4902 check_invariants (iter);
4906 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
4909 g_return_if_fail (iter != NULL);
4910 g_return_if_fail (tree != NULL);
4912 _gtk_text_btree_get_iter_at_char (tree,
4914 _gtk_text_btree_char_count (tree));
4915 check_invariants (iter);
4919 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
4921 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4923 g_return_if_fail (iter != NULL);
4925 if (real->chars_changed_stamp != _gtk_text_btree_get_chars_changed_stamp (real->tree))
4926 g_print (" %20s: <invalidated iterator>\n", desc);
4929 check_invariants (iter);
4930 g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
4932 gtk_text_iter_get_line (iter),
4933 gtk_text_iter_get_offset (iter),
4934 gtk_text_iter_get_line_offset (iter),
4935 gtk_text_iter_get_line_index (iter));
4936 check_invariants (iter);
4941 _gtk_text_iter_check (const GtkTextIter *iter)
4943 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
4944 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
4945 GtkTextLineSegment *byte_segment = NULL;
4946 GtkTextLineSegment *byte_any_segment = NULL;
4947 GtkTextLineSegment *char_segment = NULL;
4948 GtkTextLineSegment *char_any_segment = NULL;
4949 gboolean segments_updated;
4951 /* This function checks our class invariants for the Iter class. */
4953 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
4955 if (real->chars_changed_stamp !=
4956 _gtk_text_btree_get_chars_changed_stamp (real->tree))
4957 g_error ("iterator check failed: invalid iterator");
4959 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
4960 g_error ("iterator check failed: both char and byte offsets are invalid");
4962 segments_updated = (real->segments_changed_stamp ==
4963 _gtk_text_btree_get_segments_changed_stamp (real->tree));
4966 printf ("checking iter, segments %s updated, byte %d char %d\n",
4967 segments_updated ? "are" : "aren't",
4968 real->line_byte_offset,
4969 real->line_char_offset);
4972 if (segments_updated)
4974 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
4975 g_error ("iterator check failed: both char and byte segment offsets are invalid");
4977 if (real->segment->char_count == 0)
4978 g_error ("iterator check failed: segment is not indexable.");
4980 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
4981 g_error ("segment char offset is not properly up-to-date");
4983 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
4984 g_error ("segment byte offset is not properly up-to-date");
4986 if (real->segment_byte_offset >= 0 &&
4987 real->segment_byte_offset >= real->segment->byte_count)
4988 g_error ("segment byte offset is too large.");
4990 if (real->segment_char_offset >= 0 &&
4991 real->segment_char_offset >= real->segment->char_count)
4992 g_error ("segment char offset is too large.");
4995 if (real->line_byte_offset >= 0)
4997 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
4998 &byte_segment, &byte_any_segment,
4999 &seg_byte_offset, &line_byte_offset);
5001 if (line_byte_offset != real->line_byte_offset)
5002 g_error ("wrong byte offset was stored in iterator");
5004 if (segments_updated)
5006 if (real->segment != byte_segment)
5007 g_error ("wrong segment was stored in iterator");
5009 if (real->any_segment != byte_any_segment)
5010 g_error ("wrong any_segment was stored in iterator");
5012 if (seg_byte_offset != real->segment_byte_offset)
5013 g_error ("wrong segment byte offset was stored in iterator");
5015 if (byte_segment->type == >k_text_char_type)
5018 p = byte_segment->body.chars + seg_byte_offset;
5020 if (!gtk_text_byte_begins_utf8_char (p))
5021 g_error ("broken iterator byte index pointed into the middle of a character");
5026 if (real->line_char_offset >= 0)
5028 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5029 &char_segment, &char_any_segment,
5030 &seg_char_offset, &line_char_offset);
5032 if (line_char_offset != real->line_char_offset)
5033 g_error ("wrong char offset was stored in iterator");
5035 if (segments_updated)
5037 if (real->segment != char_segment)
5038 g_error ("wrong segment was stored in iterator");
5040 if (real->any_segment != char_any_segment)
5041 g_error ("wrong any_segment was stored in iterator");
5043 if (seg_char_offset != real->segment_char_offset)
5044 g_error ("wrong segment char offset was stored in iterator");
5046 if (char_segment->type == >k_text_char_type)
5049 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5052 /* hmm, not likely to happen eh */
5053 if (!gtk_text_byte_begins_utf8_char (p))
5054 g_error ("broken iterator char offset pointed into the middle of a character");
5059 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5061 if (byte_segment != char_segment)
5062 g_error ("char and byte offsets did not point to the same segment");
5064 if (byte_any_segment != char_any_segment)
5065 g_error ("char and byte offsets did not point to the same any segment");
5067 /* Make sure the segment offsets are equivalent, if it's a char
5069 if (char_segment->type == >k_text_char_type)
5071 gint byte_offset = 0;
5072 gint char_offset = 0;
5073 while (char_offset < seg_char_offset)
5075 const char * start = char_segment->body.chars + byte_offset;
5076 byte_offset += g_utf8_next_char (start) - start;
5080 if (byte_offset != seg_byte_offset)
5081 g_error ("byte offset did not correspond to char offset");
5084 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5086 if (char_offset != seg_char_offset)
5087 g_error ("char offset did not correspond to byte offset");
5089 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5090 g_error ("byte index for iterator does not index the start of a character");
5094 if (real->cached_line_number >= 0)
5098 should_be = _gtk_text_line_get_number (real->line);
5099 if (real->cached_line_number != should_be)
5100 g_error ("wrong line number was cached");
5103 if (real->cached_char_index >= 0)
5105 if (real->line_char_offset >= 0) /* only way we can check it
5106 efficiently, not a real
5111 char_index = _gtk_text_line_char_index (real->line);
5112 char_index += real->line_char_offset;
5114 if (real->cached_char_index != char_index)
5115 g_error ("wrong char index was cached");