1 /* GTK - The GIMP Toolkit
2 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
29 #include "gtktextiter.h"
30 #include "gtktextbtree.h"
31 #include "gtktextiterprivate.h"
40 * @Short_description: Text buffer iterator
43 * You may wish to begin by reading the <link linkend="TextWidget">text widget
44 * conceptual overview</link> which gives an overview of all the objects and data
45 * types related to the text widget and how they work together.
49 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
51 typedef struct _GtkTextRealIter GtkTextRealIter;
53 struct G_GNUC_MAY_ALIAS _GtkTextRealIter
55 /* Always-valid information */
58 /* At least one of these is always valid;
59 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 line_byte_offset;
64 gint line_char_offset;
65 /* These two are valid if >= 0 */
66 gint cached_char_index;
67 gint cached_line_number;
68 /* Stamps to detect the buffer changing under us */
69 gint chars_changed_stamp;
70 gint segments_changed_stamp;
71 /* Valid if the segments_changed_stamp is up-to-date */
72 GtkTextLineSegment *segment; /* indexable segment we index */
73 GtkTextLineSegment *any_segment; /* first segment in our location,
74 maybe same as "segment" */
75 /* One of these will always be valid if segments_changed_stamp is
76 up-to-date. If invalid, they are -1.
78 If the line byte offset is valid, so is the segment byte offset;
79 and ditto for char offsets. */
80 gint segment_byte_offset;
81 gint segment_char_offset;
88 /* These "set" functions should not assume any fields
89 other than the char stamp and the tree are valid.
92 iter_set_common (GtkTextRealIter *iter,
95 /* Update segments stamp */
96 iter->segments_changed_stamp =
97 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
101 iter->line_byte_offset = -1;
102 iter->line_char_offset = -1;
103 iter->segment_byte_offset = -1;
104 iter->segment_char_offset = -1;
105 iter->cached_char_index = -1;
106 iter->cached_line_number = -1;
110 iter_set_from_byte_offset (GtkTextRealIter *iter,
114 iter_set_common (iter, line);
116 if (!_gtk_text_line_byte_locate (iter->line,
120 &iter->segment_byte_offset,
121 &iter->line_byte_offset))
122 g_error ("Byte index %d is off the end of the line",
127 iter_set_from_char_offset (GtkTextRealIter *iter,
131 iter_set_common (iter, line);
133 if (!_gtk_text_line_char_locate (iter->line,
137 &iter->segment_char_offset,
138 &iter->line_char_offset))
139 g_error ("Char offset %d is off the end of the line",
144 iter_set_from_segment (GtkTextRealIter *iter,
146 GtkTextLineSegment *segment)
148 GtkTextLineSegment *seg;
151 /* This could theoretically be optimized by computing all the iter
152 fields in this same loop, but I'm skipping it for now. */
154 seg = line->segments;
155 while (seg != segment)
157 byte_offset += seg->byte_count;
161 iter_set_from_byte_offset (iter, line, byte_offset);
164 /* This function ensures that the segment-dependent information is
165 truly computed lazily; often we don't need to do the full make_real
166 work. This ensures the btree and line are valid, but doesn't
167 update the segments. */
168 static GtkTextRealIter*
169 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
171 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
173 if (iter->chars_changed_stamp !=
174 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
176 g_warning ("Invalid text buffer iterator: either the iterator "
177 "is uninitialized, or the characters/pixbufs/widgets "
178 "in the buffer have been modified since the iterator "
179 "was created.\nYou must use marks, character numbers, "
180 "or line numbers to preserve a position across buffer "
181 "modifications.\nYou can apply tags and insert marks "
182 "without invalidating your iterators,\n"
183 "but any mutation that affects 'indexable' buffer contents "
184 "(contents that can be referred to by character offset)\n"
185 "will invalidate all outstanding iterators");
189 /* We don't update the segments information since we are becoming
190 only surreal. However we do invalidate the segments information
191 if appropriate, to be sure we segfault if we try to use it and we
192 should have used make_real. */
194 if (iter->segments_changed_stamp !=
195 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
197 iter->segment = NULL;
198 iter->any_segment = NULL;
199 /* set to segfault-causing values. */
200 iter->segment_byte_offset = -10000;
201 iter->segment_char_offset = -10000;
207 static GtkTextRealIter*
208 gtk_text_iter_make_real (const GtkTextIter *_iter)
210 GtkTextRealIter *iter;
212 iter = gtk_text_iter_make_surreal (_iter);
214 if (iter->segments_changed_stamp !=
215 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
217 if (iter->line_byte_offset >= 0)
219 iter_set_from_byte_offset (iter,
221 iter->line_byte_offset);
225 g_assert (iter->line_char_offset >= 0);
227 iter_set_from_char_offset (iter,
229 iter->line_char_offset);
233 g_assert (iter->segment != NULL);
234 g_assert (iter->any_segment != NULL);
235 g_assert (iter->segment->char_count > 0);
240 static GtkTextRealIter*
241 iter_init_common (GtkTextIter *_iter,
244 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
246 g_return_val_if_fail (iter != NULL, NULL);
247 g_return_val_if_fail (tree != NULL, NULL);
251 iter->chars_changed_stamp =
252 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
257 static GtkTextRealIter*
258 iter_init_from_segment (GtkTextIter *iter,
261 GtkTextLineSegment *segment)
263 GtkTextRealIter *real;
265 g_return_val_if_fail (line != NULL, NULL);
267 real = iter_init_common (iter, tree);
269 iter_set_from_segment (real, line, segment);
274 static GtkTextRealIter*
275 iter_init_from_byte_offset (GtkTextIter *iter,
278 gint line_byte_offset)
280 GtkTextRealIter *real;
282 g_return_val_if_fail (line != NULL, NULL);
284 real = iter_init_common (iter, tree);
286 iter_set_from_byte_offset (real, line, line_byte_offset);
288 if (real->segment->type == >k_text_char_type &&
289 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
290 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
291 "character; this will crash the text buffer. "
292 "Byte indexes must refer to the start of a character.",
298 static GtkTextRealIter*
299 iter_init_from_char_offset (GtkTextIter *iter,
302 gint line_char_offset)
304 GtkTextRealIter *real;
306 g_return_val_if_fail (line != NULL, NULL);
308 real = iter_init_common (iter, tree);
310 iter_set_from_char_offset (real, line, line_char_offset);
316 invalidate_char_index (GtkTextRealIter *iter)
318 iter->cached_char_index = -1;
322 adjust_char_index (GtkTextRealIter *iter, gint count)
324 if (iter->cached_char_index >= 0)
325 iter->cached_char_index += count;
329 adjust_line_number (GtkTextRealIter *iter, gint count)
331 if (iter->cached_line_number >= 0)
332 iter->cached_line_number += count;
336 ensure_char_offsets (GtkTextRealIter *iter)
338 if (iter->line_char_offset < 0)
340 g_assert (iter->line_byte_offset >= 0);
342 _gtk_text_line_byte_to_char_offsets (iter->line,
343 iter->line_byte_offset,
344 &iter->line_char_offset,
345 &iter->segment_char_offset);
350 ensure_byte_offsets (GtkTextRealIter *iter)
352 if (iter->line_byte_offset < 0)
354 g_assert (iter->line_char_offset >= 0);
356 _gtk_text_line_char_to_byte_offsets (iter->line,
357 iter->line_char_offset,
358 &iter->line_byte_offset,
359 &iter->segment_byte_offset);
363 static inline gboolean
364 is_segment_start (GtkTextRealIter *real)
366 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
369 #ifdef G_ENABLE_DEBUG
371 check_invariants (const GtkTextIter *iter)
373 if (gtk_get_debug_flags () & GTK_DEBUG_TEXT)
374 _gtk_text_iter_check (iter);
377 #define check_invariants(x)
381 * gtk_text_iter_get_buffer:
384 * Returns the #GtkTextBuffer this iterator is associated with.
386 * Return value: (transfer none): the buffer
389 gtk_text_iter_get_buffer (const GtkTextIter *iter)
391 GtkTextRealIter *real;
393 g_return_val_if_fail (iter != NULL, NULL);
395 real = gtk_text_iter_make_surreal (iter);
400 check_invariants (iter);
402 return _gtk_text_btree_get_buffer (real->tree);
406 * gtk_text_iter_copy:
409 * Creates a dynamically-allocated copy of an iterator. This function
410 * is not useful in applications, because iterators can be copied with a
411 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
412 * function is used by language bindings.
414 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
417 gtk_text_iter_copy (const GtkTextIter *iter)
419 GtkTextIter *new_iter;
421 g_return_val_if_fail (iter != NULL, NULL);
423 new_iter = g_slice_new (GtkTextIter);
431 * gtk_text_iter_free:
432 * @iter: a dynamically-allocated iterator
434 * Free an iterator allocated on the heap. This function
435 * is intended for use in language bindings, and is not
436 * especially useful for applications, because iterators can
437 * simply be allocated on the stack.
440 gtk_text_iter_free (GtkTextIter *iter)
442 g_return_if_fail (iter != NULL);
444 g_slice_free (GtkTextIter, iter);
448 * gtk_text_iter_assign:
449 * @iter: a #GtkTextIter
450 * @other: another #GtkTextIter
452 * Assigns the value of @other to @iter. This function
453 * is not useful in applications, because iterators can be assigned
454 * with <literal>GtkTextIter i = j;</literal>. The
455 * function is used by language bindings.
460 gtk_text_iter_assign (GtkTextIter *iter,
461 const GtkTextIter *other)
463 g_return_if_fail (iter != NULL);
464 g_return_if_fail (other != NULL);
469 G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
474 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
476 GtkTextRealIter *real;
478 g_return_val_if_fail (iter != NULL, NULL);
480 real = gtk_text_iter_make_real (iter);
485 check_invariants (iter);
487 g_assert (real->segment != NULL);
489 return real->segment;
493 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
495 GtkTextRealIter *real;
497 g_return_val_if_fail (iter != NULL, NULL);
499 real = gtk_text_iter_make_real (iter);
504 check_invariants (iter);
506 g_assert (real->any_segment != NULL);
508 return real->any_segment;
512 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
514 GtkTextRealIter *real;
516 g_return_val_if_fail (iter != NULL, 0);
518 real = gtk_text_iter_make_real (iter);
523 ensure_byte_offsets (real);
525 check_invariants (iter);
527 return real->segment_byte_offset;
531 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
533 GtkTextRealIter *real;
535 g_return_val_if_fail (iter != NULL, 0);
537 real = gtk_text_iter_make_real (iter);
542 ensure_char_offsets (real);
544 check_invariants (iter);
546 return real->segment_char_offset;
549 /* This function does not require a still-valid
552 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
554 const GtkTextRealIter *real;
556 g_return_val_if_fail (iter != NULL, NULL);
558 real = (const GtkTextRealIter*)iter;
563 /* This function does not require a still-valid
566 _gtk_text_iter_get_btree (const GtkTextIter *iter)
568 const GtkTextRealIter *real;
570 g_return_val_if_fail (iter != NULL, NULL);
572 real = (const GtkTextRealIter*)iter;
582 * gtk_text_iter_get_offset:
585 * Returns the character offset of an iterator.
586 * Each character in a #GtkTextBuffer has an offset,
587 * starting with 0 for the first character in the buffer.
588 * Use gtk_text_buffer_get_iter_at_offset () to convert an
589 * offset back into an iterator.
591 * Return value: a character offset
594 gtk_text_iter_get_offset (const GtkTextIter *iter)
596 GtkTextRealIter *real;
598 g_return_val_if_fail (iter != NULL, 0);
600 real = gtk_text_iter_make_surreal (iter);
605 check_invariants (iter);
607 if (real->cached_char_index < 0)
609 ensure_char_offsets (real);
611 real->cached_char_index =
612 _gtk_text_line_char_index (real->line);
613 real->cached_char_index += real->line_char_offset;
616 check_invariants (iter);
618 return real->cached_char_index;
622 * gtk_text_iter_get_line:
625 * Returns the line number containing the iterator. Lines in
626 * a #GtkTextBuffer are numbered beginning with 0 for the first
627 * line in the buffer.
629 * Return value: a line number
632 gtk_text_iter_get_line (const GtkTextIter *iter)
634 GtkTextRealIter *real;
636 g_return_val_if_fail (iter != NULL, 0);
638 real = gtk_text_iter_make_surreal (iter);
643 if (real->cached_line_number < 0)
644 real->cached_line_number =
645 _gtk_text_line_get_number (real->line);
647 check_invariants (iter);
649 return real->cached_line_number;
653 * gtk_text_iter_get_line_offset:
656 * Returns the character offset of the iterator,
657 * counting from the start of a newline-terminated line.
658 * The first character on the line has offset 0.
660 * Return value: offset from start of line
663 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
665 GtkTextRealIter *real;
667 g_return_val_if_fail (iter != NULL, 0);
669 real = gtk_text_iter_make_surreal (iter);
674 ensure_char_offsets (real);
676 check_invariants (iter);
678 return real->line_char_offset;
682 * gtk_text_iter_get_line_index:
685 * Returns the byte index of the iterator, counting
686 * from the start of a newline-terminated line.
687 * Remember that #GtkTextBuffer encodes text in
688 * UTF-8, and that characters can require a variable
689 * number of bytes to represent.
691 * Return value: distance from start of line, in bytes
694 gtk_text_iter_get_line_index (const GtkTextIter *iter)
696 GtkTextRealIter *real;
698 g_return_val_if_fail (iter != NULL, 0);
700 real = gtk_text_iter_make_surreal (iter);
705 ensure_byte_offsets (real);
707 check_invariants (iter);
709 return real->line_byte_offset;
713 * gtk_text_iter_get_visible_line_offset:
714 * @iter: a #GtkTextIter
716 * Returns the offset in characters from the start of the
717 * line to the given @iter, not counting characters that
718 * are invisible due to tags with the "invisible" flag
721 * Return value: offset in visible characters from the start of the line
724 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
726 GtkTextRealIter *real;
728 GtkTextLineSegment *seg;
731 g_return_val_if_fail (iter != NULL, 0);
733 real = gtk_text_iter_make_real (iter);
738 ensure_char_offsets (real);
740 check_invariants (iter);
742 vis_offset = real->line_char_offset;
744 g_assert (vis_offset >= 0);
746 _gtk_text_btree_get_iter_at_line (real->tree,
751 seg = _gtk_text_iter_get_indexable_segment (&pos);
753 while (seg != real->segment)
755 /* This is a pretty expensive call, making the
756 * whole function pretty lame; we could keep track
757 * of current invisibility state by looking at toggle
758 * segments as we loop, and then call this function
759 * only once per line, in order to speed up the loop
762 if (_gtk_text_btree_char_is_invisible (&pos))
763 vis_offset -= seg->char_count;
765 _gtk_text_iter_forward_indexable_segment (&pos);
767 seg = _gtk_text_iter_get_indexable_segment (&pos);
770 if (_gtk_text_btree_char_is_invisible (&pos))
771 vis_offset -= real->segment_char_offset;
778 * gtk_text_iter_get_visible_line_index:
779 * @iter: a #GtkTextIter
781 * Returns the number of bytes from the start of the
782 * line to the given @iter, not counting bytes that
783 * are invisible due to tags with the "invisible" flag
786 * Return value: byte index of @iter with respect to the start of the line
789 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
791 GtkTextRealIter *real;
793 GtkTextLineSegment *seg;
796 g_return_val_if_fail (iter != NULL, 0);
798 real = gtk_text_iter_make_real (iter);
803 ensure_byte_offsets (real);
805 check_invariants (iter);
807 vis_offset = real->line_byte_offset;
809 g_assert (vis_offset >= 0);
811 _gtk_text_btree_get_iter_at_line (real->tree,
816 seg = _gtk_text_iter_get_indexable_segment (&pos);
818 while (seg != real->segment)
820 /* This is a pretty expensive call, making the
821 * whole function pretty lame; we could keep track
822 * of current invisibility state by looking at toggle
823 * segments as we loop, and then call this function
824 * only once per line, in order to speed up the loop
827 if (_gtk_text_btree_char_is_invisible (&pos))
828 vis_offset -= seg->byte_count;
830 _gtk_text_iter_forward_indexable_segment (&pos);
832 seg = _gtk_text_iter_get_indexable_segment (&pos);
835 if (_gtk_text_btree_char_is_invisible (&pos))
836 vis_offset -= real->segment_byte_offset;
846 * gtk_text_iter_get_char:
849 * Returns the Unicode character at this iterator. (Equivalent to
850 * operator* on a C++ iterator.) If the element at this iterator is a
851 * non-character element, such as an image embedded in the buffer, the
852 * Unicode "unknown" character 0xFFFC is returned. If invoked on
853 * the end iterator, zero is returned; zero is not a valid Unicode character.
854 * So you can write a loop which ends when gtk_text_iter_get_char ()
857 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
860 gtk_text_iter_get_char (const GtkTextIter *iter)
862 GtkTextRealIter *real;
864 g_return_val_if_fail (iter != NULL, 0);
866 real = gtk_text_iter_make_real (iter);
871 check_invariants (iter);
873 if (gtk_text_iter_is_end (iter))
875 else if (real->segment->type == >k_text_char_type)
877 ensure_byte_offsets (real);
879 return g_utf8_get_char (real->segment->body.chars +
880 real->segment_byte_offset);
884 /* Unicode "unknown character" 0xFFFC */
885 return GTK_TEXT_UNKNOWN_CHAR;
890 * gtk_text_iter_get_slice:
891 * @start: iterator at start of a range
892 * @end: iterator at end of a range
894 * Returns the text in the given range. A "slice" is an array of
895 * characters encoded in UTF-8 format, including the Unicode "unknown"
896 * character 0xFFFC for iterable non-character elements in the buffer,
897 * such as images. Because images are encoded in the slice, byte and
898 * character offsets in the returned array will correspond to byte
899 * offsets in the text buffer. Note that 0xFFFC can occur in normal
900 * text as well, so it is not a reliable indicator that a pixbuf or
901 * widget is in the buffer.
903 * Return value: slice of text from the buffer
906 gtk_text_iter_get_slice (const GtkTextIter *start,
907 const GtkTextIter *end)
909 g_return_val_if_fail (start != NULL, NULL);
910 g_return_val_if_fail (end != NULL, NULL);
912 check_invariants (start);
913 check_invariants (end);
915 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
919 * gtk_text_iter_get_text:
920 * @start: iterator at start of a range
921 * @end: iterator at end of a range
923 * Returns <emphasis>text</emphasis> in the given range. If the range
924 * contains non-text elements such as images, the character and byte
925 * offsets in the returned string will not correspond to character and
926 * byte offsets in the buffer. If you want offsets to correspond, see
927 * gtk_text_iter_get_slice ().
929 * Return value: array of characters from the buffer
932 gtk_text_iter_get_text (const GtkTextIter *start,
933 const GtkTextIter *end)
935 g_return_val_if_fail (start != NULL, NULL);
936 g_return_val_if_fail (end != NULL, NULL);
938 check_invariants (start);
939 check_invariants (end);
941 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
945 * gtk_text_iter_get_visible_slice:
946 * @start: iterator at start of range
947 * @end: iterator at end of range
949 * Like gtk_text_iter_get_slice (), but invisible text is not included.
950 * Invisible text is usually invisible because a #GtkTextTag with the
951 * "invisible" attribute turned on has been applied to it.
953 * Return value: slice of text from the buffer
956 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
957 const GtkTextIter *end)
959 g_return_val_if_fail (start != NULL, NULL);
960 g_return_val_if_fail (end != NULL, NULL);
962 check_invariants (start);
963 check_invariants (end);
965 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
969 * gtk_text_iter_get_visible_text:
970 * @start: iterator at start of range
971 * @end: iterator at end of range
973 * Like gtk_text_iter_get_text (), but invisible text is not included.
974 * Invisible text is usually invisible because a #GtkTextTag with the
975 * "invisible" attribute turned on has been applied to it.
977 * Return value: string containing visible text in the range
980 gtk_text_iter_get_visible_text (const GtkTextIter *start,
981 const GtkTextIter *end)
983 g_return_val_if_fail (start != NULL, NULL);
984 g_return_val_if_fail (end != NULL, NULL);
986 check_invariants (start);
987 check_invariants (end);
989 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
993 * gtk_text_iter_get_pixbuf:
996 * If the element at @iter is a pixbuf, the pixbuf is returned
997 * (with no new reference count added). Otherwise,
1000 * Return value: (transfer none): the pixbuf at @iter
1003 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1005 GtkTextRealIter *real;
1007 g_return_val_if_fail (iter != NULL, NULL);
1009 real = gtk_text_iter_make_real (iter);
1014 check_invariants (iter);
1016 if (real->segment->type != >k_text_pixbuf_type)
1019 return real->segment->body.pixbuf.pixbuf;
1023 * gtk_text_iter_get_child_anchor:
1024 * @iter: an iterator
1026 * If the location at @iter contains a child anchor, the
1027 * anchor is returned (with no new reference count added). Otherwise,
1028 * %NULL is returned.
1030 * Return value: (transfer none): the anchor at @iter
1033 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1035 GtkTextRealIter *real;
1037 g_return_val_if_fail (iter != NULL, NULL);
1039 real = gtk_text_iter_make_real (iter);
1044 check_invariants (iter);
1046 if (real->segment->type != >k_text_child_type)
1049 return real->segment->body.child.obj;
1053 * gtk_text_iter_get_marks:
1054 * @iter: an iterator
1056 * Returns a list of all #GtkTextMark at this location. Because marks
1057 * are not iterable (they don't take up any "space" in the buffer,
1058 * they are just marks in between iterable locations), multiple marks
1059 * can exist in the same place. The returned list is not in any
1062 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1065 gtk_text_iter_get_marks (const GtkTextIter *iter)
1067 GtkTextRealIter *real;
1068 GtkTextLineSegment *seg;
1071 g_return_val_if_fail (iter != NULL, NULL);
1073 real = gtk_text_iter_make_real (iter);
1078 check_invariants (iter);
1081 seg = real->any_segment;
1082 while (seg != real->segment)
1084 if (seg->type == >k_text_left_mark_type ||
1085 seg->type == >k_text_right_mark_type)
1086 retval = g_slist_prepend (retval, seg->body.mark.obj);
1091 /* The returned list isn't guaranteed to be in any special order,
1097 * gtk_text_iter_get_toggled_tags:
1098 * @iter: an iterator
1099 * @toggled_on: %TRUE to get toggled-on tags
1101 * Returns a list of #GtkTextTag that are toggled on or off at this
1102 * point. (If @toggled_on is %TRUE, the list contains tags that are
1103 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1104 * range of characters following @iter has that tag applied to it. If
1105 * a tag is toggled off, then some non-empty range following @iter
1106 * does <emphasis>not</emphasis> have the tag applied to it.
1108 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1111 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1112 gboolean toggled_on)
1114 GtkTextRealIter *real;
1115 GtkTextLineSegment *seg;
1118 g_return_val_if_fail (iter != NULL, NULL);
1120 real = gtk_text_iter_make_real (iter);
1125 check_invariants (iter);
1128 seg = real->any_segment;
1129 while (seg != real->segment)
1133 if (seg->type == >k_text_toggle_on_type)
1135 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1140 if (seg->type == >k_text_toggle_off_type)
1142 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1149 /* The returned list isn't guaranteed to be in any special order,
1155 * gtk_text_iter_begins_tag:
1156 * @iter: an iterator
1157 * @tag: (allow-none): a #GtkTextTag, or %NULL
1159 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1160 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1161 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1162 * <emphasis>start</emphasis> of the tagged range;
1163 * gtk_text_iter_has_tag () tells you whether an iterator is
1164 * <emphasis>within</emphasis> a tagged range.
1166 * Return value: whether @iter is the start of a range tagged with @tag
1169 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1172 GtkTextRealIter *real;
1173 GtkTextLineSegment *seg;
1175 g_return_val_if_fail (iter != NULL, FALSE);
1177 real = gtk_text_iter_make_real (iter);
1182 check_invariants (iter);
1184 seg = real->any_segment;
1185 while (seg != real->segment)
1187 if (seg->type == >k_text_toggle_on_type)
1190 seg->body.toggle.info->tag == tag)
1201 * gtk_text_iter_ends_tag:
1202 * @iter: an iterator
1203 * @tag: (allow-none): a #GtkTextTag, or %NULL
1205 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1206 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1207 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1208 * <emphasis>end</emphasis> of the tagged range;
1209 * gtk_text_iter_has_tag () tells you whether an iterator is
1210 * <emphasis>within</emphasis> a tagged range.
1212 * Return value: whether @iter is the end of a range tagged with @tag
1216 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1219 GtkTextRealIter *real;
1220 GtkTextLineSegment *seg;
1222 g_return_val_if_fail (iter != NULL, FALSE);
1224 real = gtk_text_iter_make_real (iter);
1229 check_invariants (iter);
1231 seg = real->any_segment;
1232 while (seg != real->segment)
1234 if (seg->type == >k_text_toggle_off_type)
1237 seg->body.toggle.info->tag == tag)
1248 * gtk_text_iter_toggles_tag:
1249 * @iter: an iterator
1250 * @tag: (allow-none): a #GtkTextTag, or %NULL
1252 * This is equivalent to (gtk_text_iter_begins_tag () ||
1253 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1254 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1256 * Return value: whether @tag is toggled on or off at @iter
1259 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1262 GtkTextRealIter *real;
1263 GtkTextLineSegment *seg;
1265 g_return_val_if_fail (iter != NULL, FALSE);
1267 real = gtk_text_iter_make_real (iter);
1272 check_invariants (iter);
1274 seg = real->any_segment;
1275 while (seg != real->segment)
1277 if ( (seg->type == >k_text_toggle_off_type ||
1278 seg->type == >k_text_toggle_on_type) &&
1280 seg->body.toggle.info->tag == tag) )
1290 * gtk_text_iter_has_tag:
1291 * @iter: an iterator
1292 * @tag: a #GtkTextTag
1294 * Returns %TRUE if @iter is within a range tagged with @tag.
1296 * Return value: whether @iter is tagged with @tag
1299 gtk_text_iter_has_tag (const GtkTextIter *iter,
1302 GtkTextRealIter *real;
1304 g_return_val_if_fail (iter != NULL, FALSE);
1305 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1307 real = gtk_text_iter_make_surreal (iter);
1312 check_invariants (iter);
1314 if (real->line_byte_offset >= 0)
1316 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1317 real->line_byte_offset, tag);
1321 g_assert (real->line_char_offset >= 0);
1322 return _gtk_text_line_char_has_tag (real->line, real->tree,
1323 real->line_char_offset, tag);
1328 * gtk_text_iter_get_tags:
1329 * @iter: a #GtkTextIter
1331 * Returns a list of tags that apply to @iter, in ascending order of
1332 * priority (highest-priority tags are last). The #GtkTextTag in the
1333 * list don't have a reference added, but you have to free the list
1336 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1339 gtk_text_iter_get_tags (const GtkTextIter *iter)
1346 g_return_val_if_fail (iter != NULL, NULL);
1348 /* Get the tags at this spot */
1349 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1351 /* No tags, use default style */
1352 if (tags == NULL || tag_count == 0)
1361 while (i < tag_count)
1363 retval = g_slist_prepend (retval, tags[i]);
1369 /* Return tags in ascending order of priority */
1370 return g_slist_reverse (retval);
1374 * gtk_text_iter_editable:
1375 * @iter: an iterator
1376 * @default_setting: %TRUE if text is editable by default
1378 * Returns whether the character at @iter is within an editable region
1379 * of text. Non-editable text is "locked" and can't be changed by the
1380 * user via #GtkTextView. This function is simply a convenience
1381 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1382 * to this text affect editability, @default_setting will be returned.
1384 * You don't want to use this function to decide whether text can be
1385 * inserted at @iter, because for insertion you don't want to know
1386 * whether the char at @iter is inside an editable range, you want to
1387 * know whether a new character inserted at @iter would be inside an
1388 * editable range. Use gtk_text_iter_can_insert() to handle this
1391 * Return value: whether @iter is inside an editable range
1394 gtk_text_iter_editable (const GtkTextIter *iter,
1395 gboolean default_setting)
1397 GtkTextAttributes *values;
1400 g_return_val_if_fail (iter != NULL, FALSE);
1402 values = gtk_text_attributes_new ();
1404 values->editable = default_setting;
1406 gtk_text_iter_get_attributes (iter, values);
1408 retval = values->editable;
1410 gtk_text_attributes_unref (values);
1416 * gtk_text_iter_can_insert:
1417 * @iter: an iterator
1418 * @default_editability: %TRUE if text is editable by default
1420 * Considering the default editability of the buffer, and tags that
1421 * affect editability, determines whether text inserted at @iter would
1422 * be editable. If text inserted at @iter would be editable then the
1423 * user should be allowed to insert text at @iter.
1424 * gtk_text_buffer_insert_interactive() uses this function to decide
1425 * whether insertions are allowed at a given position.
1427 * Return value: whether text inserted at @iter would be editable
1430 gtk_text_iter_can_insert (const GtkTextIter *iter,
1431 gboolean default_editability)
1433 g_return_val_if_fail (iter != NULL, FALSE);
1435 if (gtk_text_iter_editable (iter, default_editability))
1437 /* If at start/end of buffer, default editability is used */
1438 else if ((gtk_text_iter_is_start (iter) ||
1439 gtk_text_iter_is_end (iter)) &&
1440 default_editability)
1444 /* if iter isn't editable, and the char before iter is,
1445 * then iter is the first char in an editable region
1446 * and thus insertion at iter results in editable text.
1448 GtkTextIter prev = *iter;
1449 gtk_text_iter_backward_char (&prev);
1450 return gtk_text_iter_editable (&prev, default_editability);
1456 * gtk_text_iter_get_language:
1457 * @iter: an iterator
1459 * A convenience wrapper around gtk_text_iter_get_attributes (),
1460 * which returns the language in effect at @iter. If no tags affecting
1461 * language apply to @iter, the return value is identical to that of
1462 * gtk_get_default_language ().
1464 * Return value: language in effect at @iter
1467 gtk_text_iter_get_language (const GtkTextIter *iter)
1469 GtkTextAttributes *values;
1470 PangoLanguage *retval;
1472 values = gtk_text_attributes_new ();
1474 gtk_text_iter_get_attributes (iter, values);
1476 retval = values->language;
1478 gtk_text_attributes_unref (values);
1484 * gtk_text_iter_starts_line:
1485 * @iter: an iterator
1487 * Returns %TRUE if @iter begins a paragraph,
1488 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1489 * However this function is potentially more efficient than
1490 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1491 * the offset, it just has to see whether it's 0.
1493 * Return value: whether @iter begins a line
1496 gtk_text_iter_starts_line (const GtkTextIter *iter)
1498 GtkTextRealIter *real;
1500 g_return_val_if_fail (iter != NULL, FALSE);
1502 real = gtk_text_iter_make_surreal (iter);
1507 check_invariants (iter);
1509 if (real->line_byte_offset >= 0)
1511 return (real->line_byte_offset == 0);
1515 g_assert (real->line_char_offset >= 0);
1516 return (real->line_char_offset == 0);
1521 * gtk_text_iter_ends_line:
1522 * @iter: an iterator
1524 * Returns %TRUE if @iter points to the start of the paragraph
1525 * delimiter characters for a line (delimiters will be either a
1526 * newline, a carriage return, a carriage return followed by a
1527 * newline, or a Unicode paragraph separator character). Note that an
1528 * iterator pointing to the \n of a \r\n pair will not be counted as
1529 * the end of a line, the line ends before the \r. The end iterator is
1530 * considered to be at the end of a line, even though there are no
1531 * paragraph delimiter chars there.
1533 * Return value: whether @iter is at the end of a line
1536 gtk_text_iter_ends_line (const GtkTextIter *iter)
1540 g_return_val_if_fail (iter != NULL, FALSE);
1542 check_invariants (iter);
1544 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1545 * Unicode 3.0; update this if that changes.
1547 #define PARAGRAPH_SEPARATOR 0x2029
1549 wc = gtk_text_iter_get_char (iter);
1551 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1553 else if (wc == '\n')
1555 GtkTextIter tmp = *iter;
1557 /* need to determine if a \r precedes the \n, in which case
1558 * we aren't the end of the line.
1559 * Note however that if \r and \n are on different lines, they
1560 * both are terminators. This for instance may happen after
1561 * deleting some text:
1563 1 some text\r delete 'a' 1 some text\r
1564 2 a\n ---------> 2 \n
1569 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1572 if (!gtk_text_iter_backward_char (&tmp))
1575 return gtk_text_iter_get_char (&tmp) != '\r';
1582 * gtk_text_iter_is_end:
1583 * @iter: an iterator
1585 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1586 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1587 * the most efficient way to check whether an iterator is the end
1590 * Return value: whether @iter is the end iterator
1593 gtk_text_iter_is_end (const GtkTextIter *iter)
1595 GtkTextRealIter *real;
1597 g_return_val_if_fail (iter != NULL, FALSE);
1599 real = gtk_text_iter_make_surreal (iter);
1604 check_invariants (iter);
1606 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1609 /* Now we need the segments validated */
1610 real = gtk_text_iter_make_real (iter);
1615 return _gtk_text_btree_is_end (real->tree, real->line,
1617 real->segment_byte_offset,
1618 real->segment_char_offset);
1622 * gtk_text_iter_is_start:
1623 * @iter: an iterator
1625 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1626 * if @iter has a character offset of 0.
1628 * Return value: whether @iter is the first in the buffer
1631 gtk_text_iter_is_start (const GtkTextIter *iter)
1633 return gtk_text_iter_get_offset (iter) == 0;
1637 * gtk_text_iter_get_chars_in_line:
1638 * @iter: an iterator
1640 * Returns the number of characters in the line containing @iter,
1641 * including the paragraph delimiters.
1643 * Return value: number of characters in the line
1646 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1648 GtkTextRealIter *real;
1650 GtkTextLineSegment *seg;
1652 g_return_val_if_fail (iter != NULL, 0);
1654 real = gtk_text_iter_make_surreal (iter);
1659 check_invariants (iter);
1661 if (real->line_char_offset >= 0)
1663 /* We can start at the segments we've already found. */
1664 count = real->line_char_offset - real->segment_char_offset;
1665 seg = _gtk_text_iter_get_indexable_segment (iter);
1669 /* count whole line. */
1670 seg = real->line->segments;
1677 count += seg->char_count;
1682 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1683 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1689 * gtk_text_iter_get_bytes_in_line:
1690 * @iter: an iterator
1692 * Returns the number of bytes in the line containing @iter,
1693 * including the paragraph delimiters.
1695 * Return value: number of bytes in the line
1698 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1700 GtkTextRealIter *real;
1702 GtkTextLineSegment *seg;
1704 g_return_val_if_fail (iter != NULL, 0);
1706 real = gtk_text_iter_make_surreal (iter);
1711 check_invariants (iter);
1713 if (real->line_byte_offset >= 0)
1715 /* We can start at the segments we've already found. */
1716 count = real->line_byte_offset - real->segment_byte_offset;
1717 seg = _gtk_text_iter_get_indexable_segment (iter);
1721 /* count whole line. */
1722 seg = real->line->segments;
1728 count += seg->byte_count;
1733 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1734 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1740 * gtk_text_iter_get_attributes:
1741 * @iter: an iterator
1742 * @values: (out): a #GtkTextAttributes to be filled in
1744 * Computes the effect of any tags applied to this spot in the
1745 * text. The @values parameter should be initialized to the default
1746 * settings you wish to use if no tags are in effect. You'd typically
1747 * obtain the defaults from gtk_text_view_get_default_attributes().
1749 * gtk_text_iter_get_attributes () will modify @values, applying the
1750 * effects of any tags present at @iter. If any tags affected @values,
1751 * the function returns %TRUE.
1753 * Return value: %TRUE if @values was modified
1756 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1757 GtkTextAttributes *values)
1762 /* Get the tags at this spot */
1763 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1765 /* No tags, use default style */
1766 if (tags == NULL || tag_count == 0)
1773 _gtk_text_attributes_fill_from_tags (values,
1783 * Increments/decrements
1786 /* The return value of this indicates WHETHER WE MOVED.
1787 * The return value of public functions indicates
1788 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1790 * This function will not change the iterator if
1791 * it's already on the last (end iter) line, i.e. it
1792 * won't move to the end of the last line.
1795 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1797 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1799 GtkTextLine *new_line;
1801 new_line = _gtk_text_line_next (real->line);
1802 g_assert (new_line);
1803 g_assert (new_line != real->line);
1804 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1806 real->line = new_line;
1808 real->line_byte_offset = 0;
1809 real->line_char_offset = 0;
1811 real->segment_byte_offset = 0;
1812 real->segment_char_offset = 0;
1814 /* Find first segments in new line */
1815 real->any_segment = real->line->segments;
1816 real->segment = real->any_segment;
1817 while (real->segment->char_count == 0)
1818 real->segment = real->segment->next;
1824 /* There is no way to move forward a line; we were already at
1825 * the line containing the end iterator.
1826 * However we may not be at the end iterator itself.
1834 /* The return value of this indicates WHETHER WE MOVED.
1835 * The return value of public functions indicates
1836 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1838 * This function is currently unused, thus it is #if-0-ed. It is
1839 * left here, since it's non-trivial code that might be useful in
1843 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1845 GtkTextLine *new_line;
1847 new_line = _gtk_text_line_previous (real->line);
1849 g_assert (new_line != real->line);
1851 if (new_line != NULL)
1853 real->line = new_line;
1855 real->line_byte_offset = 0;
1856 real->line_char_offset = 0;
1858 real->segment_byte_offset = 0;
1859 real->segment_char_offset = 0;
1861 /* Find first segments in new line */
1862 real->any_segment = real->line->segments;
1863 real->segment = real->any_segment;
1864 while (real->segment->char_count == 0)
1865 real->segment = real->segment->next;
1871 /* There is no way to move backward; we were already
1872 at the first line. */
1874 /* We leave real->line as-is */
1876 /* Note that we didn't clamp to the start of the first line. */
1883 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1887 forward_char (GtkTextRealIter *real)
1889 GtkTextIter *iter = (GtkTextIter*)real;
1891 check_invariants ((GtkTextIter*)real);
1893 ensure_char_offsets (real);
1895 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1897 /* Need to move to the next segment; if no next segment,
1898 need to move to next line. */
1899 return _gtk_text_iter_forward_indexable_segment (iter);
1903 /* Just moving within a segment. Keep byte count
1904 up-to-date, if it was already up-to-date. */
1906 g_assert (real->segment->type == >k_text_char_type);
1908 if (real->line_byte_offset >= 0)
1911 const char * start =
1912 real->segment->body.chars + real->segment_byte_offset;
1914 bytes = g_utf8_next_char (start) - start;
1916 real->line_byte_offset += bytes;
1917 real->segment_byte_offset += bytes;
1919 g_assert (real->segment_byte_offset < real->segment->byte_count);
1922 real->line_char_offset += 1;
1923 real->segment_char_offset += 1;
1925 adjust_char_index (real, 1);
1927 g_assert (real->segment_char_offset < real->segment->char_count);
1929 /* We moved into the middle of a segment, so the any_segment
1930 must now be the segment we're in the middle of. */
1931 real->any_segment = real->segment;
1933 check_invariants ((GtkTextIter*)real);
1935 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1943 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1945 /* Need to move to the next segment; if no next segment,
1946 need to move to next line. */
1947 GtkTextLineSegment *seg;
1948 GtkTextLineSegment *any_seg;
1949 GtkTextRealIter *real;
1953 g_return_val_if_fail (iter != NULL, FALSE);
1955 real = gtk_text_iter_make_real (iter);
1960 check_invariants (iter);
1962 if (real->line_char_offset >= 0)
1964 chars_skipped = real->segment->char_count - real->segment_char_offset;
1965 g_assert (chars_skipped > 0);
1970 if (real->line_byte_offset >= 0)
1972 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1973 g_assert (bytes_skipped > 0);
1978 /* Get first segment of any kind */
1979 any_seg = real->segment->next;
1980 /* skip non-indexable segments, if any */
1982 while (seg != NULL && seg->char_count == 0)
1987 real->any_segment = any_seg;
1988 real->segment = seg;
1990 if (real->line_byte_offset >= 0)
1992 g_assert (bytes_skipped > 0);
1993 real->segment_byte_offset = 0;
1994 real->line_byte_offset += bytes_skipped;
1997 if (real->line_char_offset >= 0)
1999 g_assert (chars_skipped > 0);
2000 real->segment_char_offset = 0;
2001 real->line_char_offset += chars_skipped;
2002 adjust_char_index (real, chars_skipped);
2005 check_invariants (iter);
2007 return !gtk_text_iter_is_end (iter);
2011 /* End of the line */
2012 if (forward_line_leaving_caches_unmodified (real))
2014 adjust_line_number (real, 1);
2015 if (real->line_char_offset >= 0)
2016 adjust_char_index (real, chars_skipped);
2018 g_assert (real->line_byte_offset == 0);
2019 g_assert (real->line_char_offset == 0);
2020 g_assert (real->segment_byte_offset == 0);
2021 g_assert (real->segment_char_offset == 0);
2022 g_assert (gtk_text_iter_starts_line (iter));
2024 check_invariants (iter);
2026 return !gtk_text_iter_is_end (iter);
2030 /* End of buffer, but iter is still at start of last segment,
2031 * not at the end iterator. We put it on the end iterator.
2034 check_invariants (iter);
2036 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2037 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2039 gtk_text_iter_forward_to_line_end (iter);
2041 g_assert (gtk_text_iter_is_end (iter));
2049 at_last_indexable_segment (GtkTextRealIter *real)
2051 GtkTextLineSegment *seg;
2053 /* Return TRUE if there are no indexable segments after
2057 seg = real->segment->next;
2060 if (seg->char_count > 0)
2067 /* Goes back to the start of the next segment, even if
2068 * we're not at the start of the current segment (always
2069 * ends up on a different segment if it returns TRUE)
2072 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2074 /* Move to the start of the previous segment; if no previous
2075 * segment, to the last segment in the previous line. This is
2076 * inherently a bit inefficient due to the singly-linked list and
2077 * tree nodes, but we can't afford the RAM for doubly-linked.
2079 GtkTextRealIter *real;
2080 GtkTextLineSegment *seg;
2081 GtkTextLineSegment *any_seg;
2082 GtkTextLineSegment *prev_seg;
2083 GtkTextLineSegment *prev_any_seg;
2087 g_return_val_if_fail (iter != NULL, FALSE);
2089 real = gtk_text_iter_make_real (iter);
2094 check_invariants (iter);
2096 /* Find first segments in line */
2097 any_seg = real->line->segments;
2099 while (seg->char_count == 0)
2102 if (seg == real->segment)
2104 /* Could probably do this case faster by hand-coding the
2108 /* We were already at the start of a line;
2109 * go back to the previous line.
2111 if (gtk_text_iter_backward_line (iter))
2113 /* Go forward to last indexable segment in line. */
2114 while (!at_last_indexable_segment (real))
2115 _gtk_text_iter_forward_indexable_segment (iter);
2117 check_invariants (iter);
2122 return FALSE; /* We were at the start of the first line. */
2125 /* We must be in the middle of a line; so find the indexable
2126 * segment just before our current segment.
2128 g_assert (seg != real->segment);
2132 prev_any_seg = any_seg;
2134 any_seg = seg->next;
2136 while (seg->char_count == 0)
2139 while (seg != real->segment);
2141 g_assert (prev_seg != NULL);
2142 g_assert (prev_any_seg != NULL);
2143 g_assert (prev_seg->char_count > 0);
2145 /* We skipped the entire previous segment, plus any
2146 * chars we were into the current segment.
2148 if (real->segment_byte_offset >= 0)
2149 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2153 if (real->segment_char_offset >= 0)
2154 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2158 real->segment = prev_seg;
2159 real->any_segment = prev_any_seg;
2160 real->segment_byte_offset = 0;
2161 real->segment_char_offset = 0;
2163 if (bytes_skipped >= 0)
2165 if (real->line_byte_offset >= 0)
2167 real->line_byte_offset -= bytes_skipped;
2168 g_assert (real->line_byte_offset >= 0);
2172 real->line_byte_offset = -1;
2174 if (chars_skipped >= 0)
2176 if (real->line_char_offset >= 0)
2178 real->line_char_offset -= chars_skipped;
2179 g_assert (real->line_char_offset >= 0);
2182 if (real->cached_char_index >= 0)
2184 real->cached_char_index -= chars_skipped;
2185 g_assert (real->cached_char_index >= 0);
2190 real->line_char_offset = -1;
2191 real->cached_char_index = -1;
2194 /* line number is unchanged. */
2196 check_invariants (iter);
2202 * gtk_text_iter_forward_char:
2203 * @iter: an iterator
2205 * Moves @iter forward by one character offset. Note that images
2206 * embedded in the buffer occupy 1 character slot, so
2207 * gtk_text_iter_forward_char () may actually move onto an image instead
2208 * of a character, if you have images in your buffer. If @iter is the
2209 * end iterator or one character before it, @iter will now point at
2210 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2211 * convenience when writing loops.
2213 * Return value: whether @iter moved and is dereferenceable
2216 gtk_text_iter_forward_char (GtkTextIter *iter)
2218 GtkTextRealIter *real;
2220 g_return_val_if_fail (iter != NULL, FALSE);
2222 real = gtk_text_iter_make_real (iter);
2228 check_invariants (iter);
2229 return forward_char (real);
2234 * gtk_text_iter_backward_char:
2235 * @iter: an iterator
2237 * Moves backward by one character offset. Returns %TRUE if movement
2238 * was possible; if @iter was the first in the buffer (character
2239 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2242 * Return value: whether movement was possible
2245 gtk_text_iter_backward_char (GtkTextIter *iter)
2247 g_return_val_if_fail (iter != NULL, FALSE);
2249 check_invariants (iter);
2251 return gtk_text_iter_backward_chars (iter, 1);
2255 Definitely we should try to linear scan as often as possible for
2256 movement within a single line, because we can't use the BTree to
2257 speed within-line searches up; for movement between lines, we would
2258 like to avoid the linear scan probably.
2260 Instead of using this constant, it might be nice to cache the line
2261 length in the iterator and linear scan if motion is within a single
2264 I guess you'd have to profile the various approaches.
2266 #define MAX_LINEAR_SCAN 150
2270 * gtk_text_iter_forward_chars:
2271 * @iter: an iterator
2272 * @count: number of characters to move, may be negative
2274 * Moves @count characters if possible (if @count would move past the
2275 * start or end of the buffer, moves to the start or end of the
2276 * buffer). The return value indicates whether the new position of
2277 * @iter is different from its original position, and dereferenceable
2278 * (the last iterator in the buffer is not dereferenceable). If @count
2279 * is 0, the function does nothing and returns %FALSE.
2281 * Return value: whether @iter moved and is dereferenceable
2284 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2286 GtkTextRealIter *real;
2288 g_return_val_if_fail (iter != NULL, FALSE);
2290 FIX_OVERFLOWS (count);
2292 real = gtk_text_iter_make_real (iter);
2296 else if (count == 0)
2299 return gtk_text_iter_backward_chars (iter, 0 - count);
2300 else if (count < MAX_LINEAR_SCAN)
2302 check_invariants (iter);
2306 if (!forward_char (real))
2311 return forward_char (real);
2315 gint current_char_index;
2316 gint new_char_index;
2318 check_invariants (iter);
2320 current_char_index = gtk_text_iter_get_offset (iter);
2322 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2323 return FALSE; /* can't move forward */
2325 new_char_index = current_char_index + count;
2326 gtk_text_iter_set_offset (iter, new_char_index);
2328 check_invariants (iter);
2330 /* Return FALSE if we're on the non-dereferenceable end
2333 if (gtk_text_iter_is_end (iter))
2341 * gtk_text_iter_backward_chars:
2342 * @iter: an iterator
2343 * @count: number of characters to move
2345 * Moves @count characters backward, if possible (if @count would move
2346 * past the start or end of the buffer, moves to the start or end of
2347 * the buffer). The return value indicates whether the iterator moved
2348 * onto a dereferenceable position; if the iterator didn't move, or
2349 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2350 * the function does nothing and returns %FALSE.
2352 * Return value: whether @iter moved and is dereferenceable
2356 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2358 GtkTextRealIter *real;
2360 g_return_val_if_fail (iter != NULL, FALSE);
2362 FIX_OVERFLOWS (count);
2364 real = gtk_text_iter_make_real (iter);
2368 else if (count == 0)
2371 return gtk_text_iter_forward_chars (iter, 0 - count);
2373 ensure_char_offsets (real);
2374 check_invariants (iter);
2376 /* <, not <=, because if count == segment_char_offset
2377 * we're going to the front of the segment and the any_segment
2380 if (count < real->segment_char_offset)
2382 /* Optimize the within-segment case */
2383 g_assert (real->segment->char_count > 0);
2384 g_assert (real->segment->type == >k_text_char_type);
2386 if (real->line_byte_offset >= 0)
2389 gint new_byte_offset;
2391 /* if in the last fourth of the segment walk backwards */
2392 if (count < real->segment_char_offset / 4)
2393 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2396 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2397 real->segment_char_offset - count);
2399 new_byte_offset = p - real->segment->body.chars;
2400 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2401 real->segment_byte_offset = new_byte_offset;
2404 real->segment_char_offset -= count;
2405 real->line_char_offset -= count;
2407 adjust_char_index (real, 0 - count);
2409 check_invariants (iter);
2415 /* We need to go back into previous segments. For now,
2416 * just keep this really simple. FIXME
2417 * use backward_indexable_segment.
2419 if (TRUE || count > MAX_LINEAR_SCAN)
2421 gint current_char_index;
2422 gint new_char_index;
2424 current_char_index = gtk_text_iter_get_offset (iter);
2426 if (current_char_index == 0)
2427 return FALSE; /* can't move backward */
2429 new_char_index = current_char_index - count;
2430 if (new_char_index < 0)
2433 gtk_text_iter_set_offset (iter, new_char_index);
2435 check_invariants (iter);
2441 /* FIXME backward_indexable_segment here */
2450 /* These two can't be implemented efficiently (always have to use
2451 * a linear scan, since that's the only way to find all the non-text
2456 * gtk_text_iter_forward_text_chars:
2457 * @iter: a #GtkTextIter
2458 * @count: number of chars to move
2460 * Moves forward by @count text characters (pixbufs, widgets,
2461 * etc. do not count as characters for this). Equivalent to moving
2462 * through the results of gtk_text_iter_get_text (), rather than
2463 * gtk_text_iter_get_slice ().
2465 * Return value: whether @iter moved and is dereferenceable
2468 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2477 * gtk_text_iter_forward_text_chars:
2478 * @iter: a #GtkTextIter
2479 * @count: number of chars to move
2481 * Moves backward by @count text characters (pixbufs, widgets,
2482 * etc. do not count as characters for this). Equivalent to moving
2483 * through the results of gtk_text_iter_get_text (), rather than
2484 * gtk_text_iter_get_slice ().
2486 * Return value: whether @iter moved and is dereferenceable
2489 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2498 * gtk_text_iter_forward_line:
2499 * @iter: an iterator
2501 * Moves @iter to the start of the next line. If the iter is already on the
2502 * last line of the buffer, moves the iter to the end of the current line.
2503 * If after the operation, the iter is at the end of the buffer and not
2504 * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
2506 * Return value: whether @iter can be dereferenced
2509 gtk_text_iter_forward_line (GtkTextIter *iter)
2511 GtkTextRealIter *real;
2513 g_return_val_if_fail (iter != NULL, FALSE);
2515 real = gtk_text_iter_make_real (iter);
2520 check_invariants (iter);
2522 if (forward_line_leaving_caches_unmodified (real))
2524 invalidate_char_index (real);
2525 adjust_line_number (real, 1);
2527 check_invariants (iter);
2529 if (gtk_text_iter_is_end (iter))
2536 /* On the last line, move to end of it */
2538 if (!gtk_text_iter_is_end (iter))
2539 gtk_text_iter_forward_to_end (iter);
2541 check_invariants (iter);
2547 * gtk_text_iter_backward_line:
2548 * @iter: an iterator
2550 * Moves @iter to the start of the previous line. Returns %TRUE if
2551 * @iter could be moved; i.e. if @iter was at character offset 0, this
2552 * function returns %FALSE. Therefore if @iter was already on line 0,
2553 * but not at the start of the line, @iter is snapped to the start of
2554 * the line and the function returns %TRUE. (Note that this implies that
2555 * in a loop calling this function, the line number may not change on
2556 * every iteration, if your first iteration is on line 0.)
2558 * Return value: whether @iter moved
2561 gtk_text_iter_backward_line (GtkTextIter *iter)
2563 GtkTextLine *new_line;
2564 GtkTextRealIter *real;
2565 gboolean offset_will_change;
2568 g_return_val_if_fail (iter != NULL, FALSE);
2570 real = gtk_text_iter_make_real (iter);
2575 check_invariants (iter);
2577 new_line = _gtk_text_line_previous (real->line);
2579 offset_will_change = FALSE;
2580 if (real->line_char_offset > 0)
2581 offset_will_change = TRUE;
2583 if (new_line != NULL)
2585 real->line = new_line;
2587 adjust_line_number (real, -1);
2591 if (!offset_will_change)
2595 invalidate_char_index (real);
2597 real->line_byte_offset = 0;
2598 real->line_char_offset = 0;
2600 real->segment_byte_offset = 0;
2601 real->segment_char_offset = 0;
2603 /* Find first segment in line */
2604 real->any_segment = real->line->segments;
2605 real->segment = _gtk_text_line_byte_to_segment (real->line,
2608 g_assert (offset == 0);
2610 /* Note that if we are on the first line, we snap to the start of
2611 * the first line and return TRUE, so TRUE means the iterator
2612 * changed, not that the line changed; this is maybe a bit
2613 * weird. I'm not sure there's an obvious right thing to do though.
2616 check_invariants (iter);
2623 * gtk_text_iter_forward_lines:
2624 * @iter: a #GtkTextIter
2625 * @count: number of lines to move forward
2627 * Moves @count lines forward, if possible (if @count would move
2628 * past the start or end of the buffer, moves to the start or end of
2629 * the buffer). The return value indicates whether the iterator moved
2630 * onto a dereferenceable position; if the iterator didn't move, or
2631 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2632 * the function does nothing and returns %FALSE. If @count is negative,
2633 * moves backward by 0 - @count lines.
2635 * Return value: whether @iter moved and is dereferenceable
2638 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2640 FIX_OVERFLOWS (count);
2643 return gtk_text_iter_backward_lines (iter, 0 - count);
2644 else if (count == 0)
2646 else if (count == 1)
2648 check_invariants (iter);
2649 return gtk_text_iter_forward_line (iter);
2655 if (gtk_text_iter_is_end (iter))
2658 old_line = gtk_text_iter_get_line (iter);
2660 gtk_text_iter_set_line (iter, old_line + count);
2662 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2664 /* count went past the last line, so move to end of last line */
2665 if (!gtk_text_iter_is_end (iter))
2666 gtk_text_iter_forward_to_end (iter);
2669 return !gtk_text_iter_is_end (iter);
2674 * gtk_text_iter_backward_lines:
2675 * @iter: a #GtkTextIter
2676 * @count: number of lines to move backward
2678 * Moves @count lines backward, if possible (if @count would move
2679 * past the start or end of the buffer, moves to the start or end of
2680 * the buffer). The return value indicates whether the iterator moved
2681 * onto a dereferenceable position; if the iterator didn't move, or
2682 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2683 * the function does nothing and returns %FALSE. If @count is negative,
2684 * moves forward by 0 - @count lines.
2686 * Return value: whether @iter moved and is dereferenceable
2689 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2691 FIX_OVERFLOWS (count);
2694 return gtk_text_iter_forward_lines (iter, 0 - count);
2695 else if (count == 0)
2697 else if (count == 1)
2699 return gtk_text_iter_backward_line (iter);
2705 old_line = gtk_text_iter_get_line (iter);
2707 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2709 return (gtk_text_iter_get_line (iter) != old_line);
2714 * gtk_text_iter_forward_visible_line:
2715 * @iter: an iterator
2717 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2718 * was a next line to move to, and %FALSE if @iter was simply moved to
2719 * the end of the buffer and is now not dereferenceable, or if @iter was
2720 * already at the end of the buffer.
2722 * Return value: whether @iter can be dereferenced
2727 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2729 while (gtk_text_iter_forward_line (iter))
2731 if (!_gtk_text_btree_char_is_invisible (iter))
2737 if (!gtk_text_iter_forward_char (iter))
2740 if (!_gtk_text_btree_char_is_invisible (iter))
2743 while (!gtk_text_iter_ends_line (iter));
2751 * gtk_text_iter_backward_visible_line:
2752 * @iter: an iterator
2754 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2755 * @iter could be moved; i.e. if @iter was at character offset 0, this
2756 * function returns %FALSE. Therefore if @iter was already on line 0,
2757 * but not at the start of the line, @iter is snapped to the start of
2758 * the line and the function returns %TRUE. (Note that this implies that
2759 * in a loop calling this function, the line number may not change on
2760 * every iteration, if your first iteration is on line 0.)
2762 * Return value: whether @iter moved
2767 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2769 while (gtk_text_iter_backward_line (iter))
2771 if (!_gtk_text_btree_char_is_invisible (iter))
2777 if (!gtk_text_iter_backward_char (iter))
2780 if (!_gtk_text_btree_char_is_invisible (iter))
2783 while (!gtk_text_iter_starts_line (iter));
2791 * gtk_text_iter_forward_visible_lines:
2792 * @iter: a #GtkTextIter
2793 * @count: number of lines to move forward
2795 * Moves @count visible lines forward, if possible (if @count would move
2796 * past the start or end of the buffer, moves to the start or end of
2797 * the buffer). The return value indicates whether the iterator moved
2798 * onto a dereferenceable position; if the iterator didn't move, or
2799 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2800 * the function does nothing and returns %FALSE. If @count is negative,
2801 * moves backward by 0 - @count lines.
2803 * Return value: whether @iter moved and is dereferenceable
2808 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2811 FIX_OVERFLOWS (count);
2814 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2815 else if (count == 0)
2817 else if (count == 1)
2819 check_invariants (iter);
2820 return gtk_text_iter_forward_visible_line (iter);
2824 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2831 * gtk_text_iter_backward_visible_lines:
2832 * @iter: a #GtkTextIter
2833 * @count: number of lines to move backward
2835 * Moves @count visible lines backward, if possible (if @count would move
2836 * past the start or end of the buffer, moves to the start or end of
2837 * the buffer). The return value indicates whether the iterator moved
2838 * onto a dereferenceable position; if the iterator didn't move, or
2839 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2840 * the function does nothing and returns %FALSE. If @count is negative,
2841 * moves forward by 0 - @count lines.
2843 * Return value: whether @iter moved and is dereferenceable
2848 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2851 FIX_OVERFLOWS (count);
2854 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2855 else if (count == 0)
2857 else if (count == 1)
2859 return gtk_text_iter_backward_visible_line (iter);
2863 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2869 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2874 gboolean already_moved_initially);
2876 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2884 find_word_end_func (const PangoLogAttr *attrs,
2889 gboolean already_moved_initially)
2891 if (!already_moved_initially)
2894 /* Find end of next word */
2895 while (offset < min_offset + len &&
2896 !attrs[offset].is_word_end)
2899 *found_offset = offset;
2901 return offset < min_offset + len;
2905 is_word_end_func (const PangoLogAttr *attrs,
2910 return attrs[offset].is_word_end;
2914 find_word_start_func (const PangoLogAttr *attrs,
2919 gboolean already_moved_initially)
2921 if (!already_moved_initially)
2924 /* Find start of prev word */
2925 while (offset >= min_offset &&
2926 !attrs[offset].is_word_start)
2929 *found_offset = offset;
2931 return offset >= min_offset;
2935 is_word_start_func (const PangoLogAttr *attrs,
2940 return attrs[offset].is_word_start;
2944 inside_word_func (const PangoLogAttr *attrs,
2949 /* Find next word start or end */
2950 while (offset >= min_offset &&
2951 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2955 return attrs[offset].is_word_start;
2960 /* Sentence funcs */
2963 find_sentence_end_func (const PangoLogAttr *attrs,
2968 gboolean already_moved_initially)
2970 if (!already_moved_initially)
2973 /* Find end of next sentence */
2974 while (offset < min_offset + len &&
2975 !attrs[offset].is_sentence_end)
2978 *found_offset = offset;
2980 return offset < min_offset + len;
2984 is_sentence_end_func (const PangoLogAttr *attrs,
2989 return attrs[offset].is_sentence_end;
2993 find_sentence_start_func (const PangoLogAttr *attrs,
2998 gboolean already_moved_initially)
3000 if (!already_moved_initially)
3003 /* Find start of prev sentence */
3004 while (offset >= min_offset &&
3005 !attrs[offset].is_sentence_start)
3008 *found_offset = offset;
3010 return offset >= min_offset;
3014 is_sentence_start_func (const PangoLogAttr *attrs,
3019 return attrs[offset].is_sentence_start;
3023 inside_sentence_func (const PangoLogAttr *attrs,
3028 /* Find next sentence start or end */
3029 while (offset >= min_offset &&
3030 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3033 return attrs[offset].is_sentence_start;
3037 test_log_attrs (const GtkTextIter *iter,
3038 TestLogAttrFunc func)
3041 const PangoLogAttr *attrs;
3043 gboolean result = FALSE;
3045 g_return_val_if_fail (iter != NULL, FALSE);
3047 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3050 offset = gtk_text_iter_get_line_offset (iter);
3052 /* char_len may be 0 and attrs will be NULL if so, if
3053 * iter is the end iter and the last line is empty.
3055 * offset may be equal to char_len, since attrs contains an entry
3056 * for one past the end
3059 if (attrs && offset <= char_len)
3060 result = (* func) (attrs, offset, 0, char_len);
3066 find_line_log_attrs (const GtkTextIter *iter,
3067 FindLogAttrFunc func,
3069 gboolean already_moved_initially)
3072 const PangoLogAttr *attrs;
3074 gboolean result = FALSE;
3076 g_return_val_if_fail (iter != NULL, FALSE);
3078 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3081 offset = gtk_text_iter_get_line_offset (iter);
3083 /* char_len may be 0 and attrs will be NULL if so, if
3084 * iter is the end iter and the last line is empty
3088 result = (* func) (attrs, offset, 0, char_len, found_offset,
3089 already_moved_initially);
3094 /* FIXME this function is very, very gratuitously slow */
3096 find_by_log_attrs (GtkTextIter *iter,
3097 FindLogAttrFunc func,
3099 gboolean already_moved_initially)
3103 gboolean found = FALSE;
3105 g_return_val_if_fail (iter != NULL, FALSE);
3109 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3115 if (gtk_text_iter_forward_line (iter))
3116 return find_by_log_attrs (iter, func, forward,
3123 /* go to end of previous line. need to check that
3124 * line is > 0 because backward_line snaps to start of
3125 * line 0 if it's on line 0
3127 if (gtk_text_iter_get_line (iter) > 0 &&
3128 gtk_text_iter_backward_line (iter))
3130 if (!gtk_text_iter_ends_line (iter))
3131 gtk_text_iter_forward_to_line_end (iter);
3133 return find_by_log_attrs (iter, func, forward,
3142 gtk_text_iter_set_line_offset (iter, offset);
3145 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3146 !gtk_text_iter_is_end (iter);
3151 find_visible_by_log_attrs (GtkTextIter *iter,
3152 FindLogAttrFunc func,
3154 gboolean already_moved_initially)
3158 g_return_val_if_fail (iter != NULL, FALSE);
3162 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3164 if (!_gtk_text_btree_char_is_invisible (&pos))
3174 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3175 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3178 move_multiple_steps (GtkTextIter *iter,
3180 OneStepFunc step_forward,
3181 MultipleStepFunc n_steps_backward)
3183 g_return_val_if_fail (iter != NULL, FALSE);
3185 FIX_OVERFLOWS (count);
3191 return n_steps_backward (iter, -count);
3193 if (!step_forward (iter))
3199 if (!step_forward (iter))
3204 return !gtk_text_iter_is_end (iter);
3209 * gtk_text_iter_forward_word_end:
3210 * @iter: a #GtkTextIter
3212 * Moves forward to the next word end. (If @iter is currently on a
3213 * word end, moves forward to the next one after that.) Word breaks
3214 * are determined by Pango and should be correct for nearly any
3215 * language (if not, the correct fix would be to the Pango word break
3218 * Return value: %TRUE if @iter moved and is not the end iterator
3221 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3223 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3227 * gtk_text_iter_backward_word_start:
3228 * @iter: a #GtkTextIter
3230 * Moves backward to the previous word start. (If @iter is currently on a
3231 * word start, moves backward to the next one after that.) Word breaks
3232 * are determined by Pango and should be correct for nearly any
3233 * language (if not, the correct fix would be to the Pango word break
3236 * Return value: %TRUE if @iter moved and is not the end iterator
3239 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3241 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3244 /* FIXME a loop around a truly slow function means
3245 * a truly spectacularly slow function.
3249 * gtk_text_iter_forward_word_ends:
3250 * @iter: a #GtkTextIter
3251 * @count: number of times to move
3253 * Calls gtk_text_iter_forward_word_end() up to @count times.
3255 * Return value: %TRUE if @iter moved and is not the end iterator
3258 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3261 return move_multiple_steps (iter, count,
3262 gtk_text_iter_forward_word_end,
3263 gtk_text_iter_backward_word_starts);
3267 * gtk_text_iter_backward_word_starts:
3268 * @iter: a #GtkTextIter
3269 * @count: number of times to move
3271 * Calls gtk_text_iter_backward_word_start() up to @count times.
3273 * Return value: %TRUE if @iter moved and is not the end iterator
3276 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3279 return move_multiple_steps (iter, count,
3280 gtk_text_iter_backward_word_start,
3281 gtk_text_iter_forward_word_ends);
3285 * gtk_text_iter_forward_visible_word_end:
3286 * @iter: a #GtkTextIter
3288 * Moves forward to the next visible word end. (If @iter is currently on a
3289 * word end, moves forward to the next one after that.) Word breaks
3290 * are determined by Pango and should be correct for nearly any
3291 * language (if not, the correct fix would be to the Pango word break
3294 * Return value: %TRUE if @iter moved and is not the end iterator
3299 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3301 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3305 * gtk_text_iter_backward_visible_word_start:
3306 * @iter: a #GtkTextIter
3308 * Moves backward to the previous visible word start. (If @iter is currently
3309 * on a word start, moves backward to the next one after that.) Word breaks
3310 * are determined by Pango and should be correct for nearly any
3311 * language (if not, the correct fix would be to the Pango word break
3314 * Return value: %TRUE if @iter moved and is not the end iterator
3319 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3321 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3325 * gtk_text_iter_forward_visible_word_ends:
3326 * @iter: a #GtkTextIter
3327 * @count: number of times to move
3329 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3331 * Return value: %TRUE if @iter moved and is not the end iterator
3336 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3339 return move_multiple_steps (iter, count,
3340 gtk_text_iter_forward_visible_word_end,
3341 gtk_text_iter_backward_visible_word_starts);
3345 * gtk_text_iter_backward_visible_word_starts:
3346 * @iter: a #GtkTextIter
3347 * @count: number of times to move
3349 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3351 * Return value: %TRUE if @iter moved and is not the end iterator
3356 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3359 return move_multiple_steps (iter, count,
3360 gtk_text_iter_backward_visible_word_start,
3361 gtk_text_iter_forward_visible_word_ends);
3365 * gtk_text_iter_starts_word:
3366 * @iter: a #GtkTextIter
3368 * Determines whether @iter begins a natural-language word. Word
3369 * breaks are determined by Pango and should be correct for nearly any
3370 * language (if not, the correct fix would be to the Pango word break
3373 * Return value: %TRUE if @iter is at the start of a word
3376 gtk_text_iter_starts_word (const GtkTextIter *iter)
3378 return test_log_attrs (iter, is_word_start_func);
3382 * gtk_text_iter_ends_word:
3383 * @iter: a #GtkTextIter
3385 * Determines whether @iter ends a natural-language word. Word breaks
3386 * are determined by Pango and should be correct for nearly any
3387 * language (if not, the correct fix would be to the Pango word break
3390 * Return value: %TRUE if @iter is at the end of a word
3393 gtk_text_iter_ends_word (const GtkTextIter *iter)
3395 return test_log_attrs (iter, is_word_end_func);
3399 * gtk_text_iter_inside_word:
3400 * @iter: a #GtkTextIter
3402 * Determines whether @iter is inside a natural-language word (as
3403 * opposed to say inside some whitespace). Word breaks are determined
3404 * by Pango and should be correct for nearly any language (if not, the
3405 * correct fix would be to the Pango word break algorithms).
3407 * Return value: %TRUE if @iter is inside a word
3410 gtk_text_iter_inside_word (const GtkTextIter *iter)
3412 return test_log_attrs (iter, inside_word_func);
3416 * gtk_text_iter_starts_sentence:
3417 * @iter: a #GtkTextIter
3419 * Determines whether @iter begins a sentence. Sentence boundaries are
3420 * determined by Pango and should be correct for nearly any language
3421 * (if not, the correct fix would be to the Pango text boundary
3424 * Return value: %TRUE if @iter is at the start of a sentence.
3427 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3429 return test_log_attrs (iter, is_sentence_start_func);
3433 * gtk_text_iter_ends_sentence:
3434 * @iter: a #GtkTextIter
3436 * Determines whether @iter ends a sentence. Sentence boundaries are
3437 * determined by Pango and should be correct for nearly any language
3438 * (if not, the correct fix would be to the Pango text boundary
3441 * Return value: %TRUE if @iter is at the end of a sentence.
3444 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3446 return test_log_attrs (iter, is_sentence_end_func);
3450 * gtk_text_iter_inside_sentence:
3451 * @iter: a #GtkTextIter
3453 * Determines whether @iter is inside a sentence (as opposed to in
3454 * between two sentences, e.g. after a period and before the first
3455 * letter of the next sentence). Sentence boundaries are determined
3456 * by Pango and should be correct for nearly any language (if not, the
3457 * correct fix would be to the Pango text boundary algorithms).
3459 * Return value: %TRUE if @iter is inside a sentence.
3462 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3464 return test_log_attrs (iter, inside_sentence_func);
3468 * gtk_text_iter_forward_sentence_end:
3469 * @iter: a #GtkTextIter
3471 * Moves forward to the next sentence end. (If @iter is at the end of
3472 * a sentence, moves to the next end of sentence.) Sentence
3473 * boundaries are determined by Pango and should be correct for nearly
3474 * any language (if not, the correct fix would be to the Pango text
3475 * boundary algorithms).
3477 * Return value: %TRUE if @iter moved and is not the end iterator
3480 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3482 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3486 * gtk_text_iter_backward_sentence_start:
3487 * @iter: a #GtkTextIter
3489 * Moves backward to the previous sentence start; if @iter is already at
3490 * the start of a sentence, moves backward to the next one. Sentence
3491 * boundaries are determined by Pango and should be correct for nearly
3492 * any language (if not, the correct fix would be to the Pango text
3493 * boundary algorithms).
3495 * Return value: %TRUE if @iter moved and is not the end iterator
3498 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3500 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3503 /* FIXME a loop around a truly slow function means
3504 * a truly spectacularly slow function.
3507 * gtk_text_iter_forward_sentence_ends:
3508 * @iter: a #GtkTextIter
3509 * @count: number of sentences to move
3511 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3512 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3513 * negative, moves backward instead of forward.
3515 * Return value: %TRUE if @iter moved and is not the end iterator
3518 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3521 return move_multiple_steps (iter, count,
3522 gtk_text_iter_forward_sentence_end,
3523 gtk_text_iter_backward_sentence_starts);
3527 * gtk_text_iter_backward_sentence_starts:
3528 * @iter: a #GtkTextIter
3529 * @count: number of sentences to move
3531 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3532 * or until it returns %FALSE. If @count is negative, moves forward
3533 * instead of backward.
3535 * Return value: %TRUE if @iter moved and is not the end iterator
3538 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3541 return move_multiple_steps (iter, count,
3542 gtk_text_iter_backward_sentence_start,
3543 gtk_text_iter_forward_sentence_ends);
3547 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3552 gboolean already_moved_initially)
3554 if (!already_moved_initially)
3557 while (offset < (min_offset + len) &&
3558 !attrs[offset].is_cursor_position)
3561 *found_offset = offset;
3563 return offset < (min_offset + len);
3567 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3572 gboolean already_moved_initially)
3574 if (!already_moved_initially)
3577 while (offset > min_offset &&
3578 !attrs[offset].is_cursor_position)
3581 *found_offset = offset;
3583 return offset >= min_offset;
3587 is_cursor_pos_func (const PangoLogAttr *attrs,
3592 return attrs[offset].is_cursor_position;
3596 * gtk_text_iter_forward_cursor_position:
3597 * @iter: a #GtkTextIter
3599 * Moves @iter forward by a single cursor position. Cursor positions
3600 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3601 * surprisingly, there may not be a cursor position between all
3602 * characters. The most common example for European languages would be
3603 * a carriage return/newline sequence. For some Unicode characters,
3604 * the equivalent of say the letter "a" with an accent mark will be
3605 * represented as two characters, first the letter then a "combining
3606 * mark" that causes the accent to be rendered; so the cursor can't go
3607 * between those two characters. See also the #PangoLogAttr structure and
3608 * pango_break() function.
3610 * Return value: %TRUE if we moved and the new position is dereferenceable
3613 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3615 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3619 * gtk_text_iter_backward_cursor_position:
3620 * @iter: a #GtkTextIter
3622 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3624 * Return value: %TRUE if we moved
3627 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3629 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3633 * gtk_text_iter_forward_cursor_positions:
3634 * @iter: a #GtkTextIter
3635 * @count: number of positions to move
3637 * Moves up to @count cursor positions. See
3638 * gtk_text_iter_forward_cursor_position() for details.
3640 * Return value: %TRUE if we moved and the new position is dereferenceable
3643 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3646 return move_multiple_steps (iter, count,
3647 gtk_text_iter_forward_cursor_position,
3648 gtk_text_iter_backward_cursor_positions);
3652 * gtk_text_iter_backward_cursor_positions:
3653 * @iter: a #GtkTextIter
3654 * @count: number of positions to move
3656 * Moves up to @count cursor positions. See
3657 * gtk_text_iter_forward_cursor_position() for details.
3659 * Return value: %TRUE if we moved and the new position is dereferenceable
3662 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3665 return move_multiple_steps (iter, count,
3666 gtk_text_iter_backward_cursor_position,
3667 gtk_text_iter_forward_cursor_positions);
3671 * gtk_text_iter_forward_visible_cursor_position:
3672 * @iter: a #GtkTextIter
3674 * Moves @iter forward to the next visible cursor position. See
3675 * gtk_text_iter_forward_cursor_position() for details.
3677 * Return value: %TRUE if we moved and the new position is dereferenceable
3682 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3684 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3688 * gtk_text_iter_backward_visible_cursor_position:
3689 * @iter: a #GtkTextIter
3691 * Moves @iter forward to the previous visible cursor position. See
3692 * gtk_text_iter_backward_cursor_position() for details.
3694 * Return value: %TRUE if we moved and the new position is dereferenceable
3699 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3701 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3705 * gtk_text_iter_forward_visible_cursor_positions:
3706 * @iter: a #GtkTextIter
3707 * @count: number of positions to move
3709 * Moves up to @count visible cursor positions. See
3710 * gtk_text_iter_forward_cursor_position() for details.
3712 * Return value: %TRUE if we moved and the new position is dereferenceable
3717 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3720 return move_multiple_steps (iter, count,
3721 gtk_text_iter_forward_visible_cursor_position,
3722 gtk_text_iter_backward_visible_cursor_positions);
3726 * gtk_text_iter_backward_visible_cursor_positions:
3727 * @iter: a #GtkTextIter
3728 * @count: number of positions to move
3730 * Moves up to @count visible cursor positions. See
3731 * gtk_text_iter_backward_cursor_position() for details.
3733 * Return value: %TRUE if we moved and the new position is dereferenceable
3738 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3741 return move_multiple_steps (iter, count,
3742 gtk_text_iter_backward_visible_cursor_position,
3743 gtk_text_iter_forward_visible_cursor_positions);
3747 * gtk_text_iter_is_cursor_position:
3748 * @iter: a #GtkTextIter
3750 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3751 * pango_break() for details on what a cursor position is.
3753 * Return value: %TRUE if the cursor can be placed at @iter
3756 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3758 return test_log_attrs (iter, is_cursor_pos_func);
3762 * gtk_text_iter_set_line_offset:
3763 * @iter: a #GtkTextIter
3764 * @char_on_line: a character offset relative to the start of @iter's current line
3766 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3767 * (not byte) offset. The given character offset must be less than or
3768 * equal to the number of characters in the line; if equal, @iter
3769 * moves to the start of the next line. See
3770 * gtk_text_iter_set_line_index() if you have a byte index rather than
3771 * a character offset.
3775 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3778 GtkTextRealIter *real;
3781 g_return_if_fail (iter != NULL);
3783 real = gtk_text_iter_make_surreal (iter);
3788 check_invariants (iter);
3790 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3792 g_return_if_fail (char_on_line <= chars_in_line);
3794 if (char_on_line < chars_in_line)
3795 iter_set_from_char_offset (real, real->line, char_on_line);
3797 gtk_text_iter_forward_line (iter); /* set to start of next line */
3799 check_invariants (iter);
3803 * gtk_text_iter_set_line_index:
3804 * @iter: a #GtkTextIter
3805 * @byte_on_line: a byte index relative to the start of @iter's current line
3807 * Same as gtk_text_iter_set_line_offset(), but works with a
3808 * <emphasis>byte</emphasis> index. The given byte index must be at
3809 * the start of a character, it can't be in the middle of a UTF-8
3810 * encoded character.
3814 gtk_text_iter_set_line_index (GtkTextIter *iter,
3817 GtkTextRealIter *real;
3820 g_return_if_fail (iter != NULL);
3822 real = gtk_text_iter_make_surreal (iter);
3827 check_invariants (iter);
3829 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3831 g_return_if_fail (byte_on_line <= bytes_in_line);
3833 if (byte_on_line < bytes_in_line)
3834 iter_set_from_byte_offset (real, real->line, byte_on_line);
3836 gtk_text_iter_forward_line (iter);
3838 if (real->segment->type == >k_text_char_type &&
3839 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3840 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3841 "character; this will crash the text buffer. "
3842 "Byte indexes must refer to the start of a character.",
3843 G_STRLOC, byte_on_line);
3845 check_invariants (iter);
3850 * gtk_text_iter_set_visible_line_offset:
3851 * @iter: a #GtkTextIter
3852 * @char_on_line: a character offset
3854 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3855 * characters, i.e. text with a tag making it invisible is not
3856 * counted in the offset.
3859 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3862 gint chars_seen = 0;
3865 g_return_if_fail (iter != NULL);
3867 gtk_text_iter_set_line_offset (iter, 0);
3871 /* For now we use a ludicrously slow implementation */
3872 while (chars_seen < char_on_line)
3874 if (!_gtk_text_btree_char_is_invisible (&pos))
3877 if (!gtk_text_iter_forward_char (&pos))
3880 if (chars_seen == char_on_line)
3884 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3887 gtk_text_iter_forward_line (iter);
3891 * gtk_text_iter_set_visible_line_index:
3892 * @iter: a #GtkTextIter
3893 * @byte_on_line: a byte index
3895 * Like gtk_text_iter_set_line_index(), but the index is in visible
3896 * bytes, i.e. text with a tag making it invisible is not counted
3900 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3903 GtkTextRealIter *real;
3906 GtkTextLineSegment *seg;
3908 g_return_if_fail (iter != NULL);
3910 gtk_text_iter_set_line_offset (iter, 0);
3914 real = gtk_text_iter_make_real (&pos);
3919 ensure_byte_offsets (real);
3921 check_invariants (&pos);
3923 seg = _gtk_text_iter_get_indexable_segment (&pos);
3925 while (seg != NULL && byte_on_line > 0)
3927 if (!_gtk_text_btree_char_is_invisible (&pos))
3929 if (byte_on_line < seg->byte_count)
3931 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3936 byte_on_line -= seg->byte_count;
3939 offset += seg->byte_count;
3940 _gtk_text_iter_forward_indexable_segment (&pos);
3941 seg = _gtk_text_iter_get_indexable_segment (&pos);
3944 if (byte_on_line == 0)
3947 gtk_text_iter_forward_line (iter);
3951 * gtk_text_iter_set_line:
3952 * @iter: a #GtkTextIter
3953 * @line_number: line number (counted from 0)
3955 * Moves iterator @iter to the start of the line @line_number. If
3956 * @line_number is negative or larger than the number of lines in the
3957 * buffer, moves @iter to the start of the last line in the buffer.
3961 gtk_text_iter_set_line (GtkTextIter *iter,
3966 GtkTextRealIter *real;
3968 g_return_if_fail (iter != NULL);
3970 real = gtk_text_iter_make_surreal (iter);
3975 check_invariants (iter);
3977 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3979 iter_set_from_char_offset (real, line, 0);
3981 /* We might as well cache this, since we know it. */
3982 real->cached_line_number = real_line;
3984 check_invariants (iter);
3988 * gtk_text_iter_set_offset:
3989 * @iter: a #GtkTextIter
3990 * @char_offset: a character number
3992 * Sets @iter to point to @char_offset. @char_offset counts from the start
3993 * of the entire text buffer, starting with 0.
3996 gtk_text_iter_set_offset (GtkTextIter *iter,
4000 GtkTextRealIter *real;
4002 gint real_char_index;
4004 g_return_if_fail (iter != NULL);
4006 real = gtk_text_iter_make_surreal (iter);
4011 check_invariants (iter);
4013 if (real->cached_char_index >= 0 &&
4014 real->cached_char_index == char_offset)
4017 line = _gtk_text_btree_get_line_at_char (real->tree,
4022 iter_set_from_char_offset (real, line, real_char_index - line_start);
4024 /* Go ahead and cache this since we have it. */
4025 real->cached_char_index = real_char_index;
4027 check_invariants (iter);
4031 * gtk_text_iter_forward_to_end:
4032 * @iter: a #GtkTextIter
4034 * Moves @iter forward to the "end iterator," which points one past the last
4035 * valid character in the buffer. gtk_text_iter_get_char() called on the
4036 * end iterator returns 0, which is convenient for writing loops.
4039 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4041 GtkTextBuffer *buffer;
4042 GtkTextRealIter *real;
4044 g_return_if_fail (iter != NULL);
4046 real = gtk_text_iter_make_surreal (iter);
4051 buffer = _gtk_text_btree_get_buffer (real->tree);
4053 gtk_text_buffer_get_end_iter (buffer, iter);
4056 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4057 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4058 * If all else fails we could cache the para delimiter pos in the iter.
4059 * I think forward_to_line_end() actually gets called fairly often.
4062 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4067 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4068 _gtk_text_iter_get_btree (&end)))
4070 gtk_text_iter_forward_to_end (&end);
4074 /* if we aren't on the last line, go forward to start of next line, then scan
4075 * back for the delimiters on the previous line
4077 gtk_text_iter_forward_line (&end);
4078 gtk_text_iter_backward_char (&end);
4079 while (!gtk_text_iter_ends_line (&end))
4080 gtk_text_iter_backward_char (&end);
4083 return gtk_text_iter_get_line_offset (&end);
4087 * gtk_text_iter_forward_to_line_end:
4088 * @iter: a #GtkTextIter
4090 * Moves the iterator to point to the paragraph delimiter characters,
4091 * which will be either a newline, a carriage return, a carriage
4092 * return/newline in sequence, or the Unicode paragraph separator
4093 * character. If the iterator is already at the paragraph delimiter
4094 * characters, moves to the paragraph delimiter characters for the
4095 * next line. If @iter is on the last line in the buffer, which does
4096 * not end in paragraph delimiters, moves to the end iterator (end of
4097 * the last line), and returns %FALSE.
4099 * Return value: %TRUE if we moved and the new location is not the end iterator
4102 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4104 gint current_offset;
4108 g_return_val_if_fail (iter != NULL, FALSE);
4110 current_offset = gtk_text_iter_get_line_offset (iter);
4111 new_offset = find_paragraph_delimiter_for_line (iter);
4113 if (current_offset < new_offset)
4115 /* Move to end of this line. */
4116 gtk_text_iter_set_line_offset (iter, new_offset);
4117 return !gtk_text_iter_is_end (iter);
4121 /* Move to end of next line. */
4122 if (gtk_text_iter_forward_line (iter))
4124 /* We don't want to move past all
4127 if (!gtk_text_iter_ends_line (iter))
4128 gtk_text_iter_forward_to_line_end (iter);
4129 return !gtk_text_iter_is_end (iter);
4137 * gtk_text_iter_forward_to_tag_toggle:
4138 * @iter: a #GtkTextIter
4139 * @tag: (allow-none): a #GtkTextTag, or %NULL
4141 * Moves forward to the next toggle (on or off) of the
4142 * #GtkTextTag @tag, or to the next toggle of any tag if
4143 * @tag is %NULL. If no matching tag toggles are found,
4144 * returns %FALSE, otherwise %TRUE. Does not return toggles
4145 * located at @iter, only toggles after @iter. Sets @iter to
4146 * the location of the toggle, or to the end of the buffer
4147 * if no toggle is found.
4149 * Return value: whether we found a tag toggle after @iter
4152 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4155 GtkTextLine *next_line;
4156 GtkTextLine *current_line;
4157 GtkTextRealIter *real;
4159 g_return_val_if_fail (iter != NULL, FALSE);
4161 real = gtk_text_iter_make_real (iter);
4166 check_invariants (iter);
4168 current_line = real->line;
4169 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4172 while (_gtk_text_iter_forward_indexable_segment (iter))
4174 /* If we went forward to a line that couldn't contain a toggle
4175 for the tag, then skip forward to a line that could contain
4176 it. This potentially skips huge hunks of the tree, so we
4177 aren't a purely linear search. */
4178 if (real->line != current_line)
4180 if (next_line == NULL)
4182 /* End of search. Set to end of buffer. */
4183 _gtk_text_btree_get_end_iter (real->tree, iter);
4187 if (real->line != next_line)
4188 iter_set_from_byte_offset (real, next_line, 0);
4190 current_line = real->line;
4191 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4196 if (gtk_text_iter_toggles_tag (iter, tag))
4198 /* If there's a toggle here, it isn't indexable so
4199 any_segment can't be the indexable segment. */
4200 g_assert (real->any_segment != real->segment);
4205 /* Check end iterator for tags */
4206 if (gtk_text_iter_toggles_tag (iter, tag))
4208 /* If there's a toggle here, it isn't indexable so
4209 any_segment can't be the indexable segment. */
4210 g_assert (real->any_segment != real->segment);
4214 /* Reached end of buffer */
4219 * gtk_text_iter_backward_to_tag_toggle:
4220 * @iter: a #GtkTextIter
4221 * @tag: (allow-none): a #GtkTextTag, or %NULL
4223 * Moves backward to the next toggle (on or off) of the
4224 * #GtkTextTag @tag, or to the next toggle of any tag if
4225 * @tag is %NULL. If no matching tag toggles are found,
4226 * returns %FALSE, otherwise %TRUE. Does not return toggles
4227 * located at @iter, only toggles before @iter. Sets @iter
4228 * to the location of the toggle, or the start of the buffer
4229 * if no toggle is found.
4231 * Return value: whether we found a tag toggle before @iter
4234 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4237 GtkTextLine *prev_line;
4238 GtkTextLine *current_line;
4239 GtkTextRealIter *real;
4241 g_return_val_if_fail (iter != NULL, FALSE);
4243 real = gtk_text_iter_make_real (iter);
4248 check_invariants (iter);
4250 current_line = real->line;
4251 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4255 /* If we're at segment start, go to the previous segment;
4256 * if mid-segment, snap to start of current segment.
4258 if (is_segment_start (real))
4260 if (!_gtk_text_iter_backward_indexable_segment (iter))
4265 ensure_char_offsets (real);
4267 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4273 /* If we went backward to a line that couldn't contain a toggle
4274 * for the tag, then skip backward further to a line that
4275 * could contain it. This potentially skips huge hunks of the
4276 * tree, so we aren't a purely linear search.
4278 if (real->line != current_line)
4280 if (prev_line == NULL)
4282 /* End of search. Set to start of buffer. */
4283 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4287 if (real->line != prev_line)
4289 /* Set to last segment in prev_line (could do this
4292 iter_set_from_byte_offset (real, prev_line, 0);
4294 while (!at_last_indexable_segment (real))
4295 _gtk_text_iter_forward_indexable_segment (iter);
4298 current_line = real->line;
4299 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4304 if (gtk_text_iter_toggles_tag (iter, tag))
4306 /* If there's a toggle here, it isn't indexable so
4307 * any_segment can't be the indexable segment.
4309 g_assert (real->any_segment != real->segment);
4313 while (_gtk_text_iter_backward_indexable_segment (iter));
4315 /* Reached front of buffer */
4320 matches_pred (GtkTextIter *iter,
4321 GtkTextCharPredicate pred,
4326 ch = gtk_text_iter_get_char (iter);
4328 return (*pred) (ch, user_data);
4332 * gtk_text_iter_forward_find_char:
4333 * @iter: a #GtkTextIter
4334 * @pred: (scope call): a function to be called on each character
4335 * @user_data: user data for @pred
4336 * @limit: (allow-none): search limit, or %NULL for none
4338 * Advances @iter, calling @pred on each character. If
4339 * @pred returns %TRUE, returns %TRUE and stops scanning.
4340 * If @pred never returns %TRUE, @iter is set to @limit if
4341 * @limit is non-%NULL, otherwise to the end iterator.
4343 * Return value: whether a match was found
4346 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4347 GtkTextCharPredicate pred,
4349 const GtkTextIter *limit)
4351 g_return_val_if_fail (iter != NULL, FALSE);
4352 g_return_val_if_fail (pred != NULL, FALSE);
4355 gtk_text_iter_compare (iter, limit) >= 0)
4358 while ((limit == NULL ||
4359 !gtk_text_iter_equal (limit, iter)) &&
4360 gtk_text_iter_forward_char (iter))
4362 if (matches_pred (iter, pred, user_data))
4370 * gtk_text_iter_backward_find_char:
4371 * @iter: a #GtkTextIter
4372 * @pred: (scope call): function to be called on each character
4373 * @user_data: user data for @pred
4374 * @limit: (allow-none): search limit, or %NULL for none
4376 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4378 * Return value: whether a match was found
4381 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4382 GtkTextCharPredicate pred,
4384 const GtkTextIter *limit)
4386 g_return_val_if_fail (iter != NULL, FALSE);
4387 g_return_val_if_fail (pred != NULL, FALSE);
4390 gtk_text_iter_compare (iter, limit) <= 0)
4393 while ((limit == NULL ||
4394 !gtk_text_iter_equal (limit, iter)) &&
4395 gtk_text_iter_backward_char (iter))
4397 if (matches_pred (iter, pred, user_data))
4405 forward_chars_with_skipping (GtkTextIter *iter,
4407 gboolean skip_invisible,
4408 gboolean skip_nontext,
4409 gboolean skip_decomp)
4414 g_return_if_fail (count >= 0);
4420 gboolean ignored = FALSE;
4422 /* minimal workaround to avoid the infinite loop of bug #168247. */
4423 if (gtk_text_iter_is_end (iter))
4427 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4432 _gtk_text_btree_char_is_invisible (iter))
4435 if (!ignored && skip_decomp)
4437 /* being UTF8 correct sucks: this accounts for extra
4438 offsets coming from canonical decompositions of
4439 UTF8 characters (e.g. accented characters) which
4440 g_utf8_normalize() performs */
4446 buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
4447 casefold = g_utf8_casefold (buffer, buffer_len);
4448 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4449 i -= (g_utf8_strlen (normal, -1) - 1);
4454 gtk_text_iter_forward_char (iter);
4461 static const gchar *
4462 pointer_from_offset_skipping_decomp (const gchar *str,
4465 gchar *casefold, *normal;
4472 q = g_utf8_next_char (p);
4473 casefold = g_utf8_casefold (p, q - p);
4474 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4475 offset -= g_utf8_strlen (normal, -1);
4485 exact_prefix_cmp (const gchar *string,
4486 const gchar *prefix,
4491 if (strncmp (string, prefix, prefix_len) != 0)
4493 if (string[prefix_len] == '\0')
4496 type = g_unichar_type (g_utf8_get_char (string + prefix_len));
4498 /* If string contains prefix, check that prefix is not followed
4499 * by a unicode mark symbol, e.g. that trailing 'a' in prefix
4500 * is not part of two-char a-with-hat symbol in string. */
4501 return type != G_UNICODE_SPACING_MARK &&
4502 type != G_UNICODE_ENCLOSING_MARK &&
4503 type != G_UNICODE_NON_SPACING_MARK;
4506 static const gchar *
4507 utf8_strcasestr (const gchar *haystack,
4508 const gchar *needle)
4512 const gchar *ret = NULL;
4515 gchar *caseless_haystack;
4518 g_return_val_if_fail (haystack != NULL, NULL);
4519 g_return_val_if_fail (needle != NULL, NULL);
4521 casefold = g_utf8_casefold (haystack, -1);
4522 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4525 needle_len = g_utf8_strlen (needle, -1);
4526 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4528 if (needle_len == 0)
4530 ret = (gchar *)haystack;
4534 if (haystack_len < needle_len)
4540 p = (gchar *)caseless_haystack;
4541 needle_len = strlen (needle);
4546 if (exact_prefix_cmp (p, needle, needle_len))
4548 ret = pointer_from_offset_skipping_decomp (haystack, i);
4552 p = g_utf8_next_char (p);
4557 g_free (caseless_haystack);
4562 static const gchar *
4563 utf8_strrcasestr (const gchar *haystack,
4564 const gchar *needle)
4568 const gchar *ret = NULL;
4571 gchar *caseless_haystack;
4574 g_return_val_if_fail (haystack != NULL, NULL);
4575 g_return_val_if_fail (needle != NULL, NULL);
4577 casefold = g_utf8_casefold (haystack, -1);
4578 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4581 needle_len = g_utf8_strlen (needle, -1);
4582 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4584 if (needle_len == 0)
4586 ret = (gchar *)haystack;
4590 if (haystack_len < needle_len)
4596 i = haystack_len - needle_len;
4597 p = g_utf8_offset_to_pointer (caseless_haystack, i);
4598 needle_len = strlen (needle);
4600 while (p >= caseless_haystack)
4602 if (exact_prefix_cmp (p, needle, needle_len))
4604 ret = pointer_from_offset_skipping_decomp (haystack, i);
4608 p = g_utf8_prev_char (p);
4613 g_free (caseless_haystack);
4618 /* normalizes caseless strings and returns true if @s2 matches
4621 utf8_caselessnmatch (const gchar *s1,
4627 gchar *normalized_s1;
4628 gchar *normalized_s2;
4631 gboolean ret = FALSE;
4633 g_return_val_if_fail (s1 != NULL, FALSE);
4634 g_return_val_if_fail (s2 != NULL, FALSE);
4635 g_return_val_if_fail (n1 > 0, FALSE);
4636 g_return_val_if_fail (n2 > 0, FALSE);
4638 casefold = g_utf8_casefold (s1, n1);
4639 normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4642 casefold = g_utf8_casefold (s2, n2);
4643 normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4646 len_s1 = strlen (normalized_s1);
4647 len_s2 = strlen (normalized_s2);
4649 if (len_s1 >= len_s2)
4650 ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
4652 g_free (normalized_s1);
4653 g_free (normalized_s2);
4659 lines_match (const GtkTextIter *start,
4660 const gchar **lines,
4661 gboolean visible_only,
4663 gboolean case_insensitive,
4664 GtkTextIter *match_start,
4665 GtkTextIter *match_end)
4672 if (*lines == NULL || **lines == '\0')
4675 *match_start = *start;
4678 *match_end = *start;
4683 gtk_text_iter_forward_line (&next);
4685 /* No more text in buffer, but *lines is nonempty */
4686 if (gtk_text_iter_equal (start, &next))
4694 line_text = gtk_text_iter_get_visible_slice (start, &next);
4696 line_text = gtk_text_iter_get_slice (start, &next);
4701 line_text = gtk_text_iter_get_visible_text (start, &next);
4703 line_text = gtk_text_iter_get_text (start, &next);
4706 if (match_start) /* if this is the first line we're matching */
4708 if (!case_insensitive)
4709 found = strstr (line_text, *lines);
4711 found = utf8_strcasestr (line_text, *lines);
4715 /* If it's not the first line, we have to match from the
4716 * start of the line.
4718 if ((!case_insensitive &&
4719 (strncmp (line_text, *lines, strlen (*lines)) == 0)) ||
4720 (case_insensitive &&
4721 utf8_caselessnmatch (line_text, *lines, strlen (line_text),
4736 /* Get offset to start of search string */
4737 offset = g_utf8_strlen (line_text, found - line_text);
4741 /* If match start needs to be returned, set it to the
4742 * start of the search string.
4744 forward_chars_with_skipping (&next, offset,
4745 visible_only, !slice, FALSE);
4747 *match_start = next;
4749 /* Go to end of search string */
4750 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1),
4751 visible_only, !slice, TRUE);
4760 /* pass NULL for match_start, since we don't need to find the
4763 return lines_match (&next, lines, visible_only, slice, case_insensitive, NULL, match_end);
4766 /* strsplit () that retains the delimiter as part of the string. */
4768 strbreakup (const char *string,
4769 const char *delimiter,
4772 gboolean case_insensitive)
4774 GSList *string_list = NULL, *slist;
4775 gchar **str_array, *s;
4776 gchar *casefold, *new_string;
4779 g_return_val_if_fail (string != NULL, NULL);
4780 g_return_val_if_fail (delimiter != NULL, NULL);
4783 max_tokens = G_MAXINT;
4785 s = strstr (string, delimiter);
4788 guint delimiter_len = strlen (delimiter);
4794 len = s - string + delimiter_len;
4795 new_string = g_new (gchar, len + 1);
4796 strncpy (new_string, string, len);
4797 new_string[len] = 0;
4799 if (case_insensitive)
4801 casefold = g_utf8_casefold (new_string, -1);
4802 g_free (new_string);
4803 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4807 string_list = g_slist_prepend (string_list, new_string);
4809 string = s + delimiter_len;
4810 s = strstr (string, delimiter);
4812 while (--max_tokens && s);
4818 if (case_insensitive)
4820 casefold = g_utf8_casefold (string, -1);
4821 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4825 new_string = g_strdup (string);
4827 string_list = g_slist_prepend (string_list, new_string);
4830 str_array = g_new (gchar*, n);
4834 str_array[i--] = NULL;
4835 for (slist = string_list; slist; slist = slist->next)
4836 str_array[i--] = slist->data;
4838 g_slist_free (string_list);
4840 if (num_strings != NULL)
4841 *num_strings = n - 1;
4847 * gtk_text_iter_forward_search:
4848 * @iter: start of search
4849 * @str: a search string
4850 * @flags: flags affecting how the search is done
4851 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
4852 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
4853 * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
4855 * Searches forward for @str. Any match is returned by setting
4856 * @match_start to the first character of the match and @match_end to the
4857 * first character after the match. The search will not continue past
4858 * @limit. Note that a search is a linear or O(n) operation, so you
4859 * may wish to use @limit to avoid locking up your UI on large
4862 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4863 * have invisible text interspersed in @str. i.e. @str will be a
4864 * possibly-noncontiguous subsequence of the matched range. similarly,
4865 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4866 * pixbufs or child widgets mixed inside the matched range. If these
4867 * flags are not given, the match must be exact; the special 0xFFFC
4868 * character in @str will match embedded pixbufs or child widgets.
4869 * If you specify the #GTK_TEXT_SEARCH_CASE_INSENSITIVE flag, the text will
4870 * be matched regardless of what case it is in.
4872 * Return value: whether a match was found
4875 gtk_text_iter_forward_search (const GtkTextIter *iter,
4877 GtkTextSearchFlags flags,
4878 GtkTextIter *match_start,
4879 GtkTextIter *match_end,
4880 const GtkTextIter *limit)
4882 gchar **lines = NULL;
4884 gboolean retval = FALSE;
4886 gboolean visible_only;
4888 gboolean case_insensitive;
4890 g_return_val_if_fail (iter != NULL, FALSE);
4891 g_return_val_if_fail (str != NULL, FALSE);
4894 gtk_text_iter_compare (iter, limit) >= 0)
4899 /* If we can move one char, return the empty string there */
4902 if (gtk_text_iter_forward_char (&match))
4905 gtk_text_iter_equal (&match, limit))
4909 *match_start = match;
4918 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4919 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4920 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
4922 /* locate all lines */
4924 lines = strbreakup (str, "\n", -1, NULL, case_insensitive);
4930 /* This loop has an inefficient worst-case, where
4931 * gtk_text_iter_get_text () is called repeatedly on
4937 gtk_text_iter_compare (&search, limit) >= 0)
4940 if (lines_match (&search, (const gchar**)lines,
4941 visible_only, slice, case_insensitive, &match, &end))
4943 if (limit == NULL ||
4945 gtk_text_iter_compare (&end, limit) <= 0))
4950 *match_start = match;
4959 while (gtk_text_iter_forward_line (&search));
4961 g_strfreev ((gchar**)lines);
4967 vectors_equal_ignoring_trailing (gchar **vec1,
4969 gboolean case_insensitive)
4971 /* Ignores trailing chars in vec2's last line */
4983 if (!case_insensitive)
4985 if (strcmp (*i1, *i2) != 0)
4987 if (*(i2 + 1) == NULL) /* if this is the last line */
4989 len1 = strlen (*i1);
4990 len2 = strlen (*i2);
4993 strncmp (*i1, *i2, len1) == 0)
4995 /* We matched ignoring the trailing stuff in vec2 */
5011 len1 = strlen (*i1);
5012 len2 = strlen (*i2);
5014 if (!utf8_caselessnmatch (*i1, *i2, len1, len2))
5016 if (*(i2 + 1) == NULL) /* if this is the last line */
5018 if (utf8_caselessnmatch (*i2, *i1, len2, len1))
5020 /* We matched ignoring the trailing stuff in vec2 */
5045 typedef struct _LinesWindow LinesWindow;
5052 GtkTextIter first_line_start;
5053 GtkTextIter first_line_end;
5056 guint visible_only : 1;
5060 lines_window_init (LinesWindow *win,
5061 const GtkTextIter *start)
5064 GtkTextIter line_start;
5065 GtkTextIter line_end;
5067 /* If we start on line 1, there are 2 lines to search (0 and 1), so
5070 if (gtk_text_iter_is_start (start) ||
5071 gtk_text_iter_get_line (start) + 1 < win->n_lines)
5073 /* Already at the end, or not enough lines to match */
5074 win->lines = g_new0 (gchar*, 1);
5079 line_start = *start;
5082 /* Move to start iter to start of line */
5083 gtk_text_iter_set_line_offset (&line_start, 0);
5085 if (gtk_text_iter_equal (&line_start, &line_end))
5087 /* we were already at the start; so go back one line */
5088 gtk_text_iter_backward_line (&line_start);
5091 win->first_line_start = line_start;
5092 win->first_line_end = line_end;
5094 win->lines = g_new0 (gchar*, win->n_lines + 1);
5096 i = win->n_lines - 1;
5103 if (win->visible_only)
5104 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
5106 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
5110 if (win->visible_only)
5111 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
5113 line_text = gtk_text_iter_get_text (&line_start, &line_end);
5116 win->lines[i] = line_text;
5117 win->first_line_start = line_start;
5118 win->first_line_end = line_end;
5120 line_end = line_start;
5121 gtk_text_iter_backward_line (&line_start);
5128 lines_window_back (LinesWindow *win)
5130 GtkTextIter new_start;
5133 new_start = win->first_line_start;
5135 if (!gtk_text_iter_backward_line (&new_start))
5139 win->first_line_start = new_start;
5140 win->first_line_end = new_start;
5142 gtk_text_iter_forward_line (&win->first_line_end);
5147 if (win->visible_only)
5148 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
5149 &win->first_line_end);
5151 line_text = gtk_text_iter_get_slice (&win->first_line_start,
5152 &win->first_line_end);
5156 if (win->visible_only)
5157 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
5158 &win->first_line_end);
5160 line_text = gtk_text_iter_get_text (&win->first_line_start,
5161 &win->first_line_end);
5164 /* Move lines to make room for first line. */
5165 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
5167 *win->lines = line_text;
5169 /* Free old last line and NULL-terminate */
5170 g_free (win->lines[win->n_lines]);
5171 win->lines[win->n_lines] = NULL;
5177 lines_window_free (LinesWindow *win)
5179 g_strfreev (win->lines);
5183 * gtk_text_iter_backward_search:
5184 * @iter: a #GtkTextIter where the search begins
5185 * @str: search string
5186 * @flags: bitmask of flags affecting the search
5187 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
5188 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
5189 * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
5191 * Same as gtk_text_iter_forward_search(), but moves backward.
5193 * Return value: whether a match was found
5196 gtk_text_iter_backward_search (const GtkTextIter *iter,
5198 GtkTextSearchFlags flags,
5199 GtkTextIter *match_start,
5200 GtkTextIter *match_end,
5201 const GtkTextIter *limit)
5203 gchar **lines = NULL;
5207 gboolean retval = FALSE;
5208 gboolean visible_only;
5210 gboolean case_insensitive;
5212 g_return_val_if_fail (iter != NULL, FALSE);
5213 g_return_val_if_fail (str != NULL, FALSE);
5216 gtk_text_iter_compare (limit, iter) > 0)
5221 /* If we can move one char, return the empty string there */
5222 GtkTextIter match = *iter;
5224 if (limit && gtk_text_iter_equal (limit, &match))
5227 if (gtk_text_iter_backward_char (&match))
5230 *match_start = match;
5239 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
5240 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
5241 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
5243 /* locate all lines */
5245 lines = strbreakup (str, "\n", -1, &n_lines, case_insensitive);
5247 win.n_lines = n_lines;
5249 win.visible_only = visible_only;
5251 lines_window_init (&win, iter);
5253 if (*win.lines == NULL)
5258 const gchar *first_line_match;
5261 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
5263 /* We're now before the search limit, abort. */
5267 /* If there are multiple lines, the first line will
5268 * end in '\n', so this will only match at the
5269 * end of the first line, which is correct.
5271 if (!case_insensitive)
5272 first_line_match = g_strrstr (*win.lines, *lines);
5274 first_line_match = utf8_strrcasestr (*win.lines, *lines);
5276 if (first_line_match &&
5277 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1,
5283 GtkTextIter start_tmp;
5285 /* Offset to start of search string */
5286 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5288 next = win.first_line_start;
5290 forward_chars_with_skipping (&start_tmp, offset,
5291 visible_only, !slice, FALSE);
5294 gtk_text_iter_compare (limit, &start_tmp) > 0)
5295 goto out; /* match was bogus */
5298 *match_start = start_tmp;
5300 /* Go to end of search string */
5304 offset += g_utf8_strlen (*l, -1);
5308 forward_chars_with_skipping (&next, offset,
5309 visible_only, !slice, TRUE);
5318 while (lines_window_back (&win));
5321 lines_window_free (&win);
5332 * gtk_text_iter_equal:
5333 * @lhs: a #GtkTextIter
5334 * @rhs: another #GtkTextIter
5336 * Tests whether two iterators are equal, using the fastest possible
5337 * mechanism. This function is very fast; you can expect it to perform
5338 * better than e.g. getting the character offset for each iterator and
5339 * comparing the offsets yourself. Also, it's a bit faster than
5340 * gtk_text_iter_compare().
5342 * Return value: %TRUE if the iterators point to the same place in the buffer
5345 gtk_text_iter_equal (const GtkTextIter *lhs,
5346 const GtkTextIter *rhs)
5348 GtkTextRealIter *real_lhs;
5349 GtkTextRealIter *real_rhs;
5351 real_lhs = (GtkTextRealIter*)lhs;
5352 real_rhs = (GtkTextRealIter*)rhs;
5354 check_invariants (lhs);
5355 check_invariants (rhs);
5357 if (real_lhs->line != real_rhs->line)
5359 else if (real_lhs->line_byte_offset >= 0 &&
5360 real_rhs->line_byte_offset >= 0)
5361 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5364 /* the ensure_char_offsets () calls do nothing if the char offsets
5365 are already up-to-date. */
5366 ensure_char_offsets (real_lhs);
5367 ensure_char_offsets (real_rhs);
5368 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5373 * gtk_text_iter_compare:
5374 * @lhs: a #GtkTextIter
5375 * @rhs: another #GtkTextIter
5377 * A qsort()-style function that returns negative if @lhs is less than
5378 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5379 * Ordering is in character offset order, i.e. the first character in the buffer
5380 * is less than the second character in the buffer.
5382 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5385 gtk_text_iter_compare (const GtkTextIter *lhs,
5386 const GtkTextIter *rhs)
5388 GtkTextRealIter *real_lhs;
5389 GtkTextRealIter *real_rhs;
5391 real_lhs = gtk_text_iter_make_surreal (lhs);
5392 real_rhs = gtk_text_iter_make_surreal (rhs);
5394 if (real_lhs == NULL ||
5396 return -1; /* why not */
5398 check_invariants (lhs);
5399 check_invariants (rhs);
5401 if (real_lhs->line == real_rhs->line)
5403 gint left_index, right_index;
5405 if (real_lhs->line_byte_offset >= 0 &&
5406 real_rhs->line_byte_offset >= 0)
5408 left_index = real_lhs->line_byte_offset;
5409 right_index = real_rhs->line_byte_offset;
5413 /* the ensure_char_offsets () calls do nothing if
5414 the offsets are already up-to-date. */
5415 ensure_char_offsets (real_lhs);
5416 ensure_char_offsets (real_rhs);
5417 left_index = real_lhs->line_char_offset;
5418 right_index = real_rhs->line_char_offset;
5421 if (left_index < right_index)
5423 else if (left_index > right_index)
5432 line1 = gtk_text_iter_get_line (lhs);
5433 line2 = gtk_text_iter_get_line (rhs);
5436 else if (line1 > line2)
5444 * gtk_text_iter_in_range:
5445 * @iter: a #GtkTextIter
5446 * @start: start of range
5447 * @end: end of range
5449 * Checks whether @iter falls in the range [@start, @end).
5450 * @start and @end must be in ascending order.
5452 * Return value: %TRUE if @iter is in the range
5455 gtk_text_iter_in_range (const GtkTextIter *iter,
5456 const GtkTextIter *start,
5457 const GtkTextIter *end)
5459 g_return_val_if_fail (iter != NULL, FALSE);
5460 g_return_val_if_fail (start != NULL, FALSE);
5461 g_return_val_if_fail (end != NULL, FALSE);
5462 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5464 return gtk_text_iter_compare (iter, start) >= 0 &&
5465 gtk_text_iter_compare (iter, end) < 0;
5469 * gtk_text_iter_order:
5470 * @first: a #GtkTextIter
5471 * @second: another #GtkTextIter
5473 * Swaps the value of @first and @second if @second comes before
5474 * @first in the buffer. That is, ensures that @first and @second are
5475 * in sequence. Most text buffer functions that take a range call this
5476 * automatically on your behalf, so there's no real reason to call it yourself
5477 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5478 * that expect a pre-sorted range.
5482 gtk_text_iter_order (GtkTextIter *first,
5483 GtkTextIter *second)
5485 g_return_if_fail (first != NULL);
5486 g_return_if_fail (second != NULL);
5488 if (gtk_text_iter_compare (first, second) > 0)
5499 * Init iterators from the BTree
5503 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5507 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5508 gint real_char_index;
5512 g_return_if_fail (iter != NULL);
5513 g_return_if_fail (tree != NULL);
5515 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5516 &line_start, &real_char_index);
5518 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5520 real->cached_char_index = real_char_index;
5522 check_invariants (iter);
5526 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5531 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5535 g_return_if_fail (iter != NULL);
5536 g_return_if_fail (tree != NULL);
5538 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5540 iter_init_from_char_offset (iter, tree, line, char_on_line);
5542 /* We might as well cache this, since we know it. */
5543 real->cached_line_number = real_line;
5545 check_invariants (iter);
5549 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5554 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5558 g_return_if_fail (iter != NULL);
5559 g_return_if_fail (tree != NULL);
5561 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5563 iter_init_from_byte_offset (iter, tree, line, byte_index);
5565 /* We might as well cache this, since we know it. */
5566 real->cached_line_number = real_line;
5568 check_invariants (iter);
5572 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5577 g_return_if_fail (iter != NULL);
5578 g_return_if_fail (tree != NULL);
5579 g_return_if_fail (line != NULL);
5581 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5583 check_invariants (iter);
5587 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5593 g_return_val_if_fail (iter != NULL, FALSE);
5594 g_return_val_if_fail (tree != NULL, FALSE);
5596 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5600 /* Set iter to last in tree */
5601 _gtk_text_btree_get_end_iter (tree, iter);
5602 check_invariants (iter);
5607 iter_init_from_byte_offset (iter, tree, line, 0);
5609 if (!gtk_text_iter_toggles_tag (iter, tag))
5610 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5612 check_invariants (iter);
5618 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5622 g_return_val_if_fail (iter != NULL, FALSE);
5623 g_return_val_if_fail (tree != NULL, FALSE);
5625 _gtk_text_btree_get_end_iter (tree, iter);
5626 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5627 check_invariants (iter);
5633 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5635 const gchar *mark_name)
5639 g_return_val_if_fail (iter != NULL, FALSE);
5640 g_return_val_if_fail (tree != NULL, FALSE);
5642 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5648 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5649 check_invariants (iter);
5655 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5659 GtkTextLineSegment *seg;
5661 g_return_if_fail (iter != NULL);
5662 g_return_if_fail (tree != NULL);
5663 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5665 seg = mark->segment;
5667 iter_init_from_segment (iter, tree,
5668 seg->body.mark.line, seg);
5669 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5670 check_invariants (iter);
5674 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5676 GtkTextChildAnchor *anchor)
5678 GtkTextLineSegment *seg;
5680 g_return_if_fail (iter != NULL);
5681 g_return_if_fail (tree != NULL);
5682 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5684 seg = anchor->segment;
5686 g_assert (seg->body.child.line != NULL);
5688 iter_init_from_segment (iter, tree,
5689 seg->body.child.line, seg);
5690 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5691 check_invariants (iter);
5695 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5698 g_return_if_fail (iter != NULL);
5699 g_return_if_fail (tree != NULL);
5701 _gtk_text_btree_get_iter_at_char (tree,
5703 _gtk_text_btree_char_count (tree));
5704 check_invariants (iter);
5708 _gtk_text_iter_check (const GtkTextIter *iter)
5710 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5711 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5712 GtkTextLineSegment *byte_segment = NULL;
5713 GtkTextLineSegment *byte_any_segment = NULL;
5714 GtkTextLineSegment *char_segment = NULL;
5715 GtkTextLineSegment *char_any_segment = NULL;
5716 gboolean segments_updated;
5718 /* This function checks our class invariants for the Iter class. */
5720 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5722 if (real->chars_changed_stamp !=
5723 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5724 g_error ("iterator check failed: invalid iterator");
5726 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5727 g_error ("iterator check failed: both char and byte offsets are invalid");
5729 segments_updated = (real->segments_changed_stamp ==
5730 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5733 printf ("checking iter, segments %s updated, byte %d char %d\n",
5734 segments_updated ? "are" : "aren't",
5735 real->line_byte_offset,
5736 real->line_char_offset);
5739 if (segments_updated)
5741 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5742 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5744 if (real->segment->char_count == 0)
5745 g_error ("iterator check failed: segment is not indexable.");
5747 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5748 g_error ("segment char offset is not properly up-to-date");
5750 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5751 g_error ("segment byte offset is not properly up-to-date");
5753 if (real->segment_byte_offset >= 0 &&
5754 real->segment_byte_offset >= real->segment->byte_count)
5755 g_error ("segment byte offset is too large.");
5757 if (real->segment_char_offset >= 0 &&
5758 real->segment_char_offset >= real->segment->char_count)
5759 g_error ("segment char offset is too large.");
5762 if (real->line_byte_offset >= 0)
5764 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5765 &byte_segment, &byte_any_segment,
5766 &seg_byte_offset, &line_byte_offset);
5768 if (line_byte_offset != real->line_byte_offset)
5769 g_error ("wrong byte offset was stored in iterator");
5771 if (segments_updated)
5773 if (real->segment != byte_segment)
5774 g_error ("wrong segment was stored in iterator");
5776 if (real->any_segment != byte_any_segment)
5777 g_error ("wrong any_segment was stored in iterator");
5779 if (seg_byte_offset != real->segment_byte_offset)
5780 g_error ("wrong segment byte offset was stored in iterator");
5782 if (byte_segment->type == >k_text_char_type)
5785 p = byte_segment->body.chars + seg_byte_offset;
5787 if (!gtk_text_byte_begins_utf8_char (p))
5788 g_error ("broken iterator byte index pointed into the middle of a character");
5793 if (real->line_char_offset >= 0)
5795 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5796 &char_segment, &char_any_segment,
5797 &seg_char_offset, &line_char_offset);
5799 if (line_char_offset != real->line_char_offset)
5800 g_error ("wrong char offset was stored in iterator");
5802 if (segments_updated)
5804 if (real->segment != char_segment)
5805 g_error ("wrong segment was stored in iterator");
5807 if (real->any_segment != char_any_segment)
5808 g_error ("wrong any_segment was stored in iterator");
5810 if (seg_char_offset != real->segment_char_offset)
5811 g_error ("wrong segment char offset was stored in iterator");
5813 if (char_segment->type == >k_text_char_type)
5816 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5819 /* hmm, not likely to happen eh */
5820 if (!gtk_text_byte_begins_utf8_char (p))
5821 g_error ("broken iterator char offset pointed into the middle of a character");
5826 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5828 if (byte_segment != char_segment)
5829 g_error ("char and byte offsets did not point to the same segment");
5831 if (byte_any_segment != char_any_segment)
5832 g_error ("char and byte offsets did not point to the same any segment");
5834 /* Make sure the segment offsets are equivalent, if it's a char
5836 if (char_segment->type == >k_text_char_type)
5838 gint byte_offset = 0;
5839 gint char_offset = 0;
5840 while (char_offset < seg_char_offset)
5842 const char * start = char_segment->body.chars + byte_offset;
5843 byte_offset += g_utf8_next_char (start) - start;
5847 if (byte_offset != seg_byte_offset)
5848 g_error ("byte offset did not correspond to char offset");
5851 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5853 if (char_offset != seg_char_offset)
5854 g_error ("char offset did not correspond to byte offset");
5856 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5857 g_error ("byte index for iterator does not index the start of a character");
5861 if (real->cached_line_number >= 0)
5865 should_be = _gtk_text_line_get_number (real->line);
5866 if (real->cached_line_number != should_be)
5867 g_error ("wrong line number was cached");
5870 if (real->cached_char_index >= 0)
5872 if (real->line_char_offset >= 0) /* only way we can check it
5873 efficiently, not a real
5878 char_index = _gtk_text_line_char_index (real->line);
5879 char_index += real->line_char_offset;
5881 if (real->cached_char_index != char_index)
5882 g_error ("wrong char index was cached");
5886 if (_gtk_text_line_is_last (real->line, real->tree))
5887 g_error ("Iterator was on last line (past the end iterator)");