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);
447 G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
452 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
454 GtkTextRealIter *real;
456 g_return_val_if_fail (iter != NULL, NULL);
458 real = gtk_text_iter_make_real (iter);
463 check_invariants (iter);
465 g_assert (real->segment != NULL);
467 return real->segment;
471 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
473 GtkTextRealIter *real;
475 g_return_val_if_fail (iter != NULL, NULL);
477 real = gtk_text_iter_make_real (iter);
482 check_invariants (iter);
484 g_assert (real->any_segment != NULL);
486 return real->any_segment;
490 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
492 GtkTextRealIter *real;
494 g_return_val_if_fail (iter != NULL, 0);
496 real = gtk_text_iter_make_real (iter);
501 ensure_byte_offsets (real);
503 check_invariants (iter);
505 return real->segment_byte_offset;
509 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
511 GtkTextRealIter *real;
513 g_return_val_if_fail (iter != NULL, 0);
515 real = gtk_text_iter_make_real (iter);
520 ensure_char_offsets (real);
522 check_invariants (iter);
524 return real->segment_char_offset;
527 /* This function does not require a still-valid
530 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
532 const GtkTextRealIter *real;
534 g_return_val_if_fail (iter != NULL, NULL);
536 real = (const GtkTextRealIter*)iter;
541 /* This function does not require a still-valid
544 _gtk_text_iter_get_btree (const GtkTextIter *iter)
546 const GtkTextRealIter *real;
548 g_return_val_if_fail (iter != NULL, NULL);
550 real = (const GtkTextRealIter*)iter;
560 * gtk_text_iter_get_offset:
563 * Returns the character offset of an iterator.
564 * Each character in a #GtkTextBuffer has an offset,
565 * starting with 0 for the first character in the buffer.
566 * Use gtk_text_buffer_get_iter_at_offset () to convert an
567 * offset back into an iterator.
569 * Return value: a character offset
572 gtk_text_iter_get_offset (const GtkTextIter *iter)
574 GtkTextRealIter *real;
576 g_return_val_if_fail (iter != NULL, 0);
578 real = gtk_text_iter_make_surreal (iter);
583 check_invariants (iter);
585 if (real->cached_char_index < 0)
587 ensure_char_offsets (real);
589 real->cached_char_index =
590 _gtk_text_line_char_index (real->line);
591 real->cached_char_index += real->line_char_offset;
594 check_invariants (iter);
596 return real->cached_char_index;
600 * gtk_text_iter_get_line:
603 * Returns the line number containing the iterator. Lines in
604 * a #GtkTextBuffer are numbered beginning with 0 for the first
605 * line in the buffer.
607 * Return value: a line number
610 gtk_text_iter_get_line (const GtkTextIter *iter)
612 GtkTextRealIter *real;
614 g_return_val_if_fail (iter != NULL, 0);
616 real = gtk_text_iter_make_surreal (iter);
621 if (real->cached_line_number < 0)
622 real->cached_line_number =
623 _gtk_text_line_get_number (real->line);
625 check_invariants (iter);
627 return real->cached_line_number;
631 * gtk_text_iter_get_line_offset:
634 * Returns the character offset of the iterator,
635 * counting from the start of a newline-terminated line.
636 * The first character on the line has offset 0.
638 * Return value: offset from start of line
641 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
643 GtkTextRealIter *real;
645 g_return_val_if_fail (iter != NULL, 0);
647 real = gtk_text_iter_make_surreal (iter);
652 ensure_char_offsets (real);
654 check_invariants (iter);
656 return real->line_char_offset;
660 * gtk_text_iter_get_line_index:
663 * Returns the byte index of the iterator, counting
664 * from the start of a newline-terminated line.
665 * Remember that #GtkTextBuffer encodes text in
666 * UTF-8, and that characters can require a variable
667 * number of bytes to represent.
669 * Return value: distance from start of line, in bytes
672 gtk_text_iter_get_line_index (const GtkTextIter *iter)
674 GtkTextRealIter *real;
676 g_return_val_if_fail (iter != NULL, 0);
678 real = gtk_text_iter_make_surreal (iter);
683 ensure_byte_offsets (real);
685 check_invariants (iter);
687 return real->line_byte_offset;
691 * gtk_text_iter_get_visible_line_offset:
692 * @iter: a #GtkTextIter
694 * Returns the offset in characters from the start of the
695 * line to the given @iter, not counting characters that
696 * are invisible due to tags with the "invisible" flag
699 * Return value: offset in visible characters from the start of the line
702 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
704 GtkTextRealIter *real;
706 GtkTextLineSegment *seg;
709 g_return_val_if_fail (iter != NULL, 0);
711 real = gtk_text_iter_make_real (iter);
716 ensure_char_offsets (real);
718 check_invariants (iter);
720 vis_offset = real->line_char_offset;
722 g_assert (vis_offset >= 0);
724 _gtk_text_btree_get_iter_at_line (real->tree,
729 seg = _gtk_text_iter_get_indexable_segment (&pos);
731 while (seg != real->segment)
733 /* This is a pretty expensive call, making the
734 * whole function pretty lame; we could keep track
735 * of current invisibility state by looking at toggle
736 * segments as we loop, and then call this function
737 * only once per line, in order to speed up the loop
740 if (_gtk_text_btree_char_is_invisible (&pos))
741 vis_offset -= seg->char_count;
743 _gtk_text_iter_forward_indexable_segment (&pos);
745 seg = _gtk_text_iter_get_indexable_segment (&pos);
748 if (_gtk_text_btree_char_is_invisible (&pos))
749 vis_offset -= real->segment_char_offset;
756 * gtk_text_iter_get_visible_line_index:
757 * @iter: a #GtkTextIter
759 * Returns the number of bytes from the start of the
760 * line to the given @iter, not counting bytes that
761 * are invisible due to tags with the "invisible" flag
764 * Return value: byte index of @iter with respect to the start of the line
767 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
769 GtkTextRealIter *real;
771 GtkTextLineSegment *seg;
774 g_return_val_if_fail (iter != NULL, 0);
776 real = gtk_text_iter_make_real (iter);
781 ensure_byte_offsets (real);
783 check_invariants (iter);
785 vis_offset = real->line_byte_offset;
787 g_assert (vis_offset >= 0);
789 _gtk_text_btree_get_iter_at_line (real->tree,
794 seg = _gtk_text_iter_get_indexable_segment (&pos);
796 while (seg != real->segment)
798 /* This is a pretty expensive call, making the
799 * whole function pretty lame; we could keep track
800 * of current invisibility state by looking at toggle
801 * segments as we loop, and then call this function
802 * only once per line, in order to speed up the loop
805 if (_gtk_text_btree_char_is_invisible (&pos))
806 vis_offset -= seg->byte_count;
808 _gtk_text_iter_forward_indexable_segment (&pos);
810 seg = _gtk_text_iter_get_indexable_segment (&pos);
813 if (_gtk_text_btree_char_is_invisible (&pos))
814 vis_offset -= real->segment_byte_offset;
824 * gtk_text_iter_get_char:
827 * Returns the Unicode character at this iterator. (Equivalent to
828 * operator* on a C++ iterator.) If the element at this iterator is a
829 * non-character element, such as an image embedded in the buffer, the
830 * Unicode "unknown" character 0xFFFC is returned. If invoked on
831 * the end iterator, zero is returned; zero is not a valid Unicode character.
832 * So you can write a loop which ends when gtk_text_iter_get_char ()
835 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
838 gtk_text_iter_get_char (const GtkTextIter *iter)
840 GtkTextRealIter *real;
842 g_return_val_if_fail (iter != NULL, 0);
844 real = gtk_text_iter_make_real (iter);
849 check_invariants (iter);
851 if (gtk_text_iter_is_end (iter))
853 else if (real->segment->type == >k_text_char_type)
855 ensure_byte_offsets (real);
857 return g_utf8_get_char (real->segment->body.chars +
858 real->segment_byte_offset);
862 /* Unicode "unknown character" 0xFFFC */
863 return GTK_TEXT_UNKNOWN_CHAR;
868 * gtk_text_iter_get_slice:
869 * @start: iterator at start of a range
870 * @end: iterator at end of a range
872 * Returns the text in the given range. A "slice" is an array of
873 * characters encoded in UTF-8 format, including the Unicode "unknown"
874 * character 0xFFFC for iterable non-character elements in the buffer,
875 * such as images. Because images are encoded in the slice, byte and
876 * character offsets in the returned array will correspond to byte
877 * offsets in the text buffer. Note that 0xFFFC can occur in normal
878 * text as well, so it is not a reliable indicator that a pixbuf or
879 * widget is in the buffer.
881 * Return value: slice of text from the buffer
884 gtk_text_iter_get_slice (const GtkTextIter *start,
885 const GtkTextIter *end)
887 g_return_val_if_fail (start != NULL, NULL);
888 g_return_val_if_fail (end != NULL, NULL);
890 check_invariants (start);
891 check_invariants (end);
893 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
897 * gtk_text_iter_get_text:
898 * @start: iterator at start of a range
899 * @end: iterator at end of a range
901 * Returns <emphasis>text</emphasis> in the given range. If the range
902 * contains non-text elements such as images, the character and byte
903 * offsets in the returned string will not correspond to character and
904 * byte offsets in the buffer. If you want offsets to correspond, see
905 * gtk_text_iter_get_slice ().
907 * Return value: array of characters from the buffer
910 gtk_text_iter_get_text (const GtkTextIter *start,
911 const GtkTextIter *end)
913 g_return_val_if_fail (start != NULL, NULL);
914 g_return_val_if_fail (end != NULL, NULL);
916 check_invariants (start);
917 check_invariants (end);
919 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
923 * gtk_text_iter_get_visible_slice:
924 * @start: iterator at start of range
925 * @end: iterator at end of range
927 * Like gtk_text_iter_get_slice (), but invisible text is not included.
928 * Invisible text is usually invisible because a #GtkTextTag with the
929 * "invisible" attribute turned on has been applied to it.
931 * Return value: slice of text from the buffer
934 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
935 const GtkTextIter *end)
937 g_return_val_if_fail (start != NULL, NULL);
938 g_return_val_if_fail (end != NULL, NULL);
940 check_invariants (start);
941 check_invariants (end);
943 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
947 * gtk_text_iter_get_visible_text:
948 * @start: iterator at start of range
949 * @end: iterator at end of range
951 * Like gtk_text_iter_get_text (), but invisible text is not included.
952 * Invisible text is usually invisible because a #GtkTextTag with the
953 * "invisible" attribute turned on has been applied to it.
955 * Return value: string containing visible text in the range
958 gtk_text_iter_get_visible_text (const GtkTextIter *start,
959 const GtkTextIter *end)
961 g_return_val_if_fail (start != NULL, NULL);
962 g_return_val_if_fail (end != NULL, NULL);
964 check_invariants (start);
965 check_invariants (end);
967 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
971 * gtk_text_iter_get_pixbuf:
974 * If the element at @iter is a pixbuf, the pixbuf is returned
975 * (with no new reference count added). Otherwise,
978 * Return value: (transfer none): the pixbuf at @iter
981 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
983 GtkTextRealIter *real;
985 g_return_val_if_fail (iter != NULL, NULL);
987 real = gtk_text_iter_make_real (iter);
992 check_invariants (iter);
994 if (real->segment->type != >k_text_pixbuf_type)
997 return real->segment->body.pixbuf.pixbuf;
1001 * gtk_text_iter_get_child_anchor:
1002 * @iter: an iterator
1004 * If the location at @iter contains a child anchor, the
1005 * anchor is returned (with no new reference count added). Otherwise,
1006 * %NULL is returned.
1008 * Return value: (transfer none): the anchor at @iter
1011 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1013 GtkTextRealIter *real;
1015 g_return_val_if_fail (iter != NULL, NULL);
1017 real = gtk_text_iter_make_real (iter);
1022 check_invariants (iter);
1024 if (real->segment->type != >k_text_child_type)
1027 return real->segment->body.child.obj;
1031 * gtk_text_iter_get_marks:
1032 * @iter: an iterator
1034 * Returns a list of all #GtkTextMark at this location. Because marks
1035 * are not iterable (they don't take up any "space" in the buffer,
1036 * they are just marks in between iterable locations), multiple marks
1037 * can exist in the same place. The returned list is not in any
1040 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1043 gtk_text_iter_get_marks (const GtkTextIter *iter)
1045 GtkTextRealIter *real;
1046 GtkTextLineSegment *seg;
1049 g_return_val_if_fail (iter != NULL, NULL);
1051 real = gtk_text_iter_make_real (iter);
1056 check_invariants (iter);
1059 seg = real->any_segment;
1060 while (seg != real->segment)
1062 if (seg->type == >k_text_left_mark_type ||
1063 seg->type == >k_text_right_mark_type)
1064 retval = g_slist_prepend (retval, seg->body.mark.obj);
1069 /* The returned list isn't guaranteed to be in any special order,
1075 * gtk_text_iter_get_toggled_tags:
1076 * @iter: an iterator
1077 * @toggled_on: %TRUE to get toggled-on tags
1079 * Returns a list of #GtkTextTag that are toggled on or off at this
1080 * point. (If @toggled_on is %TRUE, the list contains tags that are
1081 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1082 * range of characters following @iter has that tag applied to it. If
1083 * a tag is toggled off, then some non-empty range following @iter
1084 * does <emphasis>not</emphasis> have the tag applied to it.
1086 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1089 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1090 gboolean toggled_on)
1092 GtkTextRealIter *real;
1093 GtkTextLineSegment *seg;
1096 g_return_val_if_fail (iter != NULL, NULL);
1098 real = gtk_text_iter_make_real (iter);
1103 check_invariants (iter);
1106 seg = real->any_segment;
1107 while (seg != real->segment)
1111 if (seg->type == >k_text_toggle_on_type)
1113 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1118 if (seg->type == >k_text_toggle_off_type)
1120 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1127 /* The returned list isn't guaranteed to be in any special order,
1133 * gtk_text_iter_begins_tag:
1134 * @iter: an iterator
1135 * @tag: (allow-none): a #GtkTextTag, or %NULL
1137 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1138 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1139 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1140 * <emphasis>start</emphasis> of the tagged range;
1141 * gtk_text_iter_has_tag () tells you whether an iterator is
1142 * <emphasis>within</emphasis> a tagged range.
1144 * Return value: whether @iter is the start of a range tagged with @tag
1147 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1150 GtkTextRealIter *real;
1151 GtkTextLineSegment *seg;
1153 g_return_val_if_fail (iter != NULL, FALSE);
1155 real = gtk_text_iter_make_real (iter);
1160 check_invariants (iter);
1162 seg = real->any_segment;
1163 while (seg != real->segment)
1165 if (seg->type == >k_text_toggle_on_type)
1168 seg->body.toggle.info->tag == tag)
1179 * gtk_text_iter_ends_tag:
1180 * @iter: an iterator
1181 * @tag: (allow-none): a #GtkTextTag, or %NULL
1183 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1184 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1185 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1186 * <emphasis>end</emphasis> of the tagged range;
1187 * gtk_text_iter_has_tag () tells you whether an iterator is
1188 * <emphasis>within</emphasis> a tagged range.
1190 * Return value: whether @iter is the end of a range tagged with @tag
1194 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1197 GtkTextRealIter *real;
1198 GtkTextLineSegment *seg;
1200 g_return_val_if_fail (iter != NULL, FALSE);
1202 real = gtk_text_iter_make_real (iter);
1207 check_invariants (iter);
1209 seg = real->any_segment;
1210 while (seg != real->segment)
1212 if (seg->type == >k_text_toggle_off_type)
1215 seg->body.toggle.info->tag == tag)
1226 * gtk_text_iter_toggles_tag:
1227 * @iter: an iterator
1228 * @tag: (allow-none): a #GtkTextTag, or %NULL
1230 * This is equivalent to (gtk_text_iter_begins_tag () ||
1231 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1232 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1234 * Return value: whether @tag is toggled on or off at @iter
1237 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1240 GtkTextRealIter *real;
1241 GtkTextLineSegment *seg;
1243 g_return_val_if_fail (iter != NULL, FALSE);
1245 real = gtk_text_iter_make_real (iter);
1250 check_invariants (iter);
1252 seg = real->any_segment;
1253 while (seg != real->segment)
1255 if ( (seg->type == >k_text_toggle_off_type ||
1256 seg->type == >k_text_toggle_on_type) &&
1258 seg->body.toggle.info->tag == tag) )
1268 * gtk_text_iter_has_tag:
1269 * @iter: an iterator
1270 * @tag: a #GtkTextTag
1272 * Returns %TRUE if @iter is within a range tagged with @tag.
1274 * Return value: whether @iter is tagged with @tag
1277 gtk_text_iter_has_tag (const GtkTextIter *iter,
1280 GtkTextRealIter *real;
1282 g_return_val_if_fail (iter != NULL, FALSE);
1283 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1285 real = gtk_text_iter_make_surreal (iter);
1290 check_invariants (iter);
1292 if (real->line_byte_offset >= 0)
1294 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1295 real->line_byte_offset, tag);
1299 g_assert (real->line_char_offset >= 0);
1300 return _gtk_text_line_char_has_tag (real->line, real->tree,
1301 real->line_char_offset, tag);
1306 * gtk_text_iter_get_tags:
1307 * @iter: a #GtkTextIter
1309 * Returns a list of tags that apply to @iter, in ascending order of
1310 * priority (highest-priority tags are last). The #GtkTextTag in the
1311 * list don't have a reference added, but you have to free the list
1314 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1317 gtk_text_iter_get_tags (const GtkTextIter *iter)
1324 g_return_val_if_fail (iter != NULL, NULL);
1326 /* Get the tags at this spot */
1327 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1329 /* No tags, use default style */
1330 if (tags == NULL || tag_count == 0)
1339 while (i < tag_count)
1341 retval = g_slist_prepend (retval, tags[i]);
1347 /* Return tags in ascending order of priority */
1348 return g_slist_reverse (retval);
1352 * gtk_text_iter_editable:
1353 * @iter: an iterator
1354 * @default_setting: %TRUE if text is editable by default
1356 * Returns whether the character at @iter is within an editable region
1357 * of text. Non-editable text is "locked" and can't be changed by the
1358 * user via #GtkTextView. This function is simply a convenience
1359 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1360 * to this text affect editability, @default_setting will be returned.
1362 * You don't want to use this function to decide whether text can be
1363 * inserted at @iter, because for insertion you don't want to know
1364 * whether the char at @iter is inside an editable range, you want to
1365 * know whether a new character inserted at @iter would be inside an
1366 * editable range. Use gtk_text_iter_can_insert() to handle this
1369 * Return value: whether @iter is inside an editable range
1372 gtk_text_iter_editable (const GtkTextIter *iter,
1373 gboolean default_setting)
1375 GtkTextAttributes *values;
1378 g_return_val_if_fail (iter != NULL, FALSE);
1380 values = gtk_text_attributes_new ();
1382 values->editable = default_setting;
1384 gtk_text_iter_get_attributes (iter, values);
1386 retval = values->editable;
1388 gtk_text_attributes_unref (values);
1394 * gtk_text_iter_can_insert:
1395 * @iter: an iterator
1396 * @default_editability: %TRUE if text is editable by default
1398 * Considering the default editability of the buffer, and tags that
1399 * affect editability, determines whether text inserted at @iter would
1400 * be editable. If text inserted at @iter would be editable then the
1401 * user should be allowed to insert text at @iter.
1402 * gtk_text_buffer_insert_interactive() uses this function to decide
1403 * whether insertions are allowed at a given position.
1405 * Return value: whether text inserted at @iter would be editable
1408 gtk_text_iter_can_insert (const GtkTextIter *iter,
1409 gboolean default_editability)
1411 g_return_val_if_fail (iter != NULL, FALSE);
1413 if (gtk_text_iter_editable (iter, default_editability))
1415 /* If at start/end of buffer, default editability is used */
1416 else if ((gtk_text_iter_is_start (iter) ||
1417 gtk_text_iter_is_end (iter)) &&
1418 default_editability)
1422 /* if iter isn't editable, and the char before iter is,
1423 * then iter is the first char in an editable region
1424 * and thus insertion at iter results in editable text.
1426 GtkTextIter prev = *iter;
1427 gtk_text_iter_backward_char (&prev);
1428 return gtk_text_iter_editable (&prev, default_editability);
1434 * gtk_text_iter_get_language:
1435 * @iter: an iterator
1437 * A convenience wrapper around gtk_text_iter_get_attributes (),
1438 * which returns the language in effect at @iter. If no tags affecting
1439 * language apply to @iter, the return value is identical to that of
1440 * gtk_get_default_language ().
1442 * Return value: language in effect at @iter
1445 gtk_text_iter_get_language (const GtkTextIter *iter)
1447 GtkTextAttributes *values;
1448 PangoLanguage *retval;
1450 values = gtk_text_attributes_new ();
1452 gtk_text_iter_get_attributes (iter, values);
1454 retval = values->language;
1456 gtk_text_attributes_unref (values);
1462 * gtk_text_iter_starts_line:
1463 * @iter: an iterator
1465 * Returns %TRUE if @iter begins a paragraph,
1466 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1467 * However this function is potentially more efficient than
1468 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1469 * the offset, it just has to see whether it's 0.
1471 * Return value: whether @iter begins a line
1474 gtk_text_iter_starts_line (const GtkTextIter *iter)
1476 GtkTextRealIter *real;
1478 g_return_val_if_fail (iter != NULL, FALSE);
1480 real = gtk_text_iter_make_surreal (iter);
1485 check_invariants (iter);
1487 if (real->line_byte_offset >= 0)
1489 return (real->line_byte_offset == 0);
1493 g_assert (real->line_char_offset >= 0);
1494 return (real->line_char_offset == 0);
1499 * gtk_text_iter_ends_line:
1500 * @iter: an iterator
1502 * Returns %TRUE if @iter points to the start of the paragraph
1503 * delimiter characters for a line (delimiters will be either a
1504 * newline, a carriage return, a carriage return followed by a
1505 * newline, or a Unicode paragraph separator character). Note that an
1506 * iterator pointing to the \n of a \r\n pair will not be counted as
1507 * the end of a line, the line ends before the \r. The end iterator is
1508 * considered to be at the end of a line, even though there are no
1509 * paragraph delimiter chars there.
1511 * Return value: whether @iter is at the end of a line
1514 gtk_text_iter_ends_line (const GtkTextIter *iter)
1518 g_return_val_if_fail (iter != NULL, FALSE);
1520 check_invariants (iter);
1522 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1523 * Unicode 3.0; update this if that changes.
1525 #define PARAGRAPH_SEPARATOR 0x2029
1527 wc = gtk_text_iter_get_char (iter);
1529 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1531 else if (wc == '\n')
1533 GtkTextIter tmp = *iter;
1535 /* need to determine if a \r precedes the \n, in which case
1536 * we aren't the end of the line.
1537 * Note however that if \r and \n are on different lines, they
1538 * both are terminators. This for instance may happen after
1539 * deleting some text:
1541 1 some text\r delete 'a' 1 some text\r
1542 2 a\n ---------> 2 \n
1547 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1550 if (!gtk_text_iter_backward_char (&tmp))
1553 return gtk_text_iter_get_char (&tmp) != '\r';
1560 * gtk_text_iter_is_end:
1561 * @iter: an iterator
1563 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1564 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1565 * the most efficient way to check whether an iterator is the end
1568 * Return value: whether @iter is the end iterator
1571 gtk_text_iter_is_end (const GtkTextIter *iter)
1573 GtkTextRealIter *real;
1575 g_return_val_if_fail (iter != NULL, FALSE);
1577 real = gtk_text_iter_make_surreal (iter);
1582 check_invariants (iter);
1584 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1587 /* Now we need the segments validated */
1588 real = gtk_text_iter_make_real (iter);
1593 return _gtk_text_btree_is_end (real->tree, real->line,
1595 real->segment_byte_offset,
1596 real->segment_char_offset);
1600 * gtk_text_iter_is_start:
1601 * @iter: an iterator
1603 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1604 * if @iter has a character offset of 0.
1606 * Return value: whether @iter is the first in the buffer
1609 gtk_text_iter_is_start (const GtkTextIter *iter)
1611 return gtk_text_iter_get_offset (iter) == 0;
1615 * gtk_text_iter_get_chars_in_line:
1616 * @iter: an iterator
1618 * Returns the number of characters in the line containing @iter,
1619 * including the paragraph delimiters.
1621 * Return value: number of characters in the line
1624 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1626 GtkTextRealIter *real;
1628 GtkTextLineSegment *seg;
1630 g_return_val_if_fail (iter != NULL, 0);
1632 real = gtk_text_iter_make_surreal (iter);
1637 check_invariants (iter);
1639 if (real->line_char_offset >= 0)
1641 /* We can start at the segments we've already found. */
1642 count = real->line_char_offset - real->segment_char_offset;
1643 seg = _gtk_text_iter_get_indexable_segment (iter);
1647 /* count whole line. */
1648 seg = real->line->segments;
1655 count += seg->char_count;
1660 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1661 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1667 * gtk_text_iter_get_bytes_in_line:
1668 * @iter: an iterator
1670 * Returns the number of bytes in the line containing @iter,
1671 * including the paragraph delimiters.
1673 * Return value: number of bytes in the line
1676 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1678 GtkTextRealIter *real;
1680 GtkTextLineSegment *seg;
1682 g_return_val_if_fail (iter != NULL, 0);
1684 real = gtk_text_iter_make_surreal (iter);
1689 check_invariants (iter);
1691 if (real->line_byte_offset >= 0)
1693 /* We can start at the segments we've already found. */
1694 count = real->line_byte_offset - real->segment_byte_offset;
1695 seg = _gtk_text_iter_get_indexable_segment (iter);
1699 /* count whole line. */
1700 seg = real->line->segments;
1706 count += seg->byte_count;
1711 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1712 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1718 * gtk_text_iter_get_attributes:
1719 * @iter: an iterator
1720 * @values: (out): a #GtkTextAttributes to be filled in
1722 * Computes the effect of any tags applied to this spot in the
1723 * text. The @values parameter should be initialized to the default
1724 * settings you wish to use if no tags are in effect. You'd typically
1725 * obtain the defaults from gtk_text_view_get_default_attributes().
1727 * gtk_text_iter_get_attributes () will modify @values, applying the
1728 * effects of any tags present at @iter. If any tags affected @values,
1729 * the function returns %TRUE.
1731 * Return value: %TRUE if @values was modified
1734 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1735 GtkTextAttributes *values)
1740 /* Get the tags at this spot */
1741 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1743 /* No tags, use default style */
1744 if (tags == NULL || tag_count == 0)
1751 _gtk_text_attributes_fill_from_tags (values,
1761 * Increments/decrements
1764 /* The return value of this indicates WHETHER WE MOVED.
1765 * The return value of public functions indicates
1766 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1768 * This function will not change the iterator if
1769 * it's already on the last (end iter) line, i.e. it
1770 * won't move to the end of the last line.
1773 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1775 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1777 GtkTextLine *new_line;
1779 new_line = _gtk_text_line_next (real->line);
1780 g_assert (new_line);
1781 g_assert (new_line != real->line);
1782 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1784 real->line = new_line;
1786 real->line_byte_offset = 0;
1787 real->line_char_offset = 0;
1789 real->segment_byte_offset = 0;
1790 real->segment_char_offset = 0;
1792 /* Find first segments in new line */
1793 real->any_segment = real->line->segments;
1794 real->segment = real->any_segment;
1795 while (real->segment->char_count == 0)
1796 real->segment = real->segment->next;
1802 /* There is no way to move forward a line; we were already at
1803 * the line containing the end iterator.
1804 * However we may not be at the end iterator itself.
1812 /* The return value of this indicates WHETHER WE MOVED.
1813 * The return value of public functions indicates
1814 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1816 * This function is currently unused, thus it is #if-0-ed. It is
1817 * left here, since it's non-trivial code that might be useful in
1821 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1823 GtkTextLine *new_line;
1825 new_line = _gtk_text_line_previous (real->line);
1827 g_assert (new_line != real->line);
1829 if (new_line != NULL)
1831 real->line = new_line;
1833 real->line_byte_offset = 0;
1834 real->line_char_offset = 0;
1836 real->segment_byte_offset = 0;
1837 real->segment_char_offset = 0;
1839 /* Find first segments in new line */
1840 real->any_segment = real->line->segments;
1841 real->segment = real->any_segment;
1842 while (real->segment->char_count == 0)
1843 real->segment = real->segment->next;
1849 /* There is no way to move backward; we were already
1850 at the first line. */
1852 /* We leave real->line as-is */
1854 /* Note that we didn't clamp to the start of the first line. */
1861 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1865 forward_char (GtkTextRealIter *real)
1867 GtkTextIter *iter = (GtkTextIter*)real;
1869 check_invariants ((GtkTextIter*)real);
1871 ensure_char_offsets (real);
1873 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1875 /* Need to move to the next segment; if no next segment,
1876 need to move to next line. */
1877 return _gtk_text_iter_forward_indexable_segment (iter);
1881 /* Just moving within a segment. Keep byte count
1882 up-to-date, if it was already up-to-date. */
1884 g_assert (real->segment->type == >k_text_char_type);
1886 if (real->line_byte_offset >= 0)
1889 const char * start =
1890 real->segment->body.chars + real->segment_byte_offset;
1892 bytes = g_utf8_next_char (start) - start;
1894 real->line_byte_offset += bytes;
1895 real->segment_byte_offset += bytes;
1897 g_assert (real->segment_byte_offset < real->segment->byte_count);
1900 real->line_char_offset += 1;
1901 real->segment_char_offset += 1;
1903 adjust_char_index (real, 1);
1905 g_assert (real->segment_char_offset < real->segment->char_count);
1907 /* We moved into the middle of a segment, so the any_segment
1908 must now be the segment we're in the middle of. */
1909 real->any_segment = real->segment;
1911 check_invariants ((GtkTextIter*)real);
1913 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1921 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1923 /* Need to move to the next segment; if no next segment,
1924 need to move to next line. */
1925 GtkTextLineSegment *seg;
1926 GtkTextLineSegment *any_seg;
1927 GtkTextRealIter *real;
1931 g_return_val_if_fail (iter != NULL, FALSE);
1933 real = gtk_text_iter_make_real (iter);
1938 check_invariants (iter);
1940 if (real->line_char_offset >= 0)
1942 chars_skipped = real->segment->char_count - real->segment_char_offset;
1943 g_assert (chars_skipped > 0);
1948 if (real->line_byte_offset >= 0)
1950 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1951 g_assert (bytes_skipped > 0);
1956 /* Get first segment of any kind */
1957 any_seg = real->segment->next;
1958 /* skip non-indexable segments, if any */
1960 while (seg != NULL && seg->char_count == 0)
1965 real->any_segment = any_seg;
1966 real->segment = seg;
1968 if (real->line_byte_offset >= 0)
1970 g_assert (bytes_skipped > 0);
1971 real->segment_byte_offset = 0;
1972 real->line_byte_offset += bytes_skipped;
1975 if (real->line_char_offset >= 0)
1977 g_assert (chars_skipped > 0);
1978 real->segment_char_offset = 0;
1979 real->line_char_offset += chars_skipped;
1980 adjust_char_index (real, chars_skipped);
1983 check_invariants (iter);
1985 return !gtk_text_iter_is_end (iter);
1989 /* End of the line */
1990 if (forward_line_leaving_caches_unmodified (real))
1992 adjust_line_number (real, 1);
1993 if (real->line_char_offset >= 0)
1994 adjust_char_index (real, chars_skipped);
1996 g_assert (real->line_byte_offset == 0);
1997 g_assert (real->line_char_offset == 0);
1998 g_assert (real->segment_byte_offset == 0);
1999 g_assert (real->segment_char_offset == 0);
2000 g_assert (gtk_text_iter_starts_line (iter));
2002 check_invariants (iter);
2004 return !gtk_text_iter_is_end (iter);
2008 /* End of buffer, but iter is still at start of last segment,
2009 * not at the end iterator. We put it on the end iterator.
2012 check_invariants (iter);
2014 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2015 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2017 gtk_text_iter_forward_to_line_end (iter);
2019 g_assert (gtk_text_iter_is_end (iter));
2027 at_last_indexable_segment (GtkTextRealIter *real)
2029 GtkTextLineSegment *seg;
2031 /* Return TRUE if there are no indexable segments after
2035 seg = real->segment->next;
2038 if (seg->char_count > 0)
2045 /* Goes back to the start of the next segment, even if
2046 * we're not at the start of the current segment (always
2047 * ends up on a different segment if it returns TRUE)
2050 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2052 /* Move to the start of the previous segment; if no previous
2053 * segment, to the last segment in the previous line. This is
2054 * inherently a bit inefficient due to the singly-linked list and
2055 * tree nodes, but we can't afford the RAM for doubly-linked.
2057 GtkTextRealIter *real;
2058 GtkTextLineSegment *seg;
2059 GtkTextLineSegment *any_seg;
2060 GtkTextLineSegment *prev_seg;
2061 GtkTextLineSegment *prev_any_seg;
2065 g_return_val_if_fail (iter != NULL, FALSE);
2067 real = gtk_text_iter_make_real (iter);
2072 check_invariants (iter);
2074 /* Find first segments in line */
2075 any_seg = real->line->segments;
2077 while (seg->char_count == 0)
2080 if (seg == real->segment)
2082 /* Could probably do this case faster by hand-coding the
2086 /* We were already at the start of a line;
2087 * go back to the previous line.
2089 if (gtk_text_iter_backward_line (iter))
2091 /* Go forward to last indexable segment in line. */
2092 while (!at_last_indexable_segment (real))
2093 _gtk_text_iter_forward_indexable_segment (iter);
2095 check_invariants (iter);
2100 return FALSE; /* We were at the start of the first line. */
2103 /* We must be in the middle of a line; so find the indexable
2104 * segment just before our current segment.
2106 g_assert (seg != real->segment);
2110 prev_any_seg = any_seg;
2112 any_seg = seg->next;
2114 while (seg->char_count == 0)
2117 while (seg != real->segment);
2119 g_assert (prev_seg != NULL);
2120 g_assert (prev_any_seg != NULL);
2121 g_assert (prev_seg->char_count > 0);
2123 /* We skipped the entire previous segment, plus any
2124 * chars we were into the current segment.
2126 if (real->segment_byte_offset >= 0)
2127 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2131 if (real->segment_char_offset >= 0)
2132 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2136 real->segment = prev_seg;
2137 real->any_segment = prev_any_seg;
2138 real->segment_byte_offset = 0;
2139 real->segment_char_offset = 0;
2141 if (bytes_skipped >= 0)
2143 if (real->line_byte_offset >= 0)
2145 real->line_byte_offset -= bytes_skipped;
2146 g_assert (real->line_byte_offset >= 0);
2150 real->line_byte_offset = -1;
2152 if (chars_skipped >= 0)
2154 if (real->line_char_offset >= 0)
2156 real->line_char_offset -= chars_skipped;
2157 g_assert (real->line_char_offset >= 0);
2160 if (real->cached_char_index >= 0)
2162 real->cached_char_index -= chars_skipped;
2163 g_assert (real->cached_char_index >= 0);
2168 real->line_char_offset = -1;
2169 real->cached_char_index = -1;
2172 /* line number is unchanged. */
2174 check_invariants (iter);
2180 * gtk_text_iter_forward_char:
2181 * @iter: an iterator
2183 * Moves @iter forward by one character offset. Note that images
2184 * embedded in the buffer occupy 1 character slot, so
2185 * gtk_text_iter_forward_char () may actually move onto an image instead
2186 * of a character, if you have images in your buffer. If @iter is the
2187 * end iterator or one character before it, @iter will now point at
2188 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2189 * convenience when writing loops.
2191 * Return value: whether @iter moved and is dereferenceable
2194 gtk_text_iter_forward_char (GtkTextIter *iter)
2196 GtkTextRealIter *real;
2198 g_return_val_if_fail (iter != NULL, FALSE);
2200 real = gtk_text_iter_make_real (iter);
2206 check_invariants (iter);
2207 return forward_char (real);
2212 * gtk_text_iter_backward_char:
2213 * @iter: an iterator
2215 * Moves backward by one character offset. Returns %TRUE if movement
2216 * was possible; if @iter was the first in the buffer (character
2217 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2220 * Return value: whether movement was possible
2223 gtk_text_iter_backward_char (GtkTextIter *iter)
2225 g_return_val_if_fail (iter != NULL, FALSE);
2227 check_invariants (iter);
2229 return gtk_text_iter_backward_chars (iter, 1);
2233 Definitely we should try to linear scan as often as possible for
2234 movement within a single line, because we can't use the BTree to
2235 speed within-line searches up; for movement between lines, we would
2236 like to avoid the linear scan probably.
2238 Instead of using this constant, it might be nice to cache the line
2239 length in the iterator and linear scan if motion is within a single
2242 I guess you'd have to profile the various approaches.
2244 #define MAX_LINEAR_SCAN 150
2248 * gtk_text_iter_forward_chars:
2249 * @iter: an iterator
2250 * @count: number of characters to move, may be negative
2252 * Moves @count characters if possible (if @count would move past the
2253 * start or end of the buffer, moves to the start or end of the
2254 * buffer). The return value indicates whether the new position of
2255 * @iter is different from its original position, and dereferenceable
2256 * (the last iterator in the buffer is not dereferenceable). If @count
2257 * is 0, the function does nothing and returns %FALSE.
2259 * Return value: whether @iter moved and is dereferenceable
2262 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2264 GtkTextRealIter *real;
2266 g_return_val_if_fail (iter != NULL, FALSE);
2268 FIX_OVERFLOWS (count);
2270 real = gtk_text_iter_make_real (iter);
2274 else if (count == 0)
2277 return gtk_text_iter_backward_chars (iter, 0 - count);
2278 else if (count < MAX_LINEAR_SCAN)
2280 check_invariants (iter);
2284 if (!forward_char (real))
2289 return forward_char (real);
2293 gint current_char_index;
2294 gint new_char_index;
2296 check_invariants (iter);
2298 current_char_index = gtk_text_iter_get_offset (iter);
2300 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2301 return FALSE; /* can't move forward */
2303 new_char_index = current_char_index + count;
2304 gtk_text_iter_set_offset (iter, new_char_index);
2306 check_invariants (iter);
2308 /* Return FALSE if we're on the non-dereferenceable end
2311 if (gtk_text_iter_is_end (iter))
2319 * gtk_text_iter_backward_chars:
2320 * @iter: an iterator
2321 * @count: number of characters to move
2323 * Moves @count characters backward, if possible (if @count would move
2324 * past the start or end of the buffer, moves to the start or end of
2325 * the buffer). The return value indicates whether the iterator moved
2326 * onto a dereferenceable position; if the iterator didn't move, or
2327 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2328 * the function does nothing and returns %FALSE.
2330 * Return value: whether @iter moved and is dereferenceable
2334 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2336 GtkTextRealIter *real;
2338 g_return_val_if_fail (iter != NULL, FALSE);
2340 FIX_OVERFLOWS (count);
2342 real = gtk_text_iter_make_real (iter);
2346 else if (count == 0)
2349 return gtk_text_iter_forward_chars (iter, 0 - count);
2351 ensure_char_offsets (real);
2352 check_invariants (iter);
2354 /* <, not <=, because if count == segment_char_offset
2355 * we're going to the front of the segment and the any_segment
2358 if (count < real->segment_char_offset)
2360 /* Optimize the within-segment case */
2361 g_assert (real->segment->char_count > 0);
2362 g_assert (real->segment->type == >k_text_char_type);
2364 if (real->line_byte_offset >= 0)
2367 gint new_byte_offset;
2369 /* if in the last fourth of the segment walk backwards */
2370 if (count < real->segment_char_offset / 4)
2371 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2374 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2375 real->segment_char_offset - count);
2377 new_byte_offset = p - real->segment->body.chars;
2378 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2379 real->segment_byte_offset = new_byte_offset;
2382 real->segment_char_offset -= count;
2383 real->line_char_offset -= count;
2385 adjust_char_index (real, 0 - count);
2387 check_invariants (iter);
2393 /* We need to go back into previous segments. For now,
2394 * just keep this really simple. FIXME
2395 * use backward_indexable_segment.
2397 if (TRUE || count > MAX_LINEAR_SCAN)
2399 gint current_char_index;
2400 gint new_char_index;
2402 current_char_index = gtk_text_iter_get_offset (iter);
2404 if (current_char_index == 0)
2405 return FALSE; /* can't move backward */
2407 new_char_index = current_char_index - count;
2408 if (new_char_index < 0)
2411 gtk_text_iter_set_offset (iter, new_char_index);
2413 check_invariants (iter);
2419 /* FIXME backward_indexable_segment here */
2428 /* These two can't be implemented efficiently (always have to use
2429 * a linear scan, since that's the only way to find all the non-text
2434 * gtk_text_iter_forward_text_chars:
2435 * @iter: a #GtkTextIter
2436 * @count: number of chars to move
2438 * Moves forward by @count text characters (pixbufs, widgets,
2439 * etc. do not count as characters for this). Equivalent to moving
2440 * through the results of gtk_text_iter_get_text (), rather than
2441 * gtk_text_iter_get_slice ().
2443 * Return value: whether @iter moved and is dereferenceable
2446 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2455 * gtk_text_iter_forward_text_chars:
2456 * @iter: a #GtkTextIter
2457 * @count: number of chars to move
2459 * Moves backward by @count text characters (pixbufs, widgets,
2460 * etc. do not count as characters for this). Equivalent to moving
2461 * through the results of gtk_text_iter_get_text (), rather than
2462 * gtk_text_iter_get_slice ().
2464 * Return value: whether @iter moved and is dereferenceable
2467 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2476 * gtk_text_iter_forward_line:
2477 * @iter: an iterator
2479 * Moves @iter to the start of the next line. If the iter is already on the
2480 * last line of the buffer, moves the iter to the end of the current line.
2481 * If after the operation, the iter is at the end of the buffer and not
2482 * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
2484 * Return value: whether @iter can be dereferenced
2487 gtk_text_iter_forward_line (GtkTextIter *iter)
2489 GtkTextRealIter *real;
2491 g_return_val_if_fail (iter != NULL, FALSE);
2493 real = gtk_text_iter_make_real (iter);
2498 check_invariants (iter);
2500 if (forward_line_leaving_caches_unmodified (real))
2502 invalidate_char_index (real);
2503 adjust_line_number (real, 1);
2505 check_invariants (iter);
2507 if (gtk_text_iter_is_end (iter))
2514 /* On the last line, move to end of it */
2516 if (!gtk_text_iter_is_end (iter))
2517 gtk_text_iter_forward_to_end (iter);
2519 check_invariants (iter);
2525 * gtk_text_iter_backward_line:
2526 * @iter: an iterator
2528 * Moves @iter to the start of the previous line. Returns %TRUE if
2529 * @iter could be moved; i.e. if @iter was at character offset 0, this
2530 * function returns %FALSE. Therefore if @iter was already on line 0,
2531 * but not at the start of the line, @iter is snapped to the start of
2532 * the line and the function returns %TRUE. (Note that this implies that
2533 * in a loop calling this function, the line number may not change on
2534 * every iteration, if your first iteration is on line 0.)
2536 * Return value: whether @iter moved
2539 gtk_text_iter_backward_line (GtkTextIter *iter)
2541 GtkTextLine *new_line;
2542 GtkTextRealIter *real;
2543 gboolean offset_will_change;
2546 g_return_val_if_fail (iter != NULL, FALSE);
2548 real = gtk_text_iter_make_real (iter);
2553 check_invariants (iter);
2555 new_line = _gtk_text_line_previous (real->line);
2557 offset_will_change = FALSE;
2558 if (real->line_char_offset > 0)
2559 offset_will_change = TRUE;
2561 if (new_line != NULL)
2563 real->line = new_line;
2565 adjust_line_number (real, -1);
2569 if (!offset_will_change)
2573 invalidate_char_index (real);
2575 real->line_byte_offset = 0;
2576 real->line_char_offset = 0;
2578 real->segment_byte_offset = 0;
2579 real->segment_char_offset = 0;
2581 /* Find first segment in line */
2582 real->any_segment = real->line->segments;
2583 real->segment = _gtk_text_line_byte_to_segment (real->line,
2586 g_assert (offset == 0);
2588 /* Note that if we are on the first line, we snap to the start of
2589 * the first line and return TRUE, so TRUE means the iterator
2590 * changed, not that the line changed; this is maybe a bit
2591 * weird. I'm not sure there's an obvious right thing to do though.
2594 check_invariants (iter);
2601 * gtk_text_iter_forward_lines:
2602 * @iter: a #GtkTextIter
2603 * @count: number of lines to move forward
2605 * Moves @count lines forward, if possible (if @count would move
2606 * past the start or end of the buffer, moves to the start or end of
2607 * the buffer). The return value indicates whether the iterator moved
2608 * onto a dereferenceable position; if the iterator didn't move, or
2609 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2610 * the function does nothing and returns %FALSE. If @count is negative,
2611 * moves backward by 0 - @count lines.
2613 * Return value: whether @iter moved and is dereferenceable
2616 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2618 FIX_OVERFLOWS (count);
2621 return gtk_text_iter_backward_lines (iter, 0 - count);
2622 else if (count == 0)
2624 else if (count == 1)
2626 check_invariants (iter);
2627 return gtk_text_iter_forward_line (iter);
2633 if (gtk_text_iter_is_end (iter))
2636 old_line = gtk_text_iter_get_line (iter);
2638 gtk_text_iter_set_line (iter, old_line + count);
2640 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2642 /* count went past the last line, so move to end of last line */
2643 if (!gtk_text_iter_is_end (iter))
2644 gtk_text_iter_forward_to_end (iter);
2647 return !gtk_text_iter_is_end (iter);
2652 * gtk_text_iter_backward_lines:
2653 * @iter: a #GtkTextIter
2654 * @count: number of lines to move backward
2656 * Moves @count lines backward, if possible (if @count would move
2657 * past the start or end of the buffer, moves to the start or end of
2658 * the buffer). The return value indicates whether the iterator moved
2659 * onto a dereferenceable position; if the iterator didn't move, or
2660 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2661 * the function does nothing and returns %FALSE. If @count is negative,
2662 * moves forward by 0 - @count lines.
2664 * Return value: whether @iter moved and is dereferenceable
2667 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2669 FIX_OVERFLOWS (count);
2672 return gtk_text_iter_forward_lines (iter, 0 - count);
2673 else if (count == 0)
2675 else if (count == 1)
2677 return gtk_text_iter_backward_line (iter);
2683 old_line = gtk_text_iter_get_line (iter);
2685 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2687 return (gtk_text_iter_get_line (iter) != old_line);
2692 * gtk_text_iter_forward_visible_line:
2693 * @iter: an iterator
2695 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2696 * was a next line to move to, and %FALSE if @iter was simply moved to
2697 * the end of the buffer and is now not dereferenceable, or if @iter was
2698 * already at the end of the buffer.
2700 * Return value: whether @iter can be dereferenced
2705 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2707 while (gtk_text_iter_forward_line (iter))
2709 if (!_gtk_text_btree_char_is_invisible (iter))
2715 if (!gtk_text_iter_forward_char (iter))
2718 if (!_gtk_text_btree_char_is_invisible (iter))
2721 while (!gtk_text_iter_ends_line (iter));
2729 * gtk_text_iter_backward_visible_line:
2730 * @iter: an iterator
2732 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2733 * @iter could be moved; i.e. if @iter was at character offset 0, this
2734 * function returns %FALSE. Therefore if @iter was already on line 0,
2735 * but not at the start of the line, @iter is snapped to the start of
2736 * the line and the function returns %TRUE. (Note that this implies that
2737 * in a loop calling this function, the line number may not change on
2738 * every iteration, if your first iteration is on line 0.)
2740 * Return value: whether @iter moved
2745 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2747 while (gtk_text_iter_backward_line (iter))
2749 if (!_gtk_text_btree_char_is_invisible (iter))
2755 if (!gtk_text_iter_backward_char (iter))
2758 if (!_gtk_text_btree_char_is_invisible (iter))
2761 while (!gtk_text_iter_starts_line (iter));
2769 * gtk_text_iter_forward_visible_lines:
2770 * @iter: a #GtkTextIter
2771 * @count: number of lines to move forward
2773 * Moves @count visible lines forward, if possible (if @count would move
2774 * past the start or end of the buffer, moves to the start or end of
2775 * the buffer). The return value indicates whether the iterator moved
2776 * onto a dereferenceable position; if the iterator didn't move, or
2777 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2778 * the function does nothing and returns %FALSE. If @count is negative,
2779 * moves backward by 0 - @count lines.
2781 * Return value: whether @iter moved and is dereferenceable
2786 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2789 FIX_OVERFLOWS (count);
2792 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2793 else if (count == 0)
2795 else if (count == 1)
2797 check_invariants (iter);
2798 return gtk_text_iter_forward_visible_line (iter);
2802 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2809 * gtk_text_iter_backward_visible_lines:
2810 * @iter: a #GtkTextIter
2811 * @count: number of lines to move backward
2813 * Moves @count visible lines backward, if possible (if @count would move
2814 * past the start or end of the buffer, moves to the start or end of
2815 * the buffer). The return value indicates whether the iterator moved
2816 * onto a dereferenceable position; if the iterator didn't move, or
2817 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2818 * the function does nothing and returns %FALSE. If @count is negative,
2819 * moves forward by 0 - @count lines.
2821 * Return value: whether @iter moved and is dereferenceable
2826 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2829 FIX_OVERFLOWS (count);
2832 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2833 else if (count == 0)
2835 else if (count == 1)
2837 return gtk_text_iter_backward_visible_line (iter);
2841 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2847 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2852 gboolean already_moved_initially);
2854 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2862 find_word_end_func (const PangoLogAttr *attrs,
2867 gboolean already_moved_initially)
2869 if (!already_moved_initially)
2872 /* Find end of next word */
2873 while (offset < min_offset + len &&
2874 !attrs[offset].is_word_end)
2877 *found_offset = offset;
2879 return offset < min_offset + len;
2883 is_word_end_func (const PangoLogAttr *attrs,
2888 return attrs[offset].is_word_end;
2892 find_word_start_func (const PangoLogAttr *attrs,
2897 gboolean already_moved_initially)
2899 if (!already_moved_initially)
2902 /* Find start of prev word */
2903 while (offset >= min_offset &&
2904 !attrs[offset].is_word_start)
2907 *found_offset = offset;
2909 return offset >= min_offset;
2913 is_word_start_func (const PangoLogAttr *attrs,
2918 return attrs[offset].is_word_start;
2922 inside_word_func (const PangoLogAttr *attrs,
2927 /* Find next word start or end */
2928 while (offset >= min_offset &&
2929 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2933 return attrs[offset].is_word_start;
2938 /* Sentence funcs */
2941 find_sentence_end_func (const PangoLogAttr *attrs,
2946 gboolean already_moved_initially)
2948 if (!already_moved_initially)
2951 /* Find end of next sentence */
2952 while (offset < min_offset + len &&
2953 !attrs[offset].is_sentence_end)
2956 *found_offset = offset;
2958 return offset < min_offset + len;
2962 is_sentence_end_func (const PangoLogAttr *attrs,
2967 return attrs[offset].is_sentence_end;
2971 find_sentence_start_func (const PangoLogAttr *attrs,
2976 gboolean already_moved_initially)
2978 if (!already_moved_initially)
2981 /* Find start of prev sentence */
2982 while (offset >= min_offset &&
2983 !attrs[offset].is_sentence_start)
2986 *found_offset = offset;
2988 return offset >= min_offset;
2992 is_sentence_start_func (const PangoLogAttr *attrs,
2997 return attrs[offset].is_sentence_start;
3001 inside_sentence_func (const PangoLogAttr *attrs,
3006 /* Find next sentence start or end */
3007 while (offset >= min_offset &&
3008 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3011 return attrs[offset].is_sentence_start;
3015 test_log_attrs (const GtkTextIter *iter,
3016 TestLogAttrFunc func)
3019 const PangoLogAttr *attrs;
3021 gboolean result = FALSE;
3023 g_return_val_if_fail (iter != NULL, FALSE);
3025 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3028 offset = gtk_text_iter_get_line_offset (iter);
3030 /* char_len may be 0 and attrs will be NULL if so, if
3031 * iter is the end iter and the last line is empty.
3033 * offset may be equal to char_len, since attrs contains an entry
3034 * for one past the end
3037 if (attrs && offset <= char_len)
3038 result = (* func) (attrs, offset, 0, char_len);
3044 find_line_log_attrs (const GtkTextIter *iter,
3045 FindLogAttrFunc func,
3047 gboolean already_moved_initially)
3050 const PangoLogAttr *attrs;
3052 gboolean result = FALSE;
3054 g_return_val_if_fail (iter != NULL, FALSE);
3056 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3059 offset = gtk_text_iter_get_line_offset (iter);
3061 /* char_len may be 0 and attrs will be NULL if so, if
3062 * iter is the end iter and the last line is empty
3066 result = (* func) (attrs, offset, 0, char_len, found_offset,
3067 already_moved_initially);
3072 /* FIXME this function is very, very gratuitously slow */
3074 find_by_log_attrs (GtkTextIter *iter,
3075 FindLogAttrFunc func,
3077 gboolean already_moved_initially)
3081 gboolean found = FALSE;
3083 g_return_val_if_fail (iter != NULL, FALSE);
3087 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3093 if (gtk_text_iter_forward_line (iter))
3094 return find_by_log_attrs (iter, func, forward,
3101 /* go to end of previous line. need to check that
3102 * line is > 0 because backward_line snaps to start of
3103 * line 0 if it's on line 0
3105 if (gtk_text_iter_get_line (iter) > 0 &&
3106 gtk_text_iter_backward_line (iter))
3108 if (!gtk_text_iter_ends_line (iter))
3109 gtk_text_iter_forward_to_line_end (iter);
3111 return find_by_log_attrs (iter, func, forward,
3120 gtk_text_iter_set_line_offset (iter, offset);
3123 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3124 !gtk_text_iter_is_end (iter);
3129 find_visible_by_log_attrs (GtkTextIter *iter,
3130 FindLogAttrFunc func,
3132 gboolean already_moved_initially)
3136 g_return_val_if_fail (iter != NULL, FALSE);
3140 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3142 if (!_gtk_text_btree_char_is_invisible (&pos))
3152 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3153 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3156 move_multiple_steps (GtkTextIter *iter,
3158 OneStepFunc step_forward,
3159 MultipleStepFunc n_steps_backward)
3161 g_return_val_if_fail (iter != NULL, FALSE);
3163 FIX_OVERFLOWS (count);
3169 return n_steps_backward (iter, -count);
3171 if (!step_forward (iter))
3177 if (!step_forward (iter))
3182 return !gtk_text_iter_is_end (iter);
3187 * gtk_text_iter_forward_word_end:
3188 * @iter: a #GtkTextIter
3190 * Moves forward to the next word end. (If @iter is currently on a
3191 * word end, moves forward to the next one after that.) Word breaks
3192 * are determined by Pango and should be correct for nearly any
3193 * language (if not, the correct fix would be to the Pango word break
3196 * Return value: %TRUE if @iter moved and is not the end iterator
3199 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3201 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3205 * gtk_text_iter_backward_word_start:
3206 * @iter: a #GtkTextIter
3208 * Moves backward to the previous word start. (If @iter is currently on a
3209 * word start, moves backward to the next one after that.) Word breaks
3210 * are determined by Pango and should be correct for nearly any
3211 * language (if not, the correct fix would be to the Pango word break
3214 * Return value: %TRUE if @iter moved and is not the end iterator
3217 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3219 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3222 /* FIXME a loop around a truly slow function means
3223 * a truly spectacularly slow function.
3227 * gtk_text_iter_forward_word_ends:
3228 * @iter: a #GtkTextIter
3229 * @count: number of times to move
3231 * Calls gtk_text_iter_forward_word_end() up to @count times.
3233 * Return value: %TRUE if @iter moved and is not the end iterator
3236 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3239 return move_multiple_steps (iter, count,
3240 gtk_text_iter_forward_word_end,
3241 gtk_text_iter_backward_word_starts);
3245 * gtk_text_iter_backward_word_starts:
3246 * @iter: a #GtkTextIter
3247 * @count: number of times to move
3249 * Calls gtk_text_iter_backward_word_start() up to @count times.
3251 * Return value: %TRUE if @iter moved and is not the end iterator
3254 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3257 return move_multiple_steps (iter, count,
3258 gtk_text_iter_backward_word_start,
3259 gtk_text_iter_forward_word_ends);
3263 * gtk_text_iter_forward_visible_word_end:
3264 * @iter: a #GtkTextIter
3266 * Moves forward to the next visible word end. (If @iter is currently on a
3267 * word end, moves forward to the next one after that.) Word breaks
3268 * are determined by Pango and should be correct for nearly any
3269 * language (if not, the correct fix would be to the Pango word break
3272 * Return value: %TRUE if @iter moved and is not the end iterator
3277 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3279 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3283 * gtk_text_iter_backward_visible_word_start:
3284 * @iter: a #GtkTextIter
3286 * Moves backward to the previous visible word start. (If @iter is currently
3287 * on a word start, moves backward to the next one after that.) Word breaks
3288 * are determined by Pango and should be correct for nearly any
3289 * language (if not, the correct fix would be to the Pango word break
3292 * Return value: %TRUE if @iter moved and is not the end iterator
3297 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3299 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3303 * gtk_text_iter_forward_visible_word_ends:
3304 * @iter: a #GtkTextIter
3305 * @count: number of times to move
3307 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3309 * Return value: %TRUE if @iter moved and is not the end iterator
3314 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3317 return move_multiple_steps (iter, count,
3318 gtk_text_iter_forward_visible_word_end,
3319 gtk_text_iter_backward_visible_word_starts);
3323 * gtk_text_iter_backward_visible_word_starts:
3324 * @iter: a #GtkTextIter
3325 * @count: number of times to move
3327 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3329 * Return value: %TRUE if @iter moved and is not the end iterator
3334 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3337 return move_multiple_steps (iter, count,
3338 gtk_text_iter_backward_visible_word_start,
3339 gtk_text_iter_forward_visible_word_ends);
3343 * gtk_text_iter_starts_word:
3344 * @iter: a #GtkTextIter
3346 * Determines whether @iter begins a natural-language word. Word
3347 * breaks are determined by Pango and should be correct for nearly any
3348 * language (if not, the correct fix would be to the Pango word break
3351 * Return value: %TRUE if @iter is at the start of a word
3354 gtk_text_iter_starts_word (const GtkTextIter *iter)
3356 return test_log_attrs (iter, is_word_start_func);
3360 * gtk_text_iter_ends_word:
3361 * @iter: a #GtkTextIter
3363 * Determines whether @iter ends a natural-language word. Word breaks
3364 * are determined by Pango and should be correct for nearly any
3365 * language (if not, the correct fix would be to the Pango word break
3368 * Return value: %TRUE if @iter is at the end of a word
3371 gtk_text_iter_ends_word (const GtkTextIter *iter)
3373 return test_log_attrs (iter, is_word_end_func);
3377 * gtk_text_iter_inside_word:
3378 * @iter: a #GtkTextIter
3380 * Determines whether @iter is inside a natural-language word (as
3381 * opposed to say inside some whitespace). Word breaks are determined
3382 * by Pango and should be correct for nearly any language (if not, the
3383 * correct fix would be to the Pango word break algorithms).
3385 * Return value: %TRUE if @iter is inside a word
3388 gtk_text_iter_inside_word (const GtkTextIter *iter)
3390 return test_log_attrs (iter, inside_word_func);
3394 * gtk_text_iter_starts_sentence:
3395 * @iter: a #GtkTextIter
3397 * Determines whether @iter begins a sentence. Sentence boundaries are
3398 * determined by Pango and should be correct for nearly any language
3399 * (if not, the correct fix would be to the Pango text boundary
3402 * Return value: %TRUE if @iter is at the start of a sentence.
3405 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3407 return test_log_attrs (iter, is_sentence_start_func);
3411 * gtk_text_iter_ends_sentence:
3412 * @iter: a #GtkTextIter
3414 * Determines whether @iter ends a sentence. Sentence boundaries are
3415 * determined by Pango and should be correct for nearly any language
3416 * (if not, the correct fix would be to the Pango text boundary
3419 * Return value: %TRUE if @iter is at the end of a sentence.
3422 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3424 return test_log_attrs (iter, is_sentence_end_func);
3428 * gtk_text_iter_inside_sentence:
3429 * @iter: a #GtkTextIter
3431 * Determines whether @iter is inside a sentence (as opposed to in
3432 * between two sentences, e.g. after a period and before the first
3433 * letter of the next sentence). Sentence boundaries are determined
3434 * by Pango and should be correct for nearly any language (if not, the
3435 * correct fix would be to the Pango text boundary algorithms).
3437 * Return value: %TRUE if @iter is inside a sentence.
3440 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3442 return test_log_attrs (iter, inside_sentence_func);
3446 * gtk_text_iter_forward_sentence_end:
3447 * @iter: a #GtkTextIter
3449 * Moves forward to the next sentence end. (If @iter is at the end of
3450 * a sentence, moves to the next end of sentence.) Sentence
3451 * boundaries are determined by Pango and should be correct for nearly
3452 * any language (if not, the correct fix would be to the Pango text
3453 * boundary algorithms).
3455 * Return value: %TRUE if @iter moved and is not the end iterator
3458 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3460 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3464 * gtk_text_iter_backward_sentence_start:
3465 * @iter: a #GtkTextIter
3467 * Moves backward to the previous sentence start; if @iter is already at
3468 * the start of a sentence, moves backward to the next one. Sentence
3469 * boundaries are determined by Pango and should be correct for nearly
3470 * any language (if not, the correct fix would be to the Pango text
3471 * boundary algorithms).
3473 * Return value: %TRUE if @iter moved and is not the end iterator
3476 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3478 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3481 /* FIXME a loop around a truly slow function means
3482 * a truly spectacularly slow function.
3485 * gtk_text_iter_forward_sentence_ends:
3486 * @iter: a #GtkTextIter
3487 * @count: number of sentences to move
3489 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3490 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3491 * negative, moves backward instead of forward.
3493 * Return value: %TRUE if @iter moved and is not the end iterator
3496 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3499 return move_multiple_steps (iter, count,
3500 gtk_text_iter_forward_sentence_end,
3501 gtk_text_iter_backward_sentence_starts);
3505 * gtk_text_iter_backward_sentence_starts:
3506 * @iter: a #GtkTextIter
3507 * @count: number of sentences to move
3509 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3510 * or until it returns %FALSE. If @count is negative, moves forward
3511 * instead of backward.
3513 * Return value: %TRUE if @iter moved and is not the end iterator
3516 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3519 return move_multiple_steps (iter, count,
3520 gtk_text_iter_backward_sentence_start,
3521 gtk_text_iter_forward_sentence_ends);
3525 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3530 gboolean already_moved_initially)
3532 if (!already_moved_initially)
3535 while (offset < (min_offset + len) &&
3536 !attrs[offset].is_cursor_position)
3539 *found_offset = offset;
3541 return offset < (min_offset + len);
3545 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3550 gboolean already_moved_initially)
3552 if (!already_moved_initially)
3555 while (offset > min_offset &&
3556 !attrs[offset].is_cursor_position)
3559 *found_offset = offset;
3561 return offset >= min_offset;
3565 is_cursor_pos_func (const PangoLogAttr *attrs,
3570 return attrs[offset].is_cursor_position;
3574 * gtk_text_iter_forward_cursor_position:
3575 * @iter: a #GtkTextIter
3577 * Moves @iter forward by a single cursor position. Cursor positions
3578 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3579 * surprisingly, there may not be a cursor position between all
3580 * characters. The most common example for European languages would be
3581 * a carriage return/newline sequence. For some Unicode characters,
3582 * the equivalent of say the letter "a" with an accent mark will be
3583 * represented as two characters, first the letter then a "combining
3584 * mark" that causes the accent to be rendered; so the cursor can't go
3585 * between those two characters. See also the #PangoLogAttr structure and
3586 * pango_break() function.
3588 * Return value: %TRUE if we moved and the new position is dereferenceable
3591 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3593 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3597 * gtk_text_iter_backward_cursor_position:
3598 * @iter: a #GtkTextIter
3600 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3602 * Return value: %TRUE if we moved
3605 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3607 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3611 * gtk_text_iter_forward_cursor_positions:
3612 * @iter: a #GtkTextIter
3613 * @count: number of positions to move
3615 * Moves up to @count cursor positions. See
3616 * gtk_text_iter_forward_cursor_position() for details.
3618 * Return value: %TRUE if we moved and the new position is dereferenceable
3621 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3624 return move_multiple_steps (iter, count,
3625 gtk_text_iter_forward_cursor_position,
3626 gtk_text_iter_backward_cursor_positions);
3630 * gtk_text_iter_backward_cursor_positions:
3631 * @iter: a #GtkTextIter
3632 * @count: number of positions to move
3634 * Moves up to @count cursor positions. See
3635 * gtk_text_iter_forward_cursor_position() for details.
3637 * Return value: %TRUE if we moved and the new position is dereferenceable
3640 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3643 return move_multiple_steps (iter, count,
3644 gtk_text_iter_backward_cursor_position,
3645 gtk_text_iter_forward_cursor_positions);
3649 * gtk_text_iter_forward_visible_cursor_position:
3650 * @iter: a #GtkTextIter
3652 * Moves @iter forward to the next visible cursor position. See
3653 * gtk_text_iter_forward_cursor_position() for details.
3655 * Return value: %TRUE if we moved and the new position is dereferenceable
3660 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3662 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3666 * gtk_text_iter_backward_visible_cursor_position:
3667 * @iter: a #GtkTextIter
3669 * Moves @iter forward to the previous visible cursor position. See
3670 * gtk_text_iter_backward_cursor_position() for details.
3672 * Return value: %TRUE if we moved and the new position is dereferenceable
3677 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3679 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3683 * gtk_text_iter_forward_visible_cursor_positions:
3684 * @iter: a #GtkTextIter
3685 * @count: number of positions to move
3687 * Moves up to @count visible cursor positions. See
3688 * gtk_text_iter_forward_cursor_position() for details.
3690 * Return value: %TRUE if we moved and the new position is dereferenceable
3695 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3698 return move_multiple_steps (iter, count,
3699 gtk_text_iter_forward_visible_cursor_position,
3700 gtk_text_iter_backward_visible_cursor_positions);
3704 * gtk_text_iter_backward_visible_cursor_positions:
3705 * @iter: a #GtkTextIter
3706 * @count: number of positions to move
3708 * Moves up to @count visible cursor positions. See
3709 * gtk_text_iter_backward_cursor_position() for details.
3711 * Return value: %TRUE if we moved and the new position is dereferenceable
3716 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3719 return move_multiple_steps (iter, count,
3720 gtk_text_iter_backward_visible_cursor_position,
3721 gtk_text_iter_forward_visible_cursor_positions);
3725 * gtk_text_iter_is_cursor_position:
3726 * @iter: a #GtkTextIter
3728 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3729 * pango_break() for details on what a cursor position is.
3731 * Return value: %TRUE if the cursor can be placed at @iter
3734 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3736 return test_log_attrs (iter, is_cursor_pos_func);
3740 * gtk_text_iter_set_line_offset:
3741 * @iter: a #GtkTextIter
3742 * @char_on_line: a character offset relative to the start of @iter's current line
3744 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3745 * (not byte) offset. The given character offset must be less than or
3746 * equal to the number of characters in the line; if equal, @iter
3747 * moves to the start of the next line. See
3748 * gtk_text_iter_set_line_index() if you have a byte index rather than
3749 * a character offset.
3753 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3756 GtkTextRealIter *real;
3759 g_return_if_fail (iter != NULL);
3761 real = gtk_text_iter_make_surreal (iter);
3766 check_invariants (iter);
3768 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3770 g_return_if_fail (char_on_line <= chars_in_line);
3772 if (char_on_line < chars_in_line)
3773 iter_set_from_char_offset (real, real->line, char_on_line);
3775 gtk_text_iter_forward_line (iter); /* set to start of next line */
3777 check_invariants (iter);
3781 * gtk_text_iter_set_line_index:
3782 * @iter: a #GtkTextIter
3783 * @byte_on_line: a byte index relative to the start of @iter's current line
3785 * Same as gtk_text_iter_set_line_offset(), but works with a
3786 * <emphasis>byte</emphasis> index. The given byte index must be at
3787 * the start of a character, it can't be in the middle of a UTF-8
3788 * encoded character.
3792 gtk_text_iter_set_line_index (GtkTextIter *iter,
3795 GtkTextRealIter *real;
3798 g_return_if_fail (iter != NULL);
3800 real = gtk_text_iter_make_surreal (iter);
3805 check_invariants (iter);
3807 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3809 g_return_if_fail (byte_on_line <= bytes_in_line);
3811 if (byte_on_line < bytes_in_line)
3812 iter_set_from_byte_offset (real, real->line, byte_on_line);
3814 gtk_text_iter_forward_line (iter);
3816 if (real->segment->type == >k_text_char_type &&
3817 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3818 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3819 "character; this will crash the text buffer. "
3820 "Byte indexes must refer to the start of a character.",
3821 G_STRLOC, byte_on_line);
3823 check_invariants (iter);
3828 * gtk_text_iter_set_visible_line_offset:
3829 * @iter: a #GtkTextIter
3830 * @char_on_line: a character offset
3832 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3833 * characters, i.e. text with a tag making it invisible is not
3834 * counted in the offset.
3837 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3840 gint chars_seen = 0;
3843 g_return_if_fail (iter != NULL);
3845 gtk_text_iter_set_line_offset (iter, 0);
3849 /* For now we use a ludicrously slow implementation */
3850 while (chars_seen < char_on_line)
3852 if (!_gtk_text_btree_char_is_invisible (&pos))
3855 if (!gtk_text_iter_forward_char (&pos))
3858 if (chars_seen == char_on_line)
3862 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3865 gtk_text_iter_forward_line (iter);
3869 * gtk_text_iter_set_visible_line_index:
3870 * @iter: a #GtkTextIter
3871 * @byte_on_line: a byte index
3873 * Like gtk_text_iter_set_line_index(), but the index is in visible
3874 * bytes, i.e. text with a tag making it invisible is not counted
3878 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3881 GtkTextRealIter *real;
3884 GtkTextLineSegment *seg;
3886 g_return_if_fail (iter != NULL);
3888 gtk_text_iter_set_line_offset (iter, 0);
3892 real = gtk_text_iter_make_real (&pos);
3897 ensure_byte_offsets (real);
3899 check_invariants (&pos);
3901 seg = _gtk_text_iter_get_indexable_segment (&pos);
3903 while (seg != NULL && byte_on_line > 0)
3905 if (!_gtk_text_btree_char_is_invisible (&pos))
3907 if (byte_on_line < seg->byte_count)
3909 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3914 byte_on_line -= seg->byte_count;
3917 offset += seg->byte_count;
3918 _gtk_text_iter_forward_indexable_segment (&pos);
3919 seg = _gtk_text_iter_get_indexable_segment (&pos);
3922 if (byte_on_line == 0)
3925 gtk_text_iter_forward_line (iter);
3929 * gtk_text_iter_set_line:
3930 * @iter: a #GtkTextIter
3931 * @line_number: line number (counted from 0)
3933 * Moves iterator @iter to the start of the line @line_number. If
3934 * @line_number is negative or larger than the number of lines in the
3935 * buffer, moves @iter to the start of the last line in the buffer.
3939 gtk_text_iter_set_line (GtkTextIter *iter,
3944 GtkTextRealIter *real;
3946 g_return_if_fail (iter != NULL);
3948 real = gtk_text_iter_make_surreal (iter);
3953 check_invariants (iter);
3955 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3957 iter_set_from_char_offset (real, line, 0);
3959 /* We might as well cache this, since we know it. */
3960 real->cached_line_number = real_line;
3962 check_invariants (iter);
3966 * gtk_text_iter_set_offset:
3967 * @iter: a #GtkTextIter
3968 * @char_offset: a character number
3970 * Sets @iter to point to @char_offset. @char_offset counts from the start
3971 * of the entire text buffer, starting with 0.
3974 gtk_text_iter_set_offset (GtkTextIter *iter,
3978 GtkTextRealIter *real;
3980 gint real_char_index;
3982 g_return_if_fail (iter != NULL);
3984 real = gtk_text_iter_make_surreal (iter);
3989 check_invariants (iter);
3991 if (real->cached_char_index >= 0 &&
3992 real->cached_char_index == char_offset)
3995 line = _gtk_text_btree_get_line_at_char (real->tree,
4000 iter_set_from_char_offset (real, line, real_char_index - line_start);
4002 /* Go ahead and cache this since we have it. */
4003 real->cached_char_index = real_char_index;
4005 check_invariants (iter);
4009 * gtk_text_iter_forward_to_end:
4010 * @iter: a #GtkTextIter
4012 * Moves @iter forward to the "end iterator," which points one past the last
4013 * valid character in the buffer. gtk_text_iter_get_char() called on the
4014 * end iterator returns 0, which is convenient for writing loops.
4017 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4019 GtkTextBuffer *buffer;
4020 GtkTextRealIter *real;
4022 g_return_if_fail (iter != NULL);
4024 real = gtk_text_iter_make_surreal (iter);
4029 buffer = _gtk_text_btree_get_buffer (real->tree);
4031 gtk_text_buffer_get_end_iter (buffer, iter);
4034 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4035 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4036 * If all else fails we could cache the para delimiter pos in the iter.
4037 * I think forward_to_line_end() actually gets called fairly often.
4040 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4045 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4046 _gtk_text_iter_get_btree (&end)))
4048 gtk_text_iter_forward_to_end (&end);
4052 /* if we aren't on the last line, go forward to start of next line, then scan
4053 * back for the delimiters on the previous line
4055 gtk_text_iter_forward_line (&end);
4056 gtk_text_iter_backward_char (&end);
4057 while (!gtk_text_iter_ends_line (&end))
4058 gtk_text_iter_backward_char (&end);
4061 return gtk_text_iter_get_line_offset (&end);
4065 * gtk_text_iter_forward_to_line_end:
4066 * @iter: a #GtkTextIter
4068 * Moves the iterator to point to the paragraph delimiter characters,
4069 * which will be either a newline, a carriage return, a carriage
4070 * return/newline in sequence, or the Unicode paragraph separator
4071 * character. If the iterator is already at the paragraph delimiter
4072 * characters, moves to the paragraph delimiter characters for the
4073 * next line. If @iter is on the last line in the buffer, which does
4074 * not end in paragraph delimiters, moves to the end iterator (end of
4075 * the last line), and returns %FALSE.
4077 * Return value: %TRUE if we moved and the new location is not the end iterator
4080 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4082 gint current_offset;
4086 g_return_val_if_fail (iter != NULL, FALSE);
4088 current_offset = gtk_text_iter_get_line_offset (iter);
4089 new_offset = find_paragraph_delimiter_for_line (iter);
4091 if (current_offset < new_offset)
4093 /* Move to end of this line. */
4094 gtk_text_iter_set_line_offset (iter, new_offset);
4095 return !gtk_text_iter_is_end (iter);
4099 /* Move to end of next line. */
4100 if (gtk_text_iter_forward_line (iter))
4102 /* We don't want to move past all
4105 if (!gtk_text_iter_ends_line (iter))
4106 gtk_text_iter_forward_to_line_end (iter);
4107 return !gtk_text_iter_is_end (iter);
4115 * gtk_text_iter_forward_to_tag_toggle:
4116 * @iter: a #GtkTextIter
4117 * @tag: (allow-none): a #GtkTextTag, or %NULL
4119 * Moves forward to the next toggle (on or off) of the
4120 * #GtkTextTag @tag, or to the next toggle of any tag if
4121 * @tag is %NULL. If no matching tag toggles are found,
4122 * returns %FALSE, otherwise %TRUE. Does not return toggles
4123 * located at @iter, only toggles after @iter. Sets @iter to
4124 * the location of the toggle, or to the end of the buffer
4125 * if no toggle is found.
4127 * Return value: whether we found a tag toggle after @iter
4130 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4133 GtkTextLine *next_line;
4134 GtkTextLine *current_line;
4135 GtkTextRealIter *real;
4137 g_return_val_if_fail (iter != NULL, FALSE);
4139 real = gtk_text_iter_make_real (iter);
4144 check_invariants (iter);
4146 current_line = real->line;
4147 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4150 while (_gtk_text_iter_forward_indexable_segment (iter))
4152 /* If we went forward to a line that couldn't contain a toggle
4153 for the tag, then skip forward to a line that could contain
4154 it. This potentially skips huge hunks of the tree, so we
4155 aren't a purely linear search. */
4156 if (real->line != current_line)
4158 if (next_line == NULL)
4160 /* End of search. Set to end of buffer. */
4161 _gtk_text_btree_get_end_iter (real->tree, iter);
4165 if (real->line != next_line)
4166 iter_set_from_byte_offset (real, next_line, 0);
4168 current_line = real->line;
4169 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4174 if (gtk_text_iter_toggles_tag (iter, tag))
4176 /* If there's a toggle here, it isn't indexable so
4177 any_segment can't be the indexable segment. */
4178 g_assert (real->any_segment != real->segment);
4183 /* Check end iterator for tags */
4184 if (gtk_text_iter_toggles_tag (iter, tag))
4186 /* If there's a toggle here, it isn't indexable so
4187 any_segment can't be the indexable segment. */
4188 g_assert (real->any_segment != real->segment);
4192 /* Reached end of buffer */
4197 * gtk_text_iter_backward_to_tag_toggle:
4198 * @iter: a #GtkTextIter
4199 * @tag: (allow-none): a #GtkTextTag, or %NULL
4201 * Moves backward to the next toggle (on or off) of the
4202 * #GtkTextTag @tag, or to the next toggle of any tag if
4203 * @tag is %NULL. If no matching tag toggles are found,
4204 * returns %FALSE, otherwise %TRUE. Does not return toggles
4205 * located at @iter, only toggles before @iter. Sets @iter
4206 * to the location of the toggle, or the start of the buffer
4207 * if no toggle is found.
4209 * Return value: whether we found a tag toggle before @iter
4212 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4215 GtkTextLine *prev_line;
4216 GtkTextLine *current_line;
4217 GtkTextRealIter *real;
4219 g_return_val_if_fail (iter != NULL, FALSE);
4221 real = gtk_text_iter_make_real (iter);
4226 check_invariants (iter);
4228 current_line = real->line;
4229 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4233 /* If we're at segment start, go to the previous segment;
4234 * if mid-segment, snap to start of current segment.
4236 if (is_segment_start (real))
4238 if (!_gtk_text_iter_backward_indexable_segment (iter))
4243 ensure_char_offsets (real);
4245 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4251 /* If we went backward to a line that couldn't contain a toggle
4252 * for the tag, then skip backward further to a line that
4253 * could contain it. This potentially skips huge hunks of the
4254 * tree, so we aren't a purely linear search.
4256 if (real->line != current_line)
4258 if (prev_line == NULL)
4260 /* End of search. Set to start of buffer. */
4261 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4265 if (real->line != prev_line)
4267 /* Set to last segment in prev_line (could do this
4270 iter_set_from_byte_offset (real, prev_line, 0);
4272 while (!at_last_indexable_segment (real))
4273 _gtk_text_iter_forward_indexable_segment (iter);
4276 current_line = real->line;
4277 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4282 if (gtk_text_iter_toggles_tag (iter, tag))
4284 /* If there's a toggle here, it isn't indexable so
4285 * any_segment can't be the indexable segment.
4287 g_assert (real->any_segment != real->segment);
4291 while (_gtk_text_iter_backward_indexable_segment (iter));
4293 /* Reached front of buffer */
4298 matches_pred (GtkTextIter *iter,
4299 GtkTextCharPredicate pred,
4304 ch = gtk_text_iter_get_char (iter);
4306 return (*pred) (ch, user_data);
4310 * gtk_text_iter_forward_find_char:
4311 * @iter: a #GtkTextIter
4312 * @pred: (scope call): a function to be called on each character
4313 * @user_data: user data for @pred
4314 * @limit: (allow-none): search limit, or %NULL for none
4316 * Advances @iter, calling @pred on each character. If
4317 * @pred returns %TRUE, returns %TRUE and stops scanning.
4318 * If @pred never returns %TRUE, @iter is set to @limit if
4319 * @limit is non-%NULL, otherwise to the end iterator.
4321 * Return value: whether a match was found
4324 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4325 GtkTextCharPredicate pred,
4327 const GtkTextIter *limit)
4329 g_return_val_if_fail (iter != NULL, FALSE);
4330 g_return_val_if_fail (pred != NULL, FALSE);
4333 gtk_text_iter_compare (iter, limit) >= 0)
4336 while ((limit == NULL ||
4337 !gtk_text_iter_equal (limit, iter)) &&
4338 gtk_text_iter_forward_char (iter))
4340 if (matches_pred (iter, pred, user_data))
4348 * gtk_text_iter_backward_find_char:
4349 * @iter: a #GtkTextIter
4350 * @pred: (scope call): function to be called on each character
4351 * @user_data: user data for @pred
4352 * @limit: (allow-none): search limit, or %NULL for none
4354 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4356 * Return value: whether a match was found
4359 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4360 GtkTextCharPredicate pred,
4362 const GtkTextIter *limit)
4364 g_return_val_if_fail (iter != NULL, FALSE);
4365 g_return_val_if_fail (pred != NULL, FALSE);
4368 gtk_text_iter_compare (iter, limit) <= 0)
4371 while ((limit == NULL ||
4372 !gtk_text_iter_equal (limit, iter)) &&
4373 gtk_text_iter_backward_char (iter))
4375 if (matches_pred (iter, pred, user_data))
4383 forward_chars_with_skipping (GtkTextIter *iter,
4385 gboolean skip_invisible,
4386 gboolean skip_nontext,
4387 gboolean skip_decomp)
4392 g_return_if_fail (count >= 0);
4398 gboolean ignored = FALSE;
4400 /* minimal workaround to avoid the infinite loop of bug #168247. */
4401 if (gtk_text_iter_is_end (iter))
4405 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4410 _gtk_text_btree_char_is_invisible (iter))
4413 if (!ignored && skip_decomp)
4415 /* being UTF8 correct sucks: this accounts for extra
4416 offsets coming from canonical decompositions of
4417 UTF8 characters (e.g. accented characters) which
4418 g_utf8_normalize() performs */
4424 buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
4425 casefold = g_utf8_casefold (buffer, buffer_len);
4426 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4427 i -= (g_utf8_strlen (normal, -1) - 1);
4432 gtk_text_iter_forward_char (iter);
4439 static const gchar *
4440 pointer_from_offset_skipping_decomp (const gchar *str,
4443 gchar *casefold, *normal;
4450 q = g_utf8_next_char (p);
4451 casefold = g_utf8_casefold (p, q - p);
4452 normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4453 offset -= g_utf8_strlen (normal, -1);
4463 exact_prefix_cmp (const gchar *string,
4464 const gchar *prefix,
4469 if (strncmp (string, prefix, prefix_len) != 0)
4471 if (string[prefix_len] == '\0')
4474 type = g_unichar_type (g_utf8_get_char (string + prefix_len));
4476 /* If string contains prefix, check that prefix is not followed
4477 * by a unicode mark symbol, e.g. that trailing 'a' in prefix
4478 * is not part of two-char a-with-hat symbol in string. */
4479 return type != G_UNICODE_COMBINING_MARK &&
4480 type != G_UNICODE_ENCLOSING_MARK &&
4481 type != G_UNICODE_NON_SPACING_MARK;
4484 static const gchar *
4485 utf8_strcasestr (const gchar *haystack,
4486 const gchar *needle)
4490 const gchar *ret = NULL;
4493 gchar *caseless_haystack;
4496 g_return_val_if_fail (haystack != NULL, NULL);
4497 g_return_val_if_fail (needle != NULL, NULL);
4499 casefold = g_utf8_casefold (haystack, -1);
4500 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4503 needle_len = g_utf8_strlen (needle, -1);
4504 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4506 if (needle_len == 0)
4508 ret = (gchar *)haystack;
4512 if (haystack_len < needle_len)
4518 p = (gchar *)caseless_haystack;
4519 needle_len = strlen (needle);
4524 if (exact_prefix_cmp (p, needle, needle_len))
4526 ret = pointer_from_offset_skipping_decomp (haystack, i);
4530 p = g_utf8_next_char (p);
4535 g_free (caseless_haystack);
4540 static const gchar *
4541 utf8_strrcasestr (const gchar *haystack,
4542 const gchar *needle)
4546 const gchar *ret = NULL;
4549 gchar *caseless_haystack;
4552 g_return_val_if_fail (haystack != NULL, NULL);
4553 g_return_val_if_fail (needle != NULL, NULL);
4555 casefold = g_utf8_casefold (haystack, -1);
4556 caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4559 needle_len = g_utf8_strlen (needle, -1);
4560 haystack_len = g_utf8_strlen (caseless_haystack, -1);
4562 if (needle_len == 0)
4564 ret = (gchar *)haystack;
4568 if (haystack_len < needle_len)
4574 i = haystack_len - needle_len;
4575 p = g_utf8_offset_to_pointer (caseless_haystack, i);
4576 needle_len = strlen (needle);
4578 while (p >= caseless_haystack)
4580 if (exact_prefix_cmp (p, needle, needle_len))
4582 ret = pointer_from_offset_skipping_decomp (haystack, i);
4586 p = g_utf8_prev_char (p);
4591 g_free (caseless_haystack);
4596 /* normalizes caseless strings and returns true if @s2 matches
4599 utf8_caselessnmatch (const gchar *s1,
4605 gchar *normalized_s1;
4606 gchar *normalized_s2;
4609 gboolean ret = FALSE;
4611 g_return_val_if_fail (s1 != NULL, FALSE);
4612 g_return_val_if_fail (s2 != NULL, FALSE);
4613 g_return_val_if_fail (n1 > 0, FALSE);
4614 g_return_val_if_fail (n2 > 0, FALSE);
4616 casefold = g_utf8_casefold (s1, n1);
4617 normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4620 casefold = g_utf8_casefold (s2, n2);
4621 normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4624 len_s1 = strlen (normalized_s1);
4625 len_s2 = strlen (normalized_s2);
4627 if (len_s1 >= len_s2)
4628 ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
4630 g_free (normalized_s1);
4631 g_free (normalized_s2);
4637 lines_match (const GtkTextIter *start,
4638 const gchar **lines,
4639 gboolean visible_only,
4641 gboolean case_insensitive,
4642 GtkTextIter *match_start,
4643 GtkTextIter *match_end)
4650 if (*lines == NULL || **lines == '\0')
4653 *match_start = *start;
4656 *match_end = *start;
4661 gtk_text_iter_forward_line (&next);
4663 /* No more text in buffer, but *lines is nonempty */
4664 if (gtk_text_iter_equal (start, &next))
4672 line_text = gtk_text_iter_get_visible_slice (start, &next);
4674 line_text = gtk_text_iter_get_slice (start, &next);
4679 line_text = gtk_text_iter_get_visible_text (start, &next);
4681 line_text = gtk_text_iter_get_text (start, &next);
4684 if (match_start) /* if this is the first line we're matching */
4686 if (!case_insensitive)
4687 found = strstr (line_text, *lines);
4689 found = utf8_strcasestr (line_text, *lines);
4693 /* If it's not the first line, we have to match from the
4694 * start of the line.
4696 if ((!case_insensitive &&
4697 (strncmp (line_text, *lines, strlen (*lines)) == 0)) ||
4698 (case_insensitive &&
4699 utf8_caselessnmatch (line_text, *lines, strlen (line_text),
4714 /* Get offset to start of search string */
4715 offset = g_utf8_strlen (line_text, found - line_text);
4719 /* If match start needs to be returned, set it to the
4720 * start of the search string.
4722 forward_chars_with_skipping (&next, offset,
4723 visible_only, !slice, FALSE);
4725 *match_start = next;
4727 /* Go to end of search string */
4728 forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1),
4729 visible_only, !slice, TRUE);
4738 /* pass NULL for match_start, since we don't need to find the
4741 return lines_match (&next, lines, visible_only, slice, case_insensitive, NULL, match_end);
4744 /* strsplit () that retains the delimiter as part of the string. */
4746 strbreakup (const char *string,
4747 const char *delimiter,
4750 gboolean case_insensitive)
4752 GSList *string_list = NULL, *slist;
4753 gchar **str_array, *s;
4754 gchar *casefold, *new_string;
4757 g_return_val_if_fail (string != NULL, NULL);
4758 g_return_val_if_fail (delimiter != NULL, NULL);
4761 max_tokens = G_MAXINT;
4763 s = strstr (string, delimiter);
4766 guint delimiter_len = strlen (delimiter);
4772 len = s - string + delimiter_len;
4773 new_string = g_new (gchar, len + 1);
4774 strncpy (new_string, string, len);
4775 new_string[len] = 0;
4777 if (case_insensitive)
4779 casefold = g_utf8_casefold (new_string, -1);
4780 g_free (new_string);
4781 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4785 string_list = g_slist_prepend (string_list, new_string);
4787 string = s + delimiter_len;
4788 s = strstr (string, delimiter);
4790 while (--max_tokens && s);
4796 if (case_insensitive)
4798 casefold = g_utf8_casefold (string, -1);
4799 new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4803 new_string = g_strdup (string);
4805 string_list = g_slist_prepend (string_list, new_string);
4808 str_array = g_new (gchar*, n);
4812 str_array[i--] = NULL;
4813 for (slist = string_list; slist; slist = slist->next)
4814 str_array[i--] = slist->data;
4816 g_slist_free (string_list);
4818 if (num_strings != NULL)
4819 *num_strings = n - 1;
4825 * gtk_text_iter_forward_search:
4826 * @iter: start of search
4827 * @str: a search string
4828 * @flags: flags affecting how the search is done
4829 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
4830 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
4831 * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
4833 * Searches forward for @str. Any match is returned by setting
4834 * @match_start to the first character of the match and @match_end to the
4835 * first character after the match. The search will not continue past
4836 * @limit. Note that a search is a linear or O(n) operation, so you
4837 * may wish to use @limit to avoid locking up your UI on large
4840 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4841 * have invisible text interspersed in @str. i.e. @str will be a
4842 * possibly-noncontiguous subsequence of the matched range. similarly,
4843 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4844 * pixbufs or child widgets mixed inside the matched range. If these
4845 * flags are not given, the match must be exact; the special 0xFFFC
4846 * character in @str will match embedded pixbufs or child widgets.
4847 * If you specify the #GTK_TEXT_SEARCH_CASE_INSENSITIVE flag, the text will
4848 * be matched regardless of what case it is in.
4850 * Return value: whether a match was found
4853 gtk_text_iter_forward_search (const GtkTextIter *iter,
4855 GtkTextSearchFlags flags,
4856 GtkTextIter *match_start,
4857 GtkTextIter *match_end,
4858 const GtkTextIter *limit)
4860 gchar **lines = NULL;
4862 gboolean retval = FALSE;
4864 gboolean visible_only;
4866 gboolean case_insensitive;
4868 g_return_val_if_fail (iter != NULL, FALSE);
4869 g_return_val_if_fail (str != NULL, FALSE);
4872 gtk_text_iter_compare (iter, limit) >= 0)
4877 /* If we can move one char, return the empty string there */
4880 if (gtk_text_iter_forward_char (&match))
4883 gtk_text_iter_equal (&match, limit))
4887 *match_start = match;
4896 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4897 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4898 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
4900 /* locate all lines */
4902 lines = strbreakup (str, "\n", -1, NULL, case_insensitive);
4908 /* This loop has an inefficient worst-case, where
4909 * gtk_text_iter_get_text () is called repeatedly on
4915 gtk_text_iter_compare (&search, limit) >= 0)
4918 if (lines_match (&search, (const gchar**)lines,
4919 visible_only, slice, case_insensitive, &match, &end))
4921 if (limit == NULL ||
4923 gtk_text_iter_compare (&end, limit) <= 0))
4928 *match_start = match;
4937 while (gtk_text_iter_forward_line (&search));
4939 g_strfreev ((gchar**)lines);
4945 vectors_equal_ignoring_trailing (gchar **vec1,
4947 gboolean case_insensitive)
4949 /* Ignores trailing chars in vec2's last line */
4961 if (!case_insensitive)
4963 if (strcmp (*i1, *i2) != 0)
4965 if (*(i2 + 1) == NULL) /* if this is the last line */
4967 len1 = strlen (*i1);
4968 len2 = strlen (*i2);
4971 strncmp (*i1, *i2, len1) == 0)
4973 /* We matched ignoring the trailing stuff in vec2 */
4989 len1 = strlen (*i1);
4990 len2 = strlen (*i2);
4992 if (!utf8_caselessnmatch (*i1, *i2, len1, len2))
4994 if (*(i2 + 1) == NULL) /* if this is the last line */
4996 if (utf8_caselessnmatch (*i2, *i1, len2, len1))
4998 /* We matched ignoring the trailing stuff in vec2 */
5023 typedef struct _LinesWindow LinesWindow;
5030 GtkTextIter first_line_start;
5031 GtkTextIter first_line_end;
5034 guint visible_only : 1;
5038 lines_window_init (LinesWindow *win,
5039 const GtkTextIter *start)
5042 GtkTextIter line_start;
5043 GtkTextIter line_end;
5045 /* If we start on line 1, there are 2 lines to search (0 and 1), so
5048 if (gtk_text_iter_is_start (start) ||
5049 gtk_text_iter_get_line (start) + 1 < win->n_lines)
5051 /* Already at the end, or not enough lines to match */
5052 win->lines = g_new0 (gchar*, 1);
5057 line_start = *start;
5060 /* Move to start iter to start of line */
5061 gtk_text_iter_set_line_offset (&line_start, 0);
5063 if (gtk_text_iter_equal (&line_start, &line_end))
5065 /* we were already at the start; so go back one line */
5066 gtk_text_iter_backward_line (&line_start);
5069 win->first_line_start = line_start;
5070 win->first_line_end = line_end;
5072 win->lines = g_new0 (gchar*, win->n_lines + 1);
5074 i = win->n_lines - 1;
5081 if (win->visible_only)
5082 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
5084 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
5088 if (win->visible_only)
5089 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
5091 line_text = gtk_text_iter_get_text (&line_start, &line_end);
5094 win->lines[i] = line_text;
5095 win->first_line_start = line_start;
5096 win->first_line_end = line_end;
5098 line_end = line_start;
5099 gtk_text_iter_backward_line (&line_start);
5106 lines_window_back (LinesWindow *win)
5108 GtkTextIter new_start;
5111 new_start = win->first_line_start;
5113 if (!gtk_text_iter_backward_line (&new_start))
5117 win->first_line_start = new_start;
5118 win->first_line_end = new_start;
5120 gtk_text_iter_forward_line (&win->first_line_end);
5125 if (win->visible_only)
5126 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
5127 &win->first_line_end);
5129 line_text = gtk_text_iter_get_slice (&win->first_line_start,
5130 &win->first_line_end);
5134 if (win->visible_only)
5135 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
5136 &win->first_line_end);
5138 line_text = gtk_text_iter_get_text (&win->first_line_start,
5139 &win->first_line_end);
5142 /* Move lines to make room for first line. */
5143 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
5145 *win->lines = line_text;
5147 /* Free old last line and NULL-terminate */
5148 g_free (win->lines[win->n_lines]);
5149 win->lines[win->n_lines] = NULL;
5155 lines_window_free (LinesWindow *win)
5157 g_strfreev (win->lines);
5161 * gtk_text_iter_backward_search:
5162 * @iter: a #GtkTextIter where the search begins
5163 * @str: search string
5164 * @flags: bitmask of flags affecting the search
5165 * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
5166 * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
5167 * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
5169 * Same as gtk_text_iter_forward_search(), but moves backward.
5171 * Return value: whether a match was found
5174 gtk_text_iter_backward_search (const GtkTextIter *iter,
5176 GtkTextSearchFlags flags,
5177 GtkTextIter *match_start,
5178 GtkTextIter *match_end,
5179 const GtkTextIter *limit)
5181 gchar **lines = NULL;
5185 gboolean retval = FALSE;
5186 gboolean visible_only;
5188 gboolean case_insensitive;
5190 g_return_val_if_fail (iter != NULL, FALSE);
5191 g_return_val_if_fail (str != NULL, FALSE);
5194 gtk_text_iter_compare (limit, iter) > 0)
5199 /* If we can move one char, return the empty string there */
5200 GtkTextIter match = *iter;
5202 if (limit && gtk_text_iter_equal (limit, &match))
5205 if (gtk_text_iter_backward_char (&match))
5208 *match_start = match;
5217 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
5218 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
5219 case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
5221 /* locate all lines */
5223 lines = strbreakup (str, "\n", -1, &n_lines, case_insensitive);
5225 win.n_lines = n_lines;
5227 win.visible_only = visible_only;
5229 lines_window_init (&win, iter);
5231 if (*win.lines == NULL)
5236 const gchar *first_line_match;
5239 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
5241 /* We're now before the search limit, abort. */
5245 /* If there are multiple lines, the first line will
5246 * end in '\n', so this will only match at the
5247 * end of the first line, which is correct.
5249 if (!case_insensitive)
5250 first_line_match = g_strrstr (*win.lines, *lines);
5252 first_line_match = utf8_strrcasestr (*win.lines, *lines);
5254 if (first_line_match &&
5255 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1,
5261 GtkTextIter start_tmp;
5263 /* Offset to start of search string */
5264 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5266 next = win.first_line_start;
5268 forward_chars_with_skipping (&start_tmp, offset,
5269 visible_only, !slice, FALSE);
5272 gtk_text_iter_compare (limit, &start_tmp) > 0)
5273 goto out; /* match was bogus */
5276 *match_start = start_tmp;
5278 /* Go to end of search string */
5282 offset += g_utf8_strlen (*l, -1);
5286 forward_chars_with_skipping (&next, offset,
5287 visible_only, !slice, TRUE);
5296 while (lines_window_back (&win));
5299 lines_window_free (&win);
5310 * gtk_text_iter_equal:
5311 * @lhs: a #GtkTextIter
5312 * @rhs: another #GtkTextIter
5314 * Tests whether two iterators are equal, using the fastest possible
5315 * mechanism. This function is very fast; you can expect it to perform
5316 * better than e.g. getting the character offset for each iterator and
5317 * comparing the offsets yourself. Also, it's a bit faster than
5318 * gtk_text_iter_compare().
5320 * Return value: %TRUE if the iterators point to the same place in the buffer
5323 gtk_text_iter_equal (const GtkTextIter *lhs,
5324 const GtkTextIter *rhs)
5326 GtkTextRealIter *real_lhs;
5327 GtkTextRealIter *real_rhs;
5329 real_lhs = (GtkTextRealIter*)lhs;
5330 real_rhs = (GtkTextRealIter*)rhs;
5332 check_invariants (lhs);
5333 check_invariants (rhs);
5335 if (real_lhs->line != real_rhs->line)
5337 else if (real_lhs->line_byte_offset >= 0 &&
5338 real_rhs->line_byte_offset >= 0)
5339 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5342 /* the ensure_char_offsets () calls do nothing if the char offsets
5343 are already up-to-date. */
5344 ensure_char_offsets (real_lhs);
5345 ensure_char_offsets (real_rhs);
5346 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5351 * gtk_text_iter_compare:
5352 * @lhs: a #GtkTextIter
5353 * @rhs: another #GtkTextIter
5355 * A qsort()-style function that returns negative if @lhs is less than
5356 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5357 * Ordering is in character offset order, i.e. the first character in the buffer
5358 * is less than the second character in the buffer.
5360 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5363 gtk_text_iter_compare (const GtkTextIter *lhs,
5364 const GtkTextIter *rhs)
5366 GtkTextRealIter *real_lhs;
5367 GtkTextRealIter *real_rhs;
5369 real_lhs = gtk_text_iter_make_surreal (lhs);
5370 real_rhs = gtk_text_iter_make_surreal (rhs);
5372 if (real_lhs == NULL ||
5374 return -1; /* why not */
5376 check_invariants (lhs);
5377 check_invariants (rhs);
5379 if (real_lhs->line == real_rhs->line)
5381 gint left_index, right_index;
5383 if (real_lhs->line_byte_offset >= 0 &&
5384 real_rhs->line_byte_offset >= 0)
5386 left_index = real_lhs->line_byte_offset;
5387 right_index = real_rhs->line_byte_offset;
5391 /* the ensure_char_offsets () calls do nothing if
5392 the offsets are already up-to-date. */
5393 ensure_char_offsets (real_lhs);
5394 ensure_char_offsets (real_rhs);
5395 left_index = real_lhs->line_char_offset;
5396 right_index = real_rhs->line_char_offset;
5399 if (left_index < right_index)
5401 else if (left_index > right_index)
5410 line1 = gtk_text_iter_get_line (lhs);
5411 line2 = gtk_text_iter_get_line (rhs);
5414 else if (line1 > line2)
5422 * gtk_text_iter_in_range:
5423 * @iter: a #GtkTextIter
5424 * @start: start of range
5425 * @end: end of range
5427 * Checks whether @iter falls in the range [@start, @end).
5428 * @start and @end must be in ascending order.
5430 * Return value: %TRUE if @iter is in the range
5433 gtk_text_iter_in_range (const GtkTextIter *iter,
5434 const GtkTextIter *start,
5435 const GtkTextIter *end)
5437 g_return_val_if_fail (iter != NULL, FALSE);
5438 g_return_val_if_fail (start != NULL, FALSE);
5439 g_return_val_if_fail (end != NULL, FALSE);
5440 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5442 return gtk_text_iter_compare (iter, start) >= 0 &&
5443 gtk_text_iter_compare (iter, end) < 0;
5447 * gtk_text_iter_order:
5448 * @first: a #GtkTextIter
5449 * @second: another #GtkTextIter
5451 * Swaps the value of @first and @second if @second comes before
5452 * @first in the buffer. That is, ensures that @first and @second are
5453 * in sequence. Most text buffer functions that take a range call this
5454 * automatically on your behalf, so there's no real reason to call it yourself
5455 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5456 * that expect a pre-sorted range.
5460 gtk_text_iter_order (GtkTextIter *first,
5461 GtkTextIter *second)
5463 g_return_if_fail (first != NULL);
5464 g_return_if_fail (second != NULL);
5466 if (gtk_text_iter_compare (first, second) > 0)
5477 * Init iterators from the BTree
5481 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5485 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5486 gint real_char_index;
5490 g_return_if_fail (iter != NULL);
5491 g_return_if_fail (tree != NULL);
5493 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5494 &line_start, &real_char_index);
5496 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5498 real->cached_char_index = real_char_index;
5500 check_invariants (iter);
5504 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5509 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5513 g_return_if_fail (iter != NULL);
5514 g_return_if_fail (tree != NULL);
5516 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5518 iter_init_from_char_offset (iter, tree, line, char_on_line);
5520 /* We might as well cache this, since we know it. */
5521 real->cached_line_number = real_line;
5523 check_invariants (iter);
5527 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5532 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5536 g_return_if_fail (iter != NULL);
5537 g_return_if_fail (tree != NULL);
5539 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5541 iter_init_from_byte_offset (iter, tree, line, byte_index);
5543 /* We might as well cache this, since we know it. */
5544 real->cached_line_number = real_line;
5546 check_invariants (iter);
5550 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5555 g_return_if_fail (iter != NULL);
5556 g_return_if_fail (tree != NULL);
5557 g_return_if_fail (line != NULL);
5559 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5561 check_invariants (iter);
5565 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5571 g_return_val_if_fail (iter != NULL, FALSE);
5572 g_return_val_if_fail (tree != NULL, FALSE);
5574 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5578 /* Set iter to last in tree */
5579 _gtk_text_btree_get_end_iter (tree, iter);
5580 check_invariants (iter);
5585 iter_init_from_byte_offset (iter, tree, line, 0);
5587 if (!gtk_text_iter_toggles_tag (iter, tag))
5588 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5590 check_invariants (iter);
5596 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5600 g_return_val_if_fail (iter != NULL, FALSE);
5601 g_return_val_if_fail (tree != NULL, FALSE);
5603 _gtk_text_btree_get_end_iter (tree, iter);
5604 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5605 check_invariants (iter);
5611 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5613 const gchar *mark_name)
5617 g_return_val_if_fail (iter != NULL, FALSE);
5618 g_return_val_if_fail (tree != NULL, FALSE);
5620 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5626 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5627 check_invariants (iter);
5633 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5637 GtkTextLineSegment *seg;
5639 g_return_if_fail (iter != NULL);
5640 g_return_if_fail (tree != NULL);
5641 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5643 seg = mark->segment;
5645 iter_init_from_segment (iter, tree,
5646 seg->body.mark.line, seg);
5647 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5648 check_invariants (iter);
5652 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5654 GtkTextChildAnchor *anchor)
5656 GtkTextLineSegment *seg;
5658 g_return_if_fail (iter != NULL);
5659 g_return_if_fail (tree != NULL);
5660 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5662 seg = anchor->segment;
5664 g_assert (seg->body.child.line != NULL);
5666 iter_init_from_segment (iter, tree,
5667 seg->body.child.line, seg);
5668 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5669 check_invariants (iter);
5673 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5676 g_return_if_fail (iter != NULL);
5677 g_return_if_fail (tree != NULL);
5679 _gtk_text_btree_get_iter_at_char (tree,
5681 _gtk_text_btree_char_count (tree));
5682 check_invariants (iter);
5686 _gtk_text_iter_check (const GtkTextIter *iter)
5688 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5689 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5690 GtkTextLineSegment *byte_segment = NULL;
5691 GtkTextLineSegment *byte_any_segment = NULL;
5692 GtkTextLineSegment *char_segment = NULL;
5693 GtkTextLineSegment *char_any_segment = NULL;
5694 gboolean segments_updated;
5696 /* This function checks our class invariants for the Iter class. */
5698 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5700 if (real->chars_changed_stamp !=
5701 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5702 g_error ("iterator check failed: invalid iterator");
5704 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5705 g_error ("iterator check failed: both char and byte offsets are invalid");
5707 segments_updated = (real->segments_changed_stamp ==
5708 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5711 printf ("checking iter, segments %s updated, byte %d char %d\n",
5712 segments_updated ? "are" : "aren't",
5713 real->line_byte_offset,
5714 real->line_char_offset);
5717 if (segments_updated)
5719 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5720 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5722 if (real->segment->char_count == 0)
5723 g_error ("iterator check failed: segment is not indexable.");
5725 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5726 g_error ("segment char offset is not properly up-to-date");
5728 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5729 g_error ("segment byte offset is not properly up-to-date");
5731 if (real->segment_byte_offset >= 0 &&
5732 real->segment_byte_offset >= real->segment->byte_count)
5733 g_error ("segment byte offset is too large.");
5735 if (real->segment_char_offset >= 0 &&
5736 real->segment_char_offset >= real->segment->char_count)
5737 g_error ("segment char offset is too large.");
5740 if (real->line_byte_offset >= 0)
5742 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5743 &byte_segment, &byte_any_segment,
5744 &seg_byte_offset, &line_byte_offset);
5746 if (line_byte_offset != real->line_byte_offset)
5747 g_error ("wrong byte offset was stored in iterator");
5749 if (segments_updated)
5751 if (real->segment != byte_segment)
5752 g_error ("wrong segment was stored in iterator");
5754 if (real->any_segment != byte_any_segment)
5755 g_error ("wrong any_segment was stored in iterator");
5757 if (seg_byte_offset != real->segment_byte_offset)
5758 g_error ("wrong segment byte offset was stored in iterator");
5760 if (byte_segment->type == >k_text_char_type)
5763 p = byte_segment->body.chars + seg_byte_offset;
5765 if (!gtk_text_byte_begins_utf8_char (p))
5766 g_error ("broken iterator byte index pointed into the middle of a character");
5771 if (real->line_char_offset >= 0)
5773 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5774 &char_segment, &char_any_segment,
5775 &seg_char_offset, &line_char_offset);
5777 if (line_char_offset != real->line_char_offset)
5778 g_error ("wrong char offset was stored in iterator");
5780 if (segments_updated)
5782 if (real->segment != char_segment)
5783 g_error ("wrong segment was stored in iterator");
5785 if (real->any_segment != char_any_segment)
5786 g_error ("wrong any_segment was stored in iterator");
5788 if (seg_char_offset != real->segment_char_offset)
5789 g_error ("wrong segment char offset was stored in iterator");
5791 if (char_segment->type == >k_text_char_type)
5794 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5797 /* hmm, not likely to happen eh */
5798 if (!gtk_text_byte_begins_utf8_char (p))
5799 g_error ("broken iterator char offset pointed into the middle of a character");
5804 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5806 if (byte_segment != char_segment)
5807 g_error ("char and byte offsets did not point to the same segment");
5809 if (byte_any_segment != char_any_segment)
5810 g_error ("char and byte offsets did not point to the same any segment");
5812 /* Make sure the segment offsets are equivalent, if it's a char
5814 if (char_segment->type == >k_text_char_type)
5816 gint byte_offset = 0;
5817 gint char_offset = 0;
5818 while (char_offset < seg_char_offset)
5820 const char * start = char_segment->body.chars + byte_offset;
5821 byte_offset += g_utf8_next_char (start) - start;
5825 if (byte_offset != seg_byte_offset)
5826 g_error ("byte offset did not correspond to char offset");
5829 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5831 if (char_offset != seg_char_offset)
5832 g_error ("char offset did not correspond to byte offset");
5834 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5835 g_error ("byte index for iterator does not index the start of a character");
5839 if (real->cached_line_number >= 0)
5843 should_be = _gtk_text_line_get_number (real->line);
5844 if (real->cached_line_number != should_be)
5845 g_error ("wrong line number was cached");
5848 if (real->cached_char_index >= 0)
5850 if (real->line_char_offset >= 0) /* only way we can check it
5851 efficiently, not a real
5856 char_index = _gtk_text_line_char_index (real->line);
5857 char_index += real->line_char_offset;
5859 if (real->cached_char_index != char_index)
5860 g_error ("wrong char index was cached");
5864 if (_gtk_text_line_is_last (real->line, real->tree))
5865 g_error ("Iterator was on last line (past the end iterator)");