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_debug_flags & GTK_DEBUG_TEXT)
374 _gtk_text_iter_check (iter);
377 #define check_invariants(x)
381 * gtk_text_iter_get_buffer:
384 * Returns the #GtkTextBuffer this iterator is associated with.
386 * Return value: (transfer none): the buffer
389 gtk_text_iter_get_buffer (const GtkTextIter *iter)
391 GtkTextRealIter *real;
393 g_return_val_if_fail (iter != NULL, NULL);
395 real = gtk_text_iter_make_surreal (iter);
400 check_invariants (iter);
402 return _gtk_text_btree_get_buffer (real->tree);
406 * gtk_text_iter_copy:
409 * Creates a dynamically-allocated copy of an iterator. This function
410 * is not useful in applications, because iterators can be copied with a
411 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
412 * function is used by language bindings.
414 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
417 gtk_text_iter_copy (const GtkTextIter *iter)
419 GtkTextIter *new_iter;
421 g_return_val_if_fail (iter != NULL, NULL);
423 new_iter = g_slice_new (GtkTextIter);
431 * gtk_text_iter_free:
432 * @iter: a dynamically-allocated iterator
434 * Free an iterator allocated on the heap. This function
435 * is intended for use in language bindings, and is not
436 * especially useful for applications, because iterators can
437 * simply be allocated on the stack.
440 gtk_text_iter_free (GtkTextIter *iter)
442 g_return_if_fail (iter != NULL);
444 g_slice_free (GtkTextIter, iter);
448 gtk_text_iter_get_type (void)
450 static GType our_type = 0;
453 our_type = g_boxed_type_register_static (I_("GtkTextIter"),
454 (GBoxedCopyFunc) gtk_text_iter_copy,
455 (GBoxedFreeFunc) gtk_text_iter_free);
461 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
463 GtkTextRealIter *real;
465 g_return_val_if_fail (iter != NULL, NULL);
467 real = gtk_text_iter_make_real (iter);
472 check_invariants (iter);
474 g_assert (real->segment != NULL);
476 return real->segment;
480 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
482 GtkTextRealIter *real;
484 g_return_val_if_fail (iter != NULL, NULL);
486 real = gtk_text_iter_make_real (iter);
491 check_invariants (iter);
493 g_assert (real->any_segment != NULL);
495 return real->any_segment;
499 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
501 GtkTextRealIter *real;
503 g_return_val_if_fail (iter != NULL, 0);
505 real = gtk_text_iter_make_real (iter);
510 ensure_byte_offsets (real);
512 check_invariants (iter);
514 return real->segment_byte_offset;
518 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
520 GtkTextRealIter *real;
522 g_return_val_if_fail (iter != NULL, 0);
524 real = gtk_text_iter_make_real (iter);
529 ensure_char_offsets (real);
531 check_invariants (iter);
533 return real->segment_char_offset;
536 /* This function does not require a still-valid
539 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
541 const GtkTextRealIter *real;
543 g_return_val_if_fail (iter != NULL, NULL);
545 real = (const GtkTextRealIter*)iter;
550 /* This function does not require a still-valid
553 _gtk_text_iter_get_btree (const GtkTextIter *iter)
555 const GtkTextRealIter *real;
557 g_return_val_if_fail (iter != NULL, NULL);
559 real = (const GtkTextRealIter*)iter;
569 * gtk_text_iter_get_offset:
572 * Returns the character offset of an iterator.
573 * Each character in a #GtkTextBuffer has an offset,
574 * starting with 0 for the first character in the buffer.
575 * Use gtk_text_buffer_get_iter_at_offset () to convert an
576 * offset back into an iterator.
578 * Return value: a character offset
581 gtk_text_iter_get_offset (const GtkTextIter *iter)
583 GtkTextRealIter *real;
585 g_return_val_if_fail (iter != NULL, 0);
587 real = gtk_text_iter_make_surreal (iter);
592 check_invariants (iter);
594 if (real->cached_char_index < 0)
596 ensure_char_offsets (real);
598 real->cached_char_index =
599 _gtk_text_line_char_index (real->line);
600 real->cached_char_index += real->line_char_offset;
603 check_invariants (iter);
605 return real->cached_char_index;
609 * gtk_text_iter_get_line:
612 * Returns the line number containing the iterator. Lines in
613 * a #GtkTextBuffer are numbered beginning with 0 for the first
614 * line in the buffer.
616 * Return value: a line number
619 gtk_text_iter_get_line (const GtkTextIter *iter)
621 GtkTextRealIter *real;
623 g_return_val_if_fail (iter != NULL, 0);
625 real = gtk_text_iter_make_surreal (iter);
630 if (real->cached_line_number < 0)
631 real->cached_line_number =
632 _gtk_text_line_get_number (real->line);
634 check_invariants (iter);
636 return real->cached_line_number;
640 * gtk_text_iter_get_line_offset:
643 * Returns the character offset of the iterator,
644 * counting from the start of a newline-terminated line.
645 * The first character on the line has offset 0.
647 * Return value: offset from start of line
650 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
652 GtkTextRealIter *real;
654 g_return_val_if_fail (iter != NULL, 0);
656 real = gtk_text_iter_make_surreal (iter);
661 ensure_char_offsets (real);
663 check_invariants (iter);
665 return real->line_char_offset;
669 * gtk_text_iter_get_line_index:
672 * Returns the byte index of the iterator, counting
673 * from the start of a newline-terminated line.
674 * Remember that #GtkTextBuffer encodes text in
675 * UTF-8, and that characters can require a variable
676 * number of bytes to represent.
678 * Return value: distance from start of line, in bytes
681 gtk_text_iter_get_line_index (const GtkTextIter *iter)
683 GtkTextRealIter *real;
685 g_return_val_if_fail (iter != NULL, 0);
687 real = gtk_text_iter_make_surreal (iter);
692 ensure_byte_offsets (real);
694 check_invariants (iter);
696 return real->line_byte_offset;
700 * gtk_text_iter_get_visible_line_offset:
701 * @iter: a #GtkTextIter
703 * Returns the offset in characters from the start of the
704 * line to the given @iter, not counting characters that
705 * are invisible due to tags with the "invisible" flag
708 * Return value: offset in visible characters from the start of the line
711 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
713 GtkTextRealIter *real;
715 GtkTextLineSegment *seg;
718 g_return_val_if_fail (iter != NULL, 0);
720 real = gtk_text_iter_make_real (iter);
725 ensure_char_offsets (real);
727 check_invariants (iter);
729 vis_offset = real->line_char_offset;
731 g_assert (vis_offset >= 0);
733 _gtk_text_btree_get_iter_at_line (real->tree,
738 seg = _gtk_text_iter_get_indexable_segment (&pos);
740 while (seg != real->segment)
742 /* This is a pretty expensive call, making the
743 * whole function pretty lame; we could keep track
744 * of current invisibility state by looking at toggle
745 * segments as we loop, and then call this function
746 * only once per line, in order to speed up the loop
749 if (_gtk_text_btree_char_is_invisible (&pos))
750 vis_offset -= seg->char_count;
752 _gtk_text_iter_forward_indexable_segment (&pos);
754 seg = _gtk_text_iter_get_indexable_segment (&pos);
757 if (_gtk_text_btree_char_is_invisible (&pos))
758 vis_offset -= real->segment_char_offset;
765 * gtk_text_iter_get_visible_line_index:
766 * @iter: a #GtkTextIter
768 * Returns the number of bytes from the start of the
769 * line to the given @iter, not counting bytes that
770 * are invisible due to tags with the "invisible" flag
773 * Return value: byte index of @iter with respect to the start of the line
776 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
778 GtkTextRealIter *real;
780 GtkTextLineSegment *seg;
783 g_return_val_if_fail (iter != NULL, 0);
785 real = gtk_text_iter_make_real (iter);
790 ensure_byte_offsets (real);
792 check_invariants (iter);
794 vis_offset = real->line_byte_offset;
796 g_assert (vis_offset >= 0);
798 _gtk_text_btree_get_iter_at_line (real->tree,
803 seg = _gtk_text_iter_get_indexable_segment (&pos);
805 while (seg != real->segment)
807 /* This is a pretty expensive call, making the
808 * whole function pretty lame; we could keep track
809 * of current invisibility state by looking at toggle
810 * segments as we loop, and then call this function
811 * only once per line, in order to speed up the loop
814 if (_gtk_text_btree_char_is_invisible (&pos))
815 vis_offset -= seg->byte_count;
817 _gtk_text_iter_forward_indexable_segment (&pos);
819 seg = _gtk_text_iter_get_indexable_segment (&pos);
822 if (_gtk_text_btree_char_is_invisible (&pos))
823 vis_offset -= real->segment_byte_offset;
833 * gtk_text_iter_get_char:
836 * Returns the Unicode character at this iterator. (Equivalent to
837 * operator* on a C++ iterator.) If the element at this iterator is a
838 * non-character element, such as an image embedded in the buffer, the
839 * Unicode "unknown" character 0xFFFC is returned. If invoked on
840 * the end iterator, zero is returned; zero is not a valid Unicode character.
841 * So you can write a loop which ends when gtk_text_iter_get_char ()
844 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
847 gtk_text_iter_get_char (const GtkTextIter *iter)
849 GtkTextRealIter *real;
851 g_return_val_if_fail (iter != NULL, 0);
853 real = gtk_text_iter_make_real (iter);
858 check_invariants (iter);
860 if (gtk_text_iter_is_end (iter))
862 else if (real->segment->type == >k_text_char_type)
864 ensure_byte_offsets (real);
866 return g_utf8_get_char (real->segment->body.chars +
867 real->segment_byte_offset);
871 /* Unicode "unknown character" 0xFFFC */
872 return GTK_TEXT_UNKNOWN_CHAR;
877 * gtk_text_iter_get_slice:
878 * @start: iterator at start of a range
879 * @end: iterator at end of a range
881 * Returns the text in the given range. A "slice" is an array of
882 * characters encoded in UTF-8 format, including the Unicode "unknown"
883 * character 0xFFFC for iterable non-character elements in the buffer,
884 * such as images. Because images are encoded in the slice, byte and
885 * character offsets in the returned array will correspond to byte
886 * offsets in the text buffer. Note that 0xFFFC can occur in normal
887 * text as well, so it is not a reliable indicator that a pixbuf or
888 * widget is in the buffer.
890 * Return value: slice of text from the buffer
893 gtk_text_iter_get_slice (const GtkTextIter *start,
894 const GtkTextIter *end)
896 g_return_val_if_fail (start != NULL, NULL);
897 g_return_val_if_fail (end != NULL, NULL);
899 check_invariants (start);
900 check_invariants (end);
902 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
906 * gtk_text_iter_get_text:
907 * @start: iterator at start of a range
908 * @end: iterator at end of a range
910 * Returns <emphasis>text</emphasis> in the given range. If the range
911 * contains non-text elements such as images, the character and byte
912 * offsets in the returned string will not correspond to character and
913 * byte offsets in the buffer. If you want offsets to correspond, see
914 * gtk_text_iter_get_slice ().
916 * Return value: array of characters from the buffer
919 gtk_text_iter_get_text (const GtkTextIter *start,
920 const GtkTextIter *end)
922 g_return_val_if_fail (start != NULL, NULL);
923 g_return_val_if_fail (end != NULL, NULL);
925 check_invariants (start);
926 check_invariants (end);
928 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
932 * gtk_text_iter_get_visible_slice:
933 * @start: iterator at start of range
934 * @end: iterator at end of range
936 * Like gtk_text_iter_get_slice (), but invisible text is not included.
937 * Invisible text is usually invisible because a #GtkTextTag with the
938 * "invisible" attribute turned on has been applied to it.
940 * Return value: slice of text from the buffer
943 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
944 const GtkTextIter *end)
946 g_return_val_if_fail (start != NULL, NULL);
947 g_return_val_if_fail (end != NULL, NULL);
949 check_invariants (start);
950 check_invariants (end);
952 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
956 * gtk_text_iter_get_visible_text:
957 * @start: iterator at start of range
958 * @end: iterator at end of range
960 * Like gtk_text_iter_get_text (), but invisible text is not included.
961 * Invisible text is usually invisible because a #GtkTextTag with the
962 * "invisible" attribute turned on has been applied to it.
964 * Return value: string containing visible text in the range
967 gtk_text_iter_get_visible_text (const GtkTextIter *start,
968 const GtkTextIter *end)
970 g_return_val_if_fail (start != NULL, NULL);
971 g_return_val_if_fail (end != NULL, NULL);
973 check_invariants (start);
974 check_invariants (end);
976 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
980 * gtk_text_iter_get_pixbuf:
983 * If the element at @iter is a pixbuf, the pixbuf is returned
984 * (with no new reference count added). Otherwise,
987 * Return value: (transfer none): the pixbuf at @iter
990 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
992 GtkTextRealIter *real;
994 g_return_val_if_fail (iter != NULL, NULL);
996 real = gtk_text_iter_make_real (iter);
1001 check_invariants (iter);
1003 if (real->segment->type != >k_text_pixbuf_type)
1006 return real->segment->body.pixbuf.pixbuf;
1010 * gtk_text_iter_get_child_anchor:
1011 * @iter: an iterator
1013 * If the location at @iter contains a child anchor, the
1014 * anchor is returned (with no new reference count added). Otherwise,
1015 * %NULL is returned.
1017 * Return value: the anchor at @iter
1020 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1022 GtkTextRealIter *real;
1024 g_return_val_if_fail (iter != NULL, NULL);
1026 real = gtk_text_iter_make_real (iter);
1031 check_invariants (iter);
1033 if (real->segment->type != >k_text_child_type)
1036 return real->segment->body.child.obj;
1040 * gtk_text_iter_get_marks:
1041 * @iter: an iterator
1043 * Returns a list of all #GtkTextMark at this location. Because marks
1044 * are not iterable (they don't take up any "space" in the buffer,
1045 * they are just marks in between iterable locations), multiple marks
1046 * can exist in the same place. The returned list is not in any
1049 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1052 gtk_text_iter_get_marks (const GtkTextIter *iter)
1054 GtkTextRealIter *real;
1055 GtkTextLineSegment *seg;
1058 g_return_val_if_fail (iter != NULL, NULL);
1060 real = gtk_text_iter_make_real (iter);
1065 check_invariants (iter);
1068 seg = real->any_segment;
1069 while (seg != real->segment)
1071 if (seg->type == >k_text_left_mark_type ||
1072 seg->type == >k_text_right_mark_type)
1073 retval = g_slist_prepend (retval, seg->body.mark.obj);
1078 /* The returned list isn't guaranteed to be in any special order,
1084 * gtk_text_iter_get_toggled_tags:
1085 * @iter: an iterator
1086 * @toggled_on: %TRUE to get toggled-on tags
1088 * Returns a list of #GtkTextTag that are toggled on or off at this
1089 * point. (If @toggled_on is %TRUE, the list contains tags that are
1090 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1091 * range of characters following @iter has that tag applied to it. If
1092 * a tag is toggled off, then some non-empty range following @iter
1093 * does <emphasis>not</emphasis> have the tag applied to it.
1095 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1098 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1099 gboolean toggled_on)
1101 GtkTextRealIter *real;
1102 GtkTextLineSegment *seg;
1105 g_return_val_if_fail (iter != NULL, NULL);
1107 real = gtk_text_iter_make_real (iter);
1112 check_invariants (iter);
1115 seg = real->any_segment;
1116 while (seg != real->segment)
1120 if (seg->type == >k_text_toggle_on_type)
1122 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1127 if (seg->type == >k_text_toggle_off_type)
1129 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1136 /* The returned list isn't guaranteed to be in any special order,
1142 * gtk_text_iter_begins_tag:
1143 * @iter: an iterator
1144 * @tag: (allow-none): a #GtkTextTag, or %NULL
1146 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1147 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1148 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1149 * <emphasis>start</emphasis> of the tagged range;
1150 * gtk_text_iter_has_tag () tells you whether an iterator is
1151 * <emphasis>within</emphasis> a tagged range.
1153 * Return value: whether @iter is the start of a range tagged with @tag
1156 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1159 GtkTextRealIter *real;
1160 GtkTextLineSegment *seg;
1162 g_return_val_if_fail (iter != NULL, FALSE);
1164 real = gtk_text_iter_make_real (iter);
1169 check_invariants (iter);
1171 seg = real->any_segment;
1172 while (seg != real->segment)
1174 if (seg->type == >k_text_toggle_on_type)
1177 seg->body.toggle.info->tag == tag)
1188 * gtk_text_iter_ends_tag:
1189 * @iter: an iterator
1190 * @tag: (allow-none): a #GtkTextTag, or %NULL
1192 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1193 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1194 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1195 * <emphasis>end</emphasis> of the tagged range;
1196 * gtk_text_iter_has_tag () tells you whether an iterator is
1197 * <emphasis>within</emphasis> a tagged range.
1199 * Return value: whether @iter is the end of a range tagged with @tag
1203 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1206 GtkTextRealIter *real;
1207 GtkTextLineSegment *seg;
1209 g_return_val_if_fail (iter != NULL, FALSE);
1211 real = gtk_text_iter_make_real (iter);
1216 check_invariants (iter);
1218 seg = real->any_segment;
1219 while (seg != real->segment)
1221 if (seg->type == >k_text_toggle_off_type)
1224 seg->body.toggle.info->tag == tag)
1235 * gtk_text_iter_toggles_tag:
1236 * @iter: an iterator
1237 * @tag: (allow-none): a #GtkTextTag, or %NULL
1239 * This is equivalent to (gtk_text_iter_begins_tag () ||
1240 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1241 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1243 * Return value: whether @tag is toggled on or off at @iter
1246 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1249 GtkTextRealIter *real;
1250 GtkTextLineSegment *seg;
1252 g_return_val_if_fail (iter != NULL, FALSE);
1254 real = gtk_text_iter_make_real (iter);
1259 check_invariants (iter);
1261 seg = real->any_segment;
1262 while (seg != real->segment)
1264 if ( (seg->type == >k_text_toggle_off_type ||
1265 seg->type == >k_text_toggle_on_type) &&
1267 seg->body.toggle.info->tag == tag) )
1277 * gtk_text_iter_has_tag:
1278 * @iter: an iterator
1279 * @tag: a #GtkTextTag
1281 * Returns %TRUE if @iter is within a range tagged with @tag.
1283 * Return value: whether @iter is tagged with @tag
1286 gtk_text_iter_has_tag (const GtkTextIter *iter,
1289 GtkTextRealIter *real;
1291 g_return_val_if_fail (iter != NULL, FALSE);
1292 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1294 real = gtk_text_iter_make_surreal (iter);
1299 check_invariants (iter);
1301 if (real->line_byte_offset >= 0)
1303 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1304 real->line_byte_offset, tag);
1308 g_assert (real->line_char_offset >= 0);
1309 return _gtk_text_line_char_has_tag (real->line, real->tree,
1310 real->line_char_offset, tag);
1315 * gtk_text_iter_get_tags:
1316 * @iter: a #GtkTextIter
1318 * Returns a list of tags that apply to @iter, in ascending order of
1319 * priority (highest-priority tags are last). The #GtkTextTag in the
1320 * list don't have a reference added, but you have to free the list
1323 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1326 gtk_text_iter_get_tags (const GtkTextIter *iter)
1333 g_return_val_if_fail (iter != NULL, NULL);
1335 /* Get the tags at this spot */
1336 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1338 /* No tags, use default style */
1339 if (tags == NULL || tag_count == 0)
1348 while (i < tag_count)
1350 retval = g_slist_prepend (retval, tags[i]);
1356 /* Return tags in ascending order of priority */
1357 return g_slist_reverse (retval);
1361 * gtk_text_iter_editable:
1362 * @iter: an iterator
1363 * @default_setting: %TRUE if text is editable by default
1365 * Returns whether the character at @iter is within an editable region
1366 * of text. Non-editable text is "locked" and can't be changed by the
1367 * user via #GtkTextView. This function is simply a convenience
1368 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1369 * to this text affect editability, @default_setting will be returned.
1371 * You don't want to use this function to decide whether text can be
1372 * inserted at @iter, because for insertion you don't want to know
1373 * whether the char at @iter is inside an editable range, you want to
1374 * know whether a new character inserted at @iter would be inside an
1375 * editable range. Use gtk_text_iter_can_insert() to handle this
1378 * Return value: whether @iter is inside an editable range
1381 gtk_text_iter_editable (const GtkTextIter *iter,
1382 gboolean default_setting)
1384 GtkTextAttributes *values;
1387 g_return_val_if_fail (iter != NULL, FALSE);
1389 values = gtk_text_attributes_new ();
1391 values->editable = default_setting;
1393 gtk_text_iter_get_attributes (iter, values);
1395 retval = values->editable;
1397 gtk_text_attributes_unref (values);
1403 * gtk_text_iter_can_insert:
1404 * @iter: an iterator
1405 * @default_editability: %TRUE if text is editable by default
1407 * Considering the default editability of the buffer, and tags that
1408 * affect editability, determines whether text inserted at @iter would
1409 * be editable. If text inserted at @iter would be editable then the
1410 * user should be allowed to insert text at @iter.
1411 * gtk_text_buffer_insert_interactive() uses this function to decide
1412 * whether insertions are allowed at a given position.
1414 * Return value: whether text inserted at @iter would be editable
1417 gtk_text_iter_can_insert (const GtkTextIter *iter,
1418 gboolean default_editability)
1420 g_return_val_if_fail (iter != NULL, FALSE);
1422 if (gtk_text_iter_editable (iter, default_editability))
1424 /* If at start/end of buffer, default editability is used */
1425 else if ((gtk_text_iter_is_start (iter) ||
1426 gtk_text_iter_is_end (iter)) &&
1427 default_editability)
1431 /* if iter isn't editable, and the char before iter is,
1432 * then iter is the first char in an editable region
1433 * and thus insertion at iter results in editable text.
1435 GtkTextIter prev = *iter;
1436 gtk_text_iter_backward_char (&prev);
1437 return gtk_text_iter_editable (&prev, default_editability);
1443 * gtk_text_iter_get_language:
1444 * @iter: an iterator
1446 * A convenience wrapper around gtk_text_iter_get_attributes (),
1447 * which returns the language in effect at @iter. If no tags affecting
1448 * language apply to @iter, the return value is identical to that of
1449 * gtk_get_default_language ().
1451 * Return value: language in effect at @iter
1454 gtk_text_iter_get_language (const GtkTextIter *iter)
1456 GtkTextAttributes *values;
1457 PangoLanguage *retval;
1459 values = gtk_text_attributes_new ();
1461 gtk_text_iter_get_attributes (iter, values);
1463 retval = values->language;
1465 gtk_text_attributes_unref (values);
1471 * gtk_text_iter_starts_line:
1472 * @iter: an iterator
1474 * Returns %TRUE if @iter begins a paragraph,
1475 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1476 * However this function is potentially more efficient than
1477 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1478 * the offset, it just has to see whether it's 0.
1480 * Return value: whether @iter begins a line
1483 gtk_text_iter_starts_line (const GtkTextIter *iter)
1485 GtkTextRealIter *real;
1487 g_return_val_if_fail (iter != NULL, FALSE);
1489 real = gtk_text_iter_make_surreal (iter);
1494 check_invariants (iter);
1496 if (real->line_byte_offset >= 0)
1498 return (real->line_byte_offset == 0);
1502 g_assert (real->line_char_offset >= 0);
1503 return (real->line_char_offset == 0);
1508 * gtk_text_iter_ends_line:
1509 * @iter: an iterator
1511 * Returns %TRUE if @iter points to the start of the paragraph
1512 * delimiter characters for a line (delimiters will be either a
1513 * newline, a carriage return, a carriage return followed by a
1514 * newline, or a Unicode paragraph separator character). Note that an
1515 * iterator pointing to the \n of a \r\n pair will not be counted as
1516 * the end of a line, the line ends before the \r. The end iterator is
1517 * considered to be at the end of a line, even though there are no
1518 * paragraph delimiter chars there.
1520 * Return value: whether @iter is at the end of a line
1523 gtk_text_iter_ends_line (const GtkTextIter *iter)
1527 g_return_val_if_fail (iter != NULL, FALSE);
1529 check_invariants (iter);
1531 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1532 * Unicode 3.0; update this if that changes.
1534 #define PARAGRAPH_SEPARATOR 0x2029
1536 wc = gtk_text_iter_get_char (iter);
1538 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1540 else if (wc == '\n')
1542 GtkTextIter tmp = *iter;
1544 /* need to determine if a \r precedes the \n, in which case
1545 * we aren't the end of the line.
1546 * Note however that if \r and \n are on different lines, they
1547 * both are terminators. This for instance may happen after
1548 * deleting some text:
1550 1 some text\r delete 'a' 1 some text\r
1551 2 a\n ---------> 2 \n
1556 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1559 if (!gtk_text_iter_backward_char (&tmp))
1562 return gtk_text_iter_get_char (&tmp) != '\r';
1569 * gtk_text_iter_is_end:
1570 * @iter: an iterator
1572 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1573 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1574 * the most efficient way to check whether an iterator is the end
1577 * Return value: whether @iter is the end iterator
1580 gtk_text_iter_is_end (const GtkTextIter *iter)
1582 GtkTextRealIter *real;
1584 g_return_val_if_fail (iter != NULL, FALSE);
1586 real = gtk_text_iter_make_surreal (iter);
1591 check_invariants (iter);
1593 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1596 /* Now we need the segments validated */
1597 real = gtk_text_iter_make_real (iter);
1602 return _gtk_text_btree_is_end (real->tree, real->line,
1604 real->segment_byte_offset,
1605 real->segment_char_offset);
1609 * gtk_text_iter_is_start:
1610 * @iter: an iterator
1612 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1613 * if @iter has a character offset of 0.
1615 * Return value: whether @iter is the first in the buffer
1618 gtk_text_iter_is_start (const GtkTextIter *iter)
1620 return gtk_text_iter_get_offset (iter) == 0;
1624 * gtk_text_iter_get_chars_in_line:
1625 * @iter: an iterator
1627 * Returns the number of characters in the line containing @iter,
1628 * including the paragraph delimiters.
1630 * Return value: number of characters in the line
1633 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1635 GtkTextRealIter *real;
1637 GtkTextLineSegment *seg;
1639 g_return_val_if_fail (iter != NULL, 0);
1641 real = gtk_text_iter_make_surreal (iter);
1646 check_invariants (iter);
1648 if (real->line_char_offset >= 0)
1650 /* We can start at the segments we've already found. */
1651 count = real->line_char_offset - real->segment_char_offset;
1652 seg = _gtk_text_iter_get_indexable_segment (iter);
1656 /* count whole line. */
1657 seg = real->line->segments;
1664 count += seg->char_count;
1669 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1670 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1676 * gtk_text_iter_get_bytes_in_line:
1677 * @iter: an iterator
1679 * Returns the number of bytes in the line containing @iter,
1680 * including the paragraph delimiters.
1682 * Return value: number of bytes in the line
1685 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1687 GtkTextRealIter *real;
1689 GtkTextLineSegment *seg;
1691 g_return_val_if_fail (iter != NULL, 0);
1693 real = gtk_text_iter_make_surreal (iter);
1698 check_invariants (iter);
1700 if (real->line_byte_offset >= 0)
1702 /* We can start at the segments we've already found. */
1703 count = real->line_byte_offset - real->segment_byte_offset;
1704 seg = _gtk_text_iter_get_indexable_segment (iter);
1708 /* count whole line. */
1709 seg = real->line->segments;
1715 count += seg->byte_count;
1720 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1721 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1727 * gtk_text_iter_get_attributes:
1728 * @iter: an iterator
1729 * @values: a #GtkTextAttributes to be filled in
1731 * Computes the effect of any tags applied to this spot in the
1732 * text. The @values parameter should be initialized to the default
1733 * settings you wish to use if no tags are in effect. You'd typically
1734 * obtain the defaults from gtk_text_view_get_default_attributes().
1736 * gtk_text_iter_get_attributes () will modify @values, applying the
1737 * effects of any tags present at @iter. If any tags affected @values,
1738 * the function returns %TRUE.
1740 * Return value: %TRUE if @values was modified
1743 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1744 GtkTextAttributes *values)
1749 /* Get the tags at this spot */
1750 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1752 /* No tags, use default style */
1753 if (tags == NULL || tag_count == 0)
1760 _gtk_text_attributes_fill_from_tags (values,
1770 * Increments/decrements
1773 /* The return value of this indicates WHETHER WE MOVED.
1774 * The return value of public functions indicates
1775 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1777 * This function will not change the iterator if
1778 * it's already on the last (end iter) line, i.e. it
1779 * won't move to the end of the last line.
1782 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1784 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1786 GtkTextLine *new_line;
1788 new_line = _gtk_text_line_next (real->line);
1789 g_assert (new_line);
1790 g_assert (new_line != real->line);
1791 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1793 real->line = new_line;
1795 real->line_byte_offset = 0;
1796 real->line_char_offset = 0;
1798 real->segment_byte_offset = 0;
1799 real->segment_char_offset = 0;
1801 /* Find first segments in new line */
1802 real->any_segment = real->line->segments;
1803 real->segment = real->any_segment;
1804 while (real->segment->char_count == 0)
1805 real->segment = real->segment->next;
1811 /* There is no way to move forward a line; we were already at
1812 * the line containing the end iterator.
1813 * However we may not be at the end iterator itself.
1821 /* The return value of this indicates WHETHER WE MOVED.
1822 * The return value of public functions indicates
1823 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1825 * This function is currently unused, thus it is #if-0-ed. It is
1826 * left here, since it's non-trivial code that might be useful in
1830 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1832 GtkTextLine *new_line;
1834 new_line = _gtk_text_line_previous (real->line);
1836 g_assert (new_line != real->line);
1838 if (new_line != NULL)
1840 real->line = new_line;
1842 real->line_byte_offset = 0;
1843 real->line_char_offset = 0;
1845 real->segment_byte_offset = 0;
1846 real->segment_char_offset = 0;
1848 /* Find first segments in new line */
1849 real->any_segment = real->line->segments;
1850 real->segment = real->any_segment;
1851 while (real->segment->char_count == 0)
1852 real->segment = real->segment->next;
1858 /* There is no way to move backward; we were already
1859 at the first line. */
1861 /* We leave real->line as-is */
1863 /* Note that we didn't clamp to the start of the first line. */
1870 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1874 forward_char (GtkTextRealIter *real)
1876 GtkTextIter *iter = (GtkTextIter*)real;
1878 check_invariants ((GtkTextIter*)real);
1880 ensure_char_offsets (real);
1882 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1884 /* Need to move to the next segment; if no next segment,
1885 need to move to next line. */
1886 return _gtk_text_iter_forward_indexable_segment (iter);
1890 /* Just moving within a segment. Keep byte count
1891 up-to-date, if it was already up-to-date. */
1893 g_assert (real->segment->type == >k_text_char_type);
1895 if (real->line_byte_offset >= 0)
1898 const char * start =
1899 real->segment->body.chars + real->segment_byte_offset;
1901 bytes = g_utf8_next_char (start) - start;
1903 real->line_byte_offset += bytes;
1904 real->segment_byte_offset += bytes;
1906 g_assert (real->segment_byte_offset < real->segment->byte_count);
1909 real->line_char_offset += 1;
1910 real->segment_char_offset += 1;
1912 adjust_char_index (real, 1);
1914 g_assert (real->segment_char_offset < real->segment->char_count);
1916 /* We moved into the middle of a segment, so the any_segment
1917 must now be the segment we're in the middle of. */
1918 real->any_segment = real->segment;
1920 check_invariants ((GtkTextIter*)real);
1922 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1930 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1932 /* Need to move to the next segment; if no next segment,
1933 need to move to next line. */
1934 GtkTextLineSegment *seg;
1935 GtkTextLineSegment *any_seg;
1936 GtkTextRealIter *real;
1940 g_return_val_if_fail (iter != NULL, FALSE);
1942 real = gtk_text_iter_make_real (iter);
1947 check_invariants (iter);
1949 if (real->line_char_offset >= 0)
1951 chars_skipped = real->segment->char_count - real->segment_char_offset;
1952 g_assert (chars_skipped > 0);
1957 if (real->line_byte_offset >= 0)
1959 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1960 g_assert (bytes_skipped > 0);
1965 /* Get first segment of any kind */
1966 any_seg = real->segment->next;
1967 /* skip non-indexable segments, if any */
1969 while (seg != NULL && seg->char_count == 0)
1974 real->any_segment = any_seg;
1975 real->segment = seg;
1977 if (real->line_byte_offset >= 0)
1979 g_assert (bytes_skipped > 0);
1980 real->segment_byte_offset = 0;
1981 real->line_byte_offset += bytes_skipped;
1984 if (real->line_char_offset >= 0)
1986 g_assert (chars_skipped > 0);
1987 real->segment_char_offset = 0;
1988 real->line_char_offset += chars_skipped;
1989 adjust_char_index (real, chars_skipped);
1992 check_invariants (iter);
1994 return !gtk_text_iter_is_end (iter);
1998 /* End of the line */
1999 if (forward_line_leaving_caches_unmodified (real))
2001 adjust_line_number (real, 1);
2002 if (real->line_char_offset >= 0)
2003 adjust_char_index (real, chars_skipped);
2005 g_assert (real->line_byte_offset == 0);
2006 g_assert (real->line_char_offset == 0);
2007 g_assert (real->segment_byte_offset == 0);
2008 g_assert (real->segment_char_offset == 0);
2009 g_assert (gtk_text_iter_starts_line (iter));
2011 check_invariants (iter);
2013 return !gtk_text_iter_is_end (iter);
2017 /* End of buffer, but iter is still at start of last segment,
2018 * not at the end iterator. We put it on the end iterator.
2021 check_invariants (iter);
2023 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2024 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2026 gtk_text_iter_forward_to_line_end (iter);
2028 g_assert (gtk_text_iter_is_end (iter));
2036 at_last_indexable_segment (GtkTextRealIter *real)
2038 GtkTextLineSegment *seg;
2040 /* Return TRUE if there are no indexable segments after
2044 seg = real->segment->next;
2047 if (seg->char_count > 0)
2054 /* Goes back to the start of the next segment, even if
2055 * we're not at the start of the current segment (always
2056 * ends up on a different segment if it returns TRUE)
2059 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2061 /* Move to the start of the previous segment; if no previous
2062 * segment, to the last segment in the previous line. This is
2063 * inherently a bit inefficient due to the singly-linked list and
2064 * tree nodes, but we can't afford the RAM for doubly-linked.
2066 GtkTextRealIter *real;
2067 GtkTextLineSegment *seg;
2068 GtkTextLineSegment *any_seg;
2069 GtkTextLineSegment *prev_seg;
2070 GtkTextLineSegment *prev_any_seg;
2074 g_return_val_if_fail (iter != NULL, FALSE);
2076 real = gtk_text_iter_make_real (iter);
2081 check_invariants (iter);
2083 /* Find first segments in line */
2084 any_seg = real->line->segments;
2086 while (seg->char_count == 0)
2089 if (seg == real->segment)
2091 /* Could probably do this case faster by hand-coding the
2095 /* We were already at the start of a line;
2096 * go back to the previous line.
2098 if (gtk_text_iter_backward_line (iter))
2100 /* Go forward to last indexable segment in line. */
2101 while (!at_last_indexable_segment (real))
2102 _gtk_text_iter_forward_indexable_segment (iter);
2104 check_invariants (iter);
2109 return FALSE; /* We were at the start of the first line. */
2112 /* We must be in the middle of a line; so find the indexable
2113 * segment just before our current segment.
2115 g_assert (seg != real->segment);
2119 prev_any_seg = any_seg;
2121 any_seg = seg->next;
2123 while (seg->char_count == 0)
2126 while (seg != real->segment);
2128 g_assert (prev_seg != NULL);
2129 g_assert (prev_any_seg != NULL);
2130 g_assert (prev_seg->char_count > 0);
2132 /* We skipped the entire previous segment, plus any
2133 * chars we were into the current segment.
2135 if (real->segment_byte_offset >= 0)
2136 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2140 if (real->segment_char_offset >= 0)
2141 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2145 real->segment = prev_seg;
2146 real->any_segment = prev_any_seg;
2147 real->segment_byte_offset = 0;
2148 real->segment_char_offset = 0;
2150 if (bytes_skipped >= 0)
2152 if (real->line_byte_offset >= 0)
2154 real->line_byte_offset -= bytes_skipped;
2155 g_assert (real->line_byte_offset >= 0);
2159 real->line_byte_offset = -1;
2161 if (chars_skipped >= 0)
2163 if (real->line_char_offset >= 0)
2165 real->line_char_offset -= chars_skipped;
2166 g_assert (real->line_char_offset >= 0);
2169 if (real->cached_char_index >= 0)
2171 real->cached_char_index -= chars_skipped;
2172 g_assert (real->cached_char_index >= 0);
2177 real->line_char_offset = -1;
2178 real->cached_char_index = -1;
2181 /* line number is unchanged. */
2183 check_invariants (iter);
2189 * gtk_text_iter_forward_char:
2190 * @iter: an iterator
2192 * Moves @iter forward by one character offset. Note that images
2193 * embedded in the buffer occupy 1 character slot, so
2194 * gtk_text_iter_forward_char () may actually move onto an image instead
2195 * of a character, if you have images in your buffer. If @iter is the
2196 * end iterator or one character before it, @iter will now point at
2197 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2198 * convenience when writing loops.
2200 * Return value: whether @iter moved and is dereferenceable
2203 gtk_text_iter_forward_char (GtkTextIter *iter)
2205 GtkTextRealIter *real;
2207 g_return_val_if_fail (iter != NULL, FALSE);
2209 real = gtk_text_iter_make_real (iter);
2215 check_invariants (iter);
2216 return forward_char (real);
2221 * gtk_text_iter_backward_char:
2222 * @iter: an iterator
2224 * Moves backward by one character offset. Returns %TRUE if movement
2225 * was possible; if @iter was the first in the buffer (character
2226 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2229 * Return value: whether movement was possible
2232 gtk_text_iter_backward_char (GtkTextIter *iter)
2234 g_return_val_if_fail (iter != NULL, FALSE);
2236 check_invariants (iter);
2238 return gtk_text_iter_backward_chars (iter, 1);
2242 Definitely we should try to linear scan as often as possible for
2243 movement within a single line, because we can't use the BTree to
2244 speed within-line searches up; for movement between lines, we would
2245 like to avoid the linear scan probably.
2247 Instead of using this constant, it might be nice to cache the line
2248 length in the iterator and linear scan if motion is within a single
2251 I guess you'd have to profile the various approaches.
2253 #define MAX_LINEAR_SCAN 150
2257 * gtk_text_iter_forward_chars:
2258 * @iter: an iterator
2259 * @count: number of characters to move, may be negative
2261 * Moves @count characters if possible (if @count would move past the
2262 * start or end of the buffer, moves to the start or end of the
2263 * buffer). The return value indicates whether the new position of
2264 * @iter is different from its original position, and dereferenceable
2265 * (the last iterator in the buffer is not dereferenceable). If @count
2266 * is 0, the function does nothing and returns %FALSE.
2268 * Return value: whether @iter moved and is dereferenceable
2271 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2273 GtkTextRealIter *real;
2275 g_return_val_if_fail (iter != NULL, FALSE);
2277 FIX_OVERFLOWS (count);
2279 real = gtk_text_iter_make_real (iter);
2283 else if (count == 0)
2286 return gtk_text_iter_backward_chars (iter, 0 - count);
2287 else if (count < MAX_LINEAR_SCAN)
2289 check_invariants (iter);
2293 if (!forward_char (real))
2298 return forward_char (real);
2302 gint current_char_index;
2303 gint new_char_index;
2305 check_invariants (iter);
2307 current_char_index = gtk_text_iter_get_offset (iter);
2309 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2310 return FALSE; /* can't move forward */
2312 new_char_index = current_char_index + count;
2313 gtk_text_iter_set_offset (iter, new_char_index);
2315 check_invariants (iter);
2317 /* Return FALSE if we're on the non-dereferenceable end
2320 if (gtk_text_iter_is_end (iter))
2328 * gtk_text_iter_backward_chars:
2329 * @iter: an iterator
2330 * @count: number of characters to move
2332 * Moves @count characters backward, if possible (if @count would move
2333 * past the start or end of the buffer, moves to the start or end of
2334 * the buffer). The return value indicates whether the iterator moved
2335 * onto a dereferenceable position; if the iterator didn't move, or
2336 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2337 * the function does nothing and returns %FALSE.
2339 * Return value: whether @iter moved and is dereferenceable
2343 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2345 GtkTextRealIter *real;
2347 g_return_val_if_fail (iter != NULL, FALSE);
2349 FIX_OVERFLOWS (count);
2351 real = gtk_text_iter_make_real (iter);
2355 else if (count == 0)
2358 return gtk_text_iter_forward_chars (iter, 0 - count);
2360 ensure_char_offsets (real);
2361 check_invariants (iter);
2363 /* <, not <=, because if count == segment_char_offset
2364 * we're going to the front of the segment and the any_segment
2367 if (count < real->segment_char_offset)
2369 /* Optimize the within-segment case */
2370 g_assert (real->segment->char_count > 0);
2371 g_assert (real->segment->type == >k_text_char_type);
2373 if (real->line_byte_offset >= 0)
2376 gint new_byte_offset;
2378 /* if in the last fourth of the segment walk backwards */
2379 if (count < real->segment_char_offset / 4)
2380 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2383 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2384 real->segment_char_offset - count);
2386 new_byte_offset = p - real->segment->body.chars;
2387 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2388 real->segment_byte_offset = new_byte_offset;
2391 real->segment_char_offset -= count;
2392 real->line_char_offset -= count;
2394 adjust_char_index (real, 0 - count);
2396 check_invariants (iter);
2402 /* We need to go back into previous segments. For now,
2403 * just keep this really simple. FIXME
2404 * use backward_indexable_segment.
2406 if (TRUE || count > MAX_LINEAR_SCAN)
2408 gint current_char_index;
2409 gint new_char_index;
2411 current_char_index = gtk_text_iter_get_offset (iter);
2413 if (current_char_index == 0)
2414 return FALSE; /* can't move backward */
2416 new_char_index = current_char_index - count;
2417 if (new_char_index < 0)
2420 gtk_text_iter_set_offset (iter, new_char_index);
2422 check_invariants (iter);
2428 /* FIXME backward_indexable_segment here */
2437 /* These two can't be implemented efficiently (always have to use
2438 * a linear scan, since that's the only way to find all the non-text
2443 * gtk_text_iter_forward_text_chars:
2444 * @iter: a #GtkTextIter
2445 * @count: number of chars to move
2447 * Moves forward by @count text characters (pixbufs, widgets,
2448 * etc. do not count as characters for this). Equivalent to moving
2449 * through the results of gtk_text_iter_get_text (), rather than
2450 * gtk_text_iter_get_slice ().
2452 * Return value: whether @iter moved and is dereferenceable
2455 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2464 * gtk_text_iter_forward_text_chars:
2465 * @iter: a #GtkTextIter
2466 * @count: number of chars to move
2468 * Moves backward by @count text characters (pixbufs, widgets,
2469 * etc. do not count as characters for this). Equivalent to moving
2470 * through the results of gtk_text_iter_get_text (), rather than
2471 * gtk_text_iter_get_slice ().
2473 * Return value: whether @iter moved and is dereferenceable
2476 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2485 * gtk_text_iter_forward_line:
2486 * @iter: an iterator
2488 * Moves @iter to the start of the next line. If the iter is already on the
2489 * last line of the buffer, moves the iter to the end of the current line.
2490 * If after the operation, the iter is at the end of the buffer and not
2491 * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
2493 * Return value: whether @iter can be dereferenced
2496 gtk_text_iter_forward_line (GtkTextIter *iter)
2498 GtkTextRealIter *real;
2500 g_return_val_if_fail (iter != NULL, FALSE);
2502 real = gtk_text_iter_make_real (iter);
2507 check_invariants (iter);
2509 if (forward_line_leaving_caches_unmodified (real))
2511 invalidate_char_index (real);
2512 adjust_line_number (real, 1);
2514 check_invariants (iter);
2516 if (gtk_text_iter_is_end (iter))
2523 /* On the last line, move to end of it */
2525 if (!gtk_text_iter_is_end (iter))
2526 gtk_text_iter_forward_to_end (iter);
2528 check_invariants (iter);
2534 * gtk_text_iter_backward_line:
2535 * @iter: an iterator
2537 * Moves @iter to the start of the previous line. Returns %TRUE if
2538 * @iter could be moved; i.e. if @iter was at character offset 0, this
2539 * function returns %FALSE. Therefore if @iter was already on line 0,
2540 * but not at the start of the line, @iter is snapped to the start of
2541 * the line and the function returns %TRUE. (Note that this implies that
2542 * in a loop calling this function, the line number may not change on
2543 * every iteration, if your first iteration is on line 0.)
2545 * Return value: whether @iter moved
2548 gtk_text_iter_backward_line (GtkTextIter *iter)
2550 GtkTextLine *new_line;
2551 GtkTextRealIter *real;
2552 gboolean offset_will_change;
2555 g_return_val_if_fail (iter != NULL, FALSE);
2557 real = gtk_text_iter_make_real (iter);
2562 check_invariants (iter);
2564 new_line = _gtk_text_line_previous (real->line);
2566 offset_will_change = FALSE;
2567 if (real->line_char_offset > 0)
2568 offset_will_change = TRUE;
2570 if (new_line != NULL)
2572 real->line = new_line;
2574 adjust_line_number (real, -1);
2578 if (!offset_will_change)
2582 invalidate_char_index (real);
2584 real->line_byte_offset = 0;
2585 real->line_char_offset = 0;
2587 real->segment_byte_offset = 0;
2588 real->segment_char_offset = 0;
2590 /* Find first segment in line */
2591 real->any_segment = real->line->segments;
2592 real->segment = _gtk_text_line_byte_to_segment (real->line,
2595 g_assert (offset == 0);
2597 /* Note that if we are on the first line, we snap to the start of
2598 * the first line and return TRUE, so TRUE means the iterator
2599 * changed, not that the line changed; this is maybe a bit
2600 * weird. I'm not sure there's an obvious right thing to do though.
2603 check_invariants (iter);
2610 * gtk_text_iter_forward_lines:
2611 * @iter: a #GtkTextIter
2612 * @count: number of lines to move forward
2614 * Moves @count lines forward, if possible (if @count would move
2615 * past the start or end of the buffer, moves to the start or end of
2616 * the buffer). The return value indicates whether the iterator moved
2617 * onto a dereferenceable position; if the iterator didn't move, or
2618 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2619 * the function does nothing and returns %FALSE. If @count is negative,
2620 * moves backward by 0 - @count lines.
2622 * Return value: whether @iter moved and is dereferenceable
2625 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2627 FIX_OVERFLOWS (count);
2630 return gtk_text_iter_backward_lines (iter, 0 - count);
2631 else if (count == 0)
2633 else if (count == 1)
2635 check_invariants (iter);
2636 return gtk_text_iter_forward_line (iter);
2642 if (gtk_text_iter_is_end (iter))
2645 old_line = gtk_text_iter_get_line (iter);
2647 gtk_text_iter_set_line (iter, old_line + count);
2649 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2651 /* count went past the last line, so move to end of last line */
2652 if (!gtk_text_iter_is_end (iter))
2653 gtk_text_iter_forward_to_end (iter);
2656 return !gtk_text_iter_is_end (iter);
2661 * gtk_text_iter_backward_lines:
2662 * @iter: a #GtkTextIter
2663 * @count: number of lines to move backward
2665 * Moves @count lines backward, if possible (if @count would move
2666 * past the start or end of the buffer, moves to the start or end of
2667 * the buffer). The return value indicates whether the iterator moved
2668 * onto a dereferenceable position; if the iterator didn't move, or
2669 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2670 * the function does nothing and returns %FALSE. If @count is negative,
2671 * moves forward by 0 - @count lines.
2673 * Return value: whether @iter moved and is dereferenceable
2676 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2678 FIX_OVERFLOWS (count);
2681 return gtk_text_iter_forward_lines (iter, 0 - count);
2682 else if (count == 0)
2684 else if (count == 1)
2686 return gtk_text_iter_backward_line (iter);
2692 old_line = gtk_text_iter_get_line (iter);
2694 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2696 return (gtk_text_iter_get_line (iter) != old_line);
2701 * gtk_text_iter_forward_visible_line:
2702 * @iter: an iterator
2704 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2705 * was a next line to move to, and %FALSE if @iter was simply moved to
2706 * the end of the buffer and is now not dereferenceable, or if @iter was
2707 * already at the end of the buffer.
2709 * Return value: whether @iter can be dereferenced
2714 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2716 while (gtk_text_iter_forward_line (iter))
2718 if (!_gtk_text_btree_char_is_invisible (iter))
2724 if (!gtk_text_iter_forward_char (iter))
2727 if (!_gtk_text_btree_char_is_invisible (iter))
2730 while (!gtk_text_iter_ends_line (iter));
2738 * gtk_text_iter_backward_visible_line:
2739 * @iter: an iterator
2741 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2742 * @iter could be moved; i.e. if @iter was at character offset 0, this
2743 * function returns %FALSE. Therefore if @iter was already on line 0,
2744 * but not at the start of the line, @iter is snapped to the start of
2745 * the line and the function returns %TRUE. (Note that this implies that
2746 * in a loop calling this function, the line number may not change on
2747 * every iteration, if your first iteration is on line 0.)
2749 * Return value: whether @iter moved
2754 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2756 while (gtk_text_iter_backward_line (iter))
2758 if (!_gtk_text_btree_char_is_invisible (iter))
2764 if (!gtk_text_iter_backward_char (iter))
2767 if (!_gtk_text_btree_char_is_invisible (iter))
2770 while (!gtk_text_iter_starts_line (iter));
2778 * gtk_text_iter_forward_visible_lines:
2779 * @iter: a #GtkTextIter
2780 * @count: number of lines to move forward
2782 * Moves @count visible lines forward, if possible (if @count would move
2783 * past the start or end of the buffer, moves to the start or end of
2784 * the buffer). The return value indicates whether the iterator moved
2785 * onto a dereferenceable position; if the iterator didn't move, or
2786 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2787 * the function does nothing and returns %FALSE. If @count is negative,
2788 * moves backward by 0 - @count lines.
2790 * Return value: whether @iter moved and is dereferenceable
2795 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2798 FIX_OVERFLOWS (count);
2801 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2802 else if (count == 0)
2804 else if (count == 1)
2806 check_invariants (iter);
2807 return gtk_text_iter_forward_visible_line (iter);
2811 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2818 * gtk_text_iter_backward_visible_lines:
2819 * @iter: a #GtkTextIter
2820 * @count: number of lines to move backward
2822 * Moves @count visible lines backward, if possible (if @count would move
2823 * past the start or end of the buffer, moves to the start or end of
2824 * the buffer). The return value indicates whether the iterator moved
2825 * onto a dereferenceable position; if the iterator didn't move, or
2826 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2827 * the function does nothing and returns %FALSE. If @count is negative,
2828 * moves forward by 0 - @count lines.
2830 * Return value: whether @iter moved and is dereferenceable
2835 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2838 FIX_OVERFLOWS (count);
2841 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2842 else if (count == 0)
2844 else if (count == 1)
2846 return gtk_text_iter_backward_visible_line (iter);
2850 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2856 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2861 gboolean already_moved_initially);
2863 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2871 find_word_end_func (const PangoLogAttr *attrs,
2876 gboolean already_moved_initially)
2878 if (!already_moved_initially)
2881 /* Find end of next word */
2882 while (offset < min_offset + len &&
2883 !attrs[offset].is_word_end)
2886 *found_offset = offset;
2888 return offset < min_offset + len;
2892 is_word_end_func (const PangoLogAttr *attrs,
2897 return attrs[offset].is_word_end;
2901 find_word_start_func (const PangoLogAttr *attrs,
2906 gboolean already_moved_initially)
2908 if (!already_moved_initially)
2911 /* Find start of prev word */
2912 while (offset >= min_offset &&
2913 !attrs[offset].is_word_start)
2916 *found_offset = offset;
2918 return offset >= min_offset;
2922 is_word_start_func (const PangoLogAttr *attrs,
2927 return attrs[offset].is_word_start;
2931 inside_word_func (const PangoLogAttr *attrs,
2936 /* Find next word start or end */
2937 while (offset >= min_offset &&
2938 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2942 return attrs[offset].is_word_start;
2947 /* Sentence funcs */
2950 find_sentence_end_func (const PangoLogAttr *attrs,
2955 gboolean already_moved_initially)
2957 if (!already_moved_initially)
2960 /* Find end of next sentence */
2961 while (offset < min_offset + len &&
2962 !attrs[offset].is_sentence_end)
2965 *found_offset = offset;
2967 return offset < min_offset + len;
2971 is_sentence_end_func (const PangoLogAttr *attrs,
2976 return attrs[offset].is_sentence_end;
2980 find_sentence_start_func (const PangoLogAttr *attrs,
2985 gboolean already_moved_initially)
2987 if (!already_moved_initially)
2990 /* Find start of prev sentence */
2991 while (offset >= min_offset &&
2992 !attrs[offset].is_sentence_start)
2995 *found_offset = offset;
2997 return offset >= min_offset;
3001 is_sentence_start_func (const PangoLogAttr *attrs,
3006 return attrs[offset].is_sentence_start;
3010 inside_sentence_func (const PangoLogAttr *attrs,
3015 /* Find next sentence start or end */
3016 while (offset >= min_offset &&
3017 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3020 return attrs[offset].is_sentence_start;
3024 test_log_attrs (const GtkTextIter *iter,
3025 TestLogAttrFunc func)
3028 const PangoLogAttr *attrs;
3030 gboolean result = FALSE;
3032 g_return_val_if_fail (iter != NULL, FALSE);
3034 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3037 offset = gtk_text_iter_get_line_offset (iter);
3039 /* char_len may be 0 and attrs will be NULL if so, if
3040 * iter is the end iter and the last line is empty.
3042 * offset may be equal to char_len, since attrs contains an entry
3043 * for one past the end
3046 if (attrs && offset <= char_len)
3047 result = (* func) (attrs, offset, 0, char_len);
3053 find_line_log_attrs (const GtkTextIter *iter,
3054 FindLogAttrFunc func,
3056 gboolean already_moved_initially)
3059 const PangoLogAttr *attrs;
3061 gboolean result = FALSE;
3063 g_return_val_if_fail (iter != NULL, FALSE);
3065 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3068 offset = gtk_text_iter_get_line_offset (iter);
3070 /* char_len may be 0 and attrs will be NULL if so, if
3071 * iter is the end iter and the last line is empty
3075 result = (* func) (attrs, offset, 0, char_len, found_offset,
3076 already_moved_initially);
3081 /* FIXME this function is very, very gratuitously slow */
3083 find_by_log_attrs (GtkTextIter *iter,
3084 FindLogAttrFunc func,
3086 gboolean already_moved_initially)
3090 gboolean found = FALSE;
3092 g_return_val_if_fail (iter != NULL, FALSE);
3096 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3102 if (gtk_text_iter_forward_line (iter))
3103 return find_by_log_attrs (iter, func, forward,
3110 /* go to end of previous line. need to check that
3111 * line is > 0 because backward_line snaps to start of
3112 * line 0 if it's on line 0
3114 if (gtk_text_iter_get_line (iter) > 0 &&
3115 gtk_text_iter_backward_line (iter))
3117 if (!gtk_text_iter_ends_line (iter))
3118 gtk_text_iter_forward_to_line_end (iter);
3120 return find_by_log_attrs (iter, func, forward,
3129 gtk_text_iter_set_line_offset (iter, offset);
3132 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3133 !gtk_text_iter_is_end (iter);
3138 find_visible_by_log_attrs (GtkTextIter *iter,
3139 FindLogAttrFunc func,
3141 gboolean already_moved_initially)
3145 g_return_val_if_fail (iter != NULL, FALSE);
3149 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3151 if (!_gtk_text_btree_char_is_invisible (&pos))
3161 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3162 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3165 move_multiple_steps (GtkTextIter *iter,
3167 OneStepFunc step_forward,
3168 MultipleStepFunc n_steps_backward)
3170 g_return_val_if_fail (iter != NULL, FALSE);
3172 FIX_OVERFLOWS (count);
3178 return n_steps_backward (iter, -count);
3180 if (!step_forward (iter))
3186 if (!step_forward (iter))
3191 return !gtk_text_iter_is_end (iter);
3196 * gtk_text_iter_forward_word_end:
3197 * @iter: a #GtkTextIter
3199 * Moves forward to the next word end. (If @iter is currently on a
3200 * word end, moves forward to the next one after that.) Word breaks
3201 * are determined by Pango and should be correct for nearly any
3202 * language (if not, the correct fix would be to the Pango word break
3205 * Return value: %TRUE if @iter moved and is not the end iterator
3208 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3210 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3214 * gtk_text_iter_backward_word_start:
3215 * @iter: a #GtkTextIter
3217 * Moves backward to the previous word start. (If @iter is currently on a
3218 * word start, moves backward to the next one after that.) Word breaks
3219 * are determined by Pango and should be correct for nearly any
3220 * language (if not, the correct fix would be to the Pango word break
3223 * Return value: %TRUE if @iter moved and is not the end iterator
3226 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3228 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3231 /* FIXME a loop around a truly slow function means
3232 * a truly spectacularly slow function.
3236 * gtk_text_iter_forward_word_ends:
3237 * @iter: a #GtkTextIter
3238 * @count: number of times to move
3240 * Calls gtk_text_iter_forward_word_end() up to @count times.
3242 * Return value: %TRUE if @iter moved and is not the end iterator
3245 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3248 return move_multiple_steps (iter, count,
3249 gtk_text_iter_forward_word_end,
3250 gtk_text_iter_backward_word_starts);
3254 * gtk_text_iter_backward_word_starts
3255 * @iter: a #GtkTextIter
3256 * @count: number of times to move
3258 * Calls gtk_text_iter_backward_word_start() up to @count times.
3260 * Return value: %TRUE if @iter moved and is not the end iterator
3263 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3266 return move_multiple_steps (iter, count,
3267 gtk_text_iter_backward_word_start,
3268 gtk_text_iter_forward_word_ends);
3272 * gtk_text_iter_forward_visible_word_end:
3273 * @iter: a #GtkTextIter
3275 * Moves forward to the next visible word end. (If @iter is currently on a
3276 * word end, moves forward to the next one after that.) Word breaks
3277 * are determined by Pango and should be correct for nearly any
3278 * language (if not, the correct fix would be to the Pango word break
3281 * Return value: %TRUE if @iter moved and is not the end iterator
3286 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3288 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3292 * gtk_text_iter_backward_visible_word_start:
3293 * @iter: a #GtkTextIter
3295 * Moves backward to the previous visible word start. (If @iter is currently
3296 * on a word start, moves backward to the next one after that.) Word breaks
3297 * are determined by Pango and should be correct for nearly any
3298 * language (if not, the correct fix would be to the Pango word break
3301 * Return value: %TRUE if @iter moved and is not the end iterator
3306 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3308 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3312 * gtk_text_iter_forward_visible_word_ends:
3313 * @iter: a #GtkTextIter
3314 * @count: number of times to move
3316 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3318 * Return value: %TRUE if @iter moved and is not the end iterator
3323 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3326 return move_multiple_steps (iter, count,
3327 gtk_text_iter_forward_visible_word_end,
3328 gtk_text_iter_backward_visible_word_starts);
3332 * gtk_text_iter_backward_visible_word_starts
3333 * @iter: a #GtkTextIter
3334 * @count: number of times to move
3336 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3338 * Return value: %TRUE if @iter moved and is not the end iterator
3343 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3346 return move_multiple_steps (iter, count,
3347 gtk_text_iter_backward_visible_word_start,
3348 gtk_text_iter_forward_visible_word_ends);
3352 * gtk_text_iter_starts_word:
3353 * @iter: a #GtkTextIter
3355 * Determines whether @iter begins a natural-language word. Word
3356 * breaks are determined by Pango and should be correct for nearly any
3357 * language (if not, the correct fix would be to the Pango word break
3360 * Return value: %TRUE if @iter is at the start of a word
3363 gtk_text_iter_starts_word (const GtkTextIter *iter)
3365 return test_log_attrs (iter, is_word_start_func);
3369 * gtk_text_iter_ends_word:
3370 * @iter: a #GtkTextIter
3372 * Determines whether @iter ends a natural-language word. Word breaks
3373 * are determined by Pango and should be correct for nearly any
3374 * language (if not, the correct fix would be to the Pango word break
3377 * Return value: %TRUE if @iter is at the end of a word
3380 gtk_text_iter_ends_word (const GtkTextIter *iter)
3382 return test_log_attrs (iter, is_word_end_func);
3386 * gtk_text_iter_inside_word:
3387 * @iter: a #GtkTextIter
3389 * Determines whether @iter is inside a natural-language word (as
3390 * opposed to say inside some whitespace). Word breaks are determined
3391 * by Pango and should be correct for nearly any language (if not, the
3392 * correct fix would be to the Pango word break algorithms).
3394 * Return value: %TRUE if @iter is inside a word
3397 gtk_text_iter_inside_word (const GtkTextIter *iter)
3399 return test_log_attrs (iter, inside_word_func);
3403 * gtk_text_iter_starts_sentence:
3404 * @iter: a #GtkTextIter
3406 * Determines whether @iter begins a sentence. Sentence boundaries are
3407 * determined by Pango and should be correct for nearly any language
3408 * (if not, the correct fix would be to the Pango text boundary
3411 * Return value: %TRUE if @iter is at the start of a sentence.
3414 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3416 return test_log_attrs (iter, is_sentence_start_func);
3420 * gtk_text_iter_ends_sentence:
3421 * @iter: a #GtkTextIter
3423 * Determines whether @iter ends a sentence. Sentence boundaries are
3424 * determined by Pango and should be correct for nearly any language
3425 * (if not, the correct fix would be to the Pango text boundary
3428 * Return value: %TRUE if @iter is at the end of a sentence.
3431 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3433 return test_log_attrs (iter, is_sentence_end_func);
3437 * gtk_text_iter_inside_sentence:
3438 * @iter: a #GtkTextIter
3440 * Determines whether @iter is inside a sentence (as opposed to in
3441 * between two sentences, e.g. after a period and before the first
3442 * letter of the next sentence). Sentence boundaries are determined
3443 * by Pango and should be correct for nearly any language (if not, the
3444 * correct fix would be to the Pango text boundary algorithms).
3446 * Return value: %TRUE if @iter is inside a sentence.
3449 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3451 return test_log_attrs (iter, inside_sentence_func);
3455 * gtk_text_iter_forward_sentence_end:
3456 * @iter: a #GtkTextIter
3458 * Moves forward to the next sentence end. (If @iter is at the end of
3459 * a sentence, moves to the next end of sentence.) Sentence
3460 * boundaries are determined by Pango and should be correct for nearly
3461 * any language (if not, the correct fix would be to the Pango text
3462 * boundary algorithms).
3464 * Return value: %TRUE if @iter moved and is not the end iterator
3467 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3469 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3473 * gtk_text_iter_backward_sentence_start:
3474 * @iter: a #GtkTextIter
3476 * Moves backward to the previous sentence start; if @iter is already at
3477 * the start of a sentence, moves backward to the next one. Sentence
3478 * boundaries are determined by Pango and should be correct for nearly
3479 * any language (if not, the correct fix would be to the Pango text
3480 * boundary algorithms).
3482 * Return value: %TRUE if @iter moved and is not the end iterator
3485 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3487 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3490 /* FIXME a loop around a truly slow function means
3491 * a truly spectacularly slow function.
3494 * gtk_text_iter_forward_sentence_ends:
3495 * @iter: a #GtkTextIter
3496 * @count: number of sentences to move
3498 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3499 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3500 * negative, moves backward instead of forward.
3502 * Return value: %TRUE if @iter moved and is not the end iterator
3505 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3508 return move_multiple_steps (iter, count,
3509 gtk_text_iter_forward_sentence_end,
3510 gtk_text_iter_backward_sentence_starts);
3514 * gtk_text_iter_backward_sentence_starts:
3515 * @iter: a #GtkTextIter
3516 * @count: number of sentences to move
3518 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3519 * or until it returns %FALSE. If @count is negative, moves forward
3520 * instead of backward.
3522 * Return value: %TRUE if @iter moved and is not the end iterator
3525 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3528 return move_multiple_steps (iter, count,
3529 gtk_text_iter_backward_sentence_start,
3530 gtk_text_iter_forward_sentence_ends);
3534 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3539 gboolean already_moved_initially)
3541 if (!already_moved_initially)
3544 while (offset < (min_offset + len) &&
3545 !attrs[offset].is_cursor_position)
3548 *found_offset = offset;
3550 return offset < (min_offset + len);
3554 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3559 gboolean already_moved_initially)
3561 if (!already_moved_initially)
3564 while (offset > min_offset &&
3565 !attrs[offset].is_cursor_position)
3568 *found_offset = offset;
3570 return offset >= min_offset;
3574 is_cursor_pos_func (const PangoLogAttr *attrs,
3579 return attrs[offset].is_cursor_position;
3583 * gtk_text_iter_forward_cursor_position:
3584 * @iter: a #GtkTextIter
3586 * Moves @iter forward by a single cursor position. Cursor positions
3587 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3588 * surprisingly, there may not be a cursor position between all
3589 * characters. The most common example for European languages would be
3590 * a carriage return/newline sequence. For some Unicode characters,
3591 * the equivalent of say the letter "a" with an accent mark will be
3592 * represented as two characters, first the letter then a "combining
3593 * mark" that causes the accent to be rendered; so the cursor can't go
3594 * between those two characters. See also the #PangoLogAttr structure and
3595 * pango_break() function.
3597 * Return value: %TRUE if we moved and the new position is dereferenceable
3600 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3602 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3606 * gtk_text_iter_backward_cursor_position:
3607 * @iter: a #GtkTextIter
3609 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3611 * Return value: %TRUE if we moved
3614 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3616 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3620 * gtk_text_iter_forward_cursor_positions:
3621 * @iter: a #GtkTextIter
3622 * @count: number of positions to move
3624 * Moves up to @count cursor positions. See
3625 * gtk_text_iter_forward_cursor_position() for details.
3627 * Return value: %TRUE if we moved and the new position is dereferenceable
3630 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3633 return move_multiple_steps (iter, count,
3634 gtk_text_iter_forward_cursor_position,
3635 gtk_text_iter_backward_cursor_positions);
3639 * gtk_text_iter_backward_cursor_positions:
3640 * @iter: a #GtkTextIter
3641 * @count: number of positions to move
3643 * Moves up to @count cursor positions. See
3644 * gtk_text_iter_forward_cursor_position() for details.
3646 * Return value: %TRUE if we moved and the new position is dereferenceable
3649 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3652 return move_multiple_steps (iter, count,
3653 gtk_text_iter_backward_cursor_position,
3654 gtk_text_iter_forward_cursor_positions);
3658 * gtk_text_iter_forward_visible_cursor_position:
3659 * @iter: a #GtkTextIter
3661 * Moves @iter forward to the next visible cursor position. See
3662 * gtk_text_iter_forward_cursor_position() for details.
3664 * Return value: %TRUE if we moved and the new position is dereferenceable
3669 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3671 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3675 * gtk_text_iter_backward_visible_cursor_position:
3676 * @iter: a #GtkTextIter
3678 * Moves @iter forward to the previous visible cursor position. See
3679 * gtk_text_iter_backward_cursor_position() for details.
3681 * Return value: %TRUE if we moved and the new position is dereferenceable
3686 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3688 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3692 * gtk_text_iter_forward_visible_cursor_positions:
3693 * @iter: a #GtkTextIter
3694 * @count: number of positions to move
3696 * Moves up to @count visible cursor positions. See
3697 * gtk_text_iter_forward_cursor_position() for details.
3699 * Return value: %TRUE if we moved and the new position is dereferenceable
3704 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3707 return move_multiple_steps (iter, count,
3708 gtk_text_iter_forward_visible_cursor_position,
3709 gtk_text_iter_backward_visible_cursor_positions);
3713 * gtk_text_iter_backward_visible_cursor_positions:
3714 * @iter: a #GtkTextIter
3715 * @count: number of positions to move
3717 * Moves up to @count visible cursor positions. See
3718 * gtk_text_iter_backward_cursor_position() for details.
3720 * Return value: %TRUE if we moved and the new position is dereferenceable
3725 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3728 return move_multiple_steps (iter, count,
3729 gtk_text_iter_backward_visible_cursor_position,
3730 gtk_text_iter_forward_visible_cursor_positions);
3734 * gtk_text_iter_is_cursor_position:
3735 * @iter: a #GtkTextIter
3737 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3738 * pango_break() for details on what a cursor position is.
3740 * Return value: %TRUE if the cursor can be placed at @iter
3743 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3745 return test_log_attrs (iter, is_cursor_pos_func);
3749 * gtk_text_iter_set_line_offset:
3750 * @iter: a #GtkTextIter
3751 * @char_on_line: a character offset relative to the start of @iter's current line
3753 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3754 * (not byte) offset. The given character offset must be less than or
3755 * equal to the number of characters in the line; if equal, @iter
3756 * moves to the start of the next line. See
3757 * gtk_text_iter_set_line_index() if you have a byte index rather than
3758 * a character offset.
3762 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3765 GtkTextRealIter *real;
3768 g_return_if_fail (iter != NULL);
3770 real = gtk_text_iter_make_surreal (iter);
3775 check_invariants (iter);
3777 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3779 g_return_if_fail (char_on_line <= chars_in_line);
3781 if (char_on_line < chars_in_line)
3782 iter_set_from_char_offset (real, real->line, char_on_line);
3784 gtk_text_iter_forward_line (iter); /* set to start of next line */
3786 check_invariants (iter);
3790 * gtk_text_iter_set_line_index:
3791 * @iter: a #GtkTextIter
3792 * @byte_on_line: a byte index relative to the start of @iter's current line
3794 * Same as gtk_text_iter_set_line_offset(), but works with a
3795 * <emphasis>byte</emphasis> index. The given byte index must be at
3796 * the start of a character, it can't be in the middle of a UTF-8
3797 * encoded character.
3801 gtk_text_iter_set_line_index (GtkTextIter *iter,
3804 GtkTextRealIter *real;
3807 g_return_if_fail (iter != NULL);
3809 real = gtk_text_iter_make_surreal (iter);
3814 check_invariants (iter);
3816 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3818 g_return_if_fail (byte_on_line <= bytes_in_line);
3820 if (byte_on_line < bytes_in_line)
3821 iter_set_from_byte_offset (real, real->line, byte_on_line);
3823 gtk_text_iter_forward_line (iter);
3825 if (real->segment->type == >k_text_char_type &&
3826 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3827 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3828 "character; this will crash the text buffer. "
3829 "Byte indexes must refer to the start of a character.",
3830 G_STRLOC, byte_on_line);
3832 check_invariants (iter);
3837 * gtk_text_iter_set_visible_line_offset:
3838 * @iter: a #GtkTextIter
3839 * @char_on_line: a character offset
3841 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3842 * characters, i.e. text with a tag making it invisible is not
3843 * counted in the offset.
3846 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3849 gint chars_seen = 0;
3852 g_return_if_fail (iter != NULL);
3854 gtk_text_iter_set_line_offset (iter, 0);
3858 /* For now we use a ludicrously slow implementation */
3859 while (chars_seen < char_on_line)
3861 if (!_gtk_text_btree_char_is_invisible (&pos))
3864 if (!gtk_text_iter_forward_char (&pos))
3867 if (chars_seen == char_on_line)
3871 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3874 gtk_text_iter_forward_line (iter);
3878 * gtk_text_iter_set_visible_line_index:
3879 * @iter: a #GtkTextIter
3880 * @byte_on_line: a byte index
3882 * Like gtk_text_iter_set_line_index(), but the index is in visible
3883 * bytes, i.e. text with a tag making it invisible is not counted
3887 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3890 GtkTextRealIter *real;
3893 GtkTextLineSegment *seg;
3895 g_return_if_fail (iter != NULL);
3897 gtk_text_iter_set_line_offset (iter, 0);
3901 real = gtk_text_iter_make_real (&pos);
3906 ensure_byte_offsets (real);
3908 check_invariants (&pos);
3910 seg = _gtk_text_iter_get_indexable_segment (&pos);
3912 while (seg != NULL && byte_on_line > 0)
3914 if (!_gtk_text_btree_char_is_invisible (&pos))
3916 if (byte_on_line < seg->byte_count)
3918 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3923 byte_on_line -= seg->byte_count;
3926 offset += seg->byte_count;
3927 _gtk_text_iter_forward_indexable_segment (&pos);
3928 seg = _gtk_text_iter_get_indexable_segment (&pos);
3931 if (byte_on_line == 0)
3934 gtk_text_iter_forward_line (iter);
3938 * gtk_text_iter_set_line:
3939 * @iter: a #GtkTextIter
3940 * @line_number: line number (counted from 0)
3942 * Moves iterator @iter to the start of the line @line_number. If
3943 * @line_number is negative or larger than the number of lines in the
3944 * buffer, moves @iter to the start of the last line in the buffer.
3948 gtk_text_iter_set_line (GtkTextIter *iter,
3953 GtkTextRealIter *real;
3955 g_return_if_fail (iter != NULL);
3957 real = gtk_text_iter_make_surreal (iter);
3962 check_invariants (iter);
3964 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3966 iter_set_from_char_offset (real, line, 0);
3968 /* We might as well cache this, since we know it. */
3969 real->cached_line_number = real_line;
3971 check_invariants (iter);
3975 * gtk_text_iter_set_offset:
3976 * @iter: a #GtkTextIter
3977 * @char_offset: a character number
3979 * Sets @iter to point to @char_offset. @char_offset counts from the start
3980 * of the entire text buffer, starting with 0.
3983 gtk_text_iter_set_offset (GtkTextIter *iter,
3987 GtkTextRealIter *real;
3989 gint real_char_index;
3991 g_return_if_fail (iter != NULL);
3993 real = gtk_text_iter_make_surreal (iter);
3998 check_invariants (iter);
4000 if (real->cached_char_index >= 0 &&
4001 real->cached_char_index == char_offset)
4004 line = _gtk_text_btree_get_line_at_char (real->tree,
4009 iter_set_from_char_offset (real, line, real_char_index - line_start);
4011 /* Go ahead and cache this since we have it. */
4012 real->cached_char_index = real_char_index;
4014 check_invariants (iter);
4018 * gtk_text_iter_forward_to_end:
4019 * @iter: a #GtkTextIter
4021 * Moves @iter forward to the "end iterator," which points one past the last
4022 * valid character in the buffer. gtk_text_iter_get_char() called on the
4023 * end iterator returns 0, which is convenient for writing loops.
4026 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4028 GtkTextBuffer *buffer;
4029 GtkTextRealIter *real;
4031 g_return_if_fail (iter != NULL);
4033 real = gtk_text_iter_make_surreal (iter);
4038 buffer = _gtk_text_btree_get_buffer (real->tree);
4040 gtk_text_buffer_get_end_iter (buffer, iter);
4043 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4044 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4045 * If all else fails we could cache the para delimiter pos in the iter.
4046 * I think forward_to_line_end() actually gets called fairly often.
4049 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4054 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4055 _gtk_text_iter_get_btree (&end)))
4057 gtk_text_iter_forward_to_end (&end);
4061 /* if we aren't on the last line, go forward to start of next line, then scan
4062 * back for the delimiters on the previous line
4064 gtk_text_iter_forward_line (&end);
4065 gtk_text_iter_backward_char (&end);
4066 while (!gtk_text_iter_ends_line (&end))
4067 gtk_text_iter_backward_char (&end);
4070 return gtk_text_iter_get_line_offset (&end);
4074 * gtk_text_iter_forward_to_line_end:
4075 * @iter: a #GtkTextIter
4077 * Moves the iterator to point to the paragraph delimiter characters,
4078 * which will be either a newline, a carriage return, a carriage
4079 * return/newline in sequence, or the Unicode paragraph separator
4080 * character. If the iterator is already at the paragraph delimiter
4081 * characters, moves to the paragraph delimiter characters for the
4082 * next line. If @iter is on the last line in the buffer, which does
4083 * not end in paragraph delimiters, moves to the end iterator (end of
4084 * the last line), and returns %FALSE.
4086 * Return value: %TRUE if we moved and the new location is not the end iterator
4089 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4091 gint current_offset;
4095 g_return_val_if_fail (iter != NULL, FALSE);
4097 current_offset = gtk_text_iter_get_line_offset (iter);
4098 new_offset = find_paragraph_delimiter_for_line (iter);
4100 if (current_offset < new_offset)
4102 /* Move to end of this line. */
4103 gtk_text_iter_set_line_offset (iter, new_offset);
4104 return !gtk_text_iter_is_end (iter);
4108 /* Move to end of next line. */
4109 if (gtk_text_iter_forward_line (iter))
4111 /* We don't want to move past all
4114 if (!gtk_text_iter_ends_line (iter))
4115 gtk_text_iter_forward_to_line_end (iter);
4116 return !gtk_text_iter_is_end (iter);
4124 * gtk_text_iter_forward_to_tag_toggle:
4125 * @iter: a #GtkTextIter
4126 * @tag: (allow-none): a #GtkTextTag, or %NULL
4128 * Moves forward to the next toggle (on or off) of the
4129 * #GtkTextTag @tag, or to the next toggle of any tag if
4130 * @tag is %NULL. If no matching tag toggles are found,
4131 * returns %FALSE, otherwise %TRUE. Does not return toggles
4132 * located at @iter, only toggles after @iter. Sets @iter to
4133 * the location of the toggle, or to the end of the buffer
4134 * if no toggle is found.
4136 * Return value: whether we found a tag toggle after @iter
4139 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4142 GtkTextLine *next_line;
4143 GtkTextLine *current_line;
4144 GtkTextRealIter *real;
4146 g_return_val_if_fail (iter != NULL, FALSE);
4148 real = gtk_text_iter_make_real (iter);
4153 check_invariants (iter);
4155 current_line = real->line;
4156 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4159 while (_gtk_text_iter_forward_indexable_segment (iter))
4161 /* If we went forward to a line that couldn't contain a toggle
4162 for the tag, then skip forward to a line that could contain
4163 it. This potentially skips huge hunks of the tree, so we
4164 aren't a purely linear search. */
4165 if (real->line != current_line)
4167 if (next_line == NULL)
4169 /* End of search. Set to end of buffer. */
4170 _gtk_text_btree_get_end_iter (real->tree, iter);
4174 if (real->line != next_line)
4175 iter_set_from_byte_offset (real, next_line, 0);
4177 current_line = real->line;
4178 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4183 if (gtk_text_iter_toggles_tag (iter, tag))
4185 /* If there's a toggle here, it isn't indexable so
4186 any_segment can't be the indexable segment. */
4187 g_assert (real->any_segment != real->segment);
4192 /* Check end iterator for tags */
4193 if (gtk_text_iter_toggles_tag (iter, tag))
4195 /* If there's a toggle here, it isn't indexable so
4196 any_segment can't be the indexable segment. */
4197 g_assert (real->any_segment != real->segment);
4201 /* Reached end of buffer */
4206 * gtk_text_iter_backward_to_tag_toggle:
4207 * @iter: a #GtkTextIter
4208 * @tag: (allow-none): a #GtkTextTag, or %NULL
4210 * Moves backward to the next toggle (on or off) of the
4211 * #GtkTextTag @tag, or to the next toggle of any tag if
4212 * @tag is %NULL. If no matching tag toggles are found,
4213 * returns %FALSE, otherwise %TRUE. Does not return toggles
4214 * located at @iter, only toggles before @iter. Sets @iter
4215 * to the location of the toggle, or the start of the buffer
4216 * if no toggle is found.
4218 * Return value: whether we found a tag toggle before @iter
4221 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4224 GtkTextLine *prev_line;
4225 GtkTextLine *current_line;
4226 GtkTextRealIter *real;
4228 g_return_val_if_fail (iter != NULL, FALSE);
4230 real = gtk_text_iter_make_real (iter);
4235 check_invariants (iter);
4237 current_line = real->line;
4238 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4242 /* If we're at segment start, go to the previous segment;
4243 * if mid-segment, snap to start of current segment.
4245 if (is_segment_start (real))
4247 if (!_gtk_text_iter_backward_indexable_segment (iter))
4252 ensure_char_offsets (real);
4254 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4260 /* If we went backward to a line that couldn't contain a toggle
4261 * for the tag, then skip backward further to a line that
4262 * could contain it. This potentially skips huge hunks of the
4263 * tree, so we aren't a purely linear search.
4265 if (real->line != current_line)
4267 if (prev_line == NULL)
4269 /* End of search. Set to start of buffer. */
4270 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4274 if (real->line != prev_line)
4276 /* Set to last segment in prev_line (could do this
4279 iter_set_from_byte_offset (real, prev_line, 0);
4281 while (!at_last_indexable_segment (real))
4282 _gtk_text_iter_forward_indexable_segment (iter);
4285 current_line = real->line;
4286 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4291 if (gtk_text_iter_toggles_tag (iter, tag))
4293 /* If there's a toggle here, it isn't indexable so
4294 * any_segment can't be the indexable segment.
4296 g_assert (real->any_segment != real->segment);
4300 while (_gtk_text_iter_backward_indexable_segment (iter));
4302 /* Reached front of buffer */
4307 matches_pred (GtkTextIter *iter,
4308 GtkTextCharPredicate pred,
4313 ch = gtk_text_iter_get_char (iter);
4315 return (*pred) (ch, user_data);
4319 * gtk_text_iter_forward_find_char:
4320 * @iter: a #GtkTextIter
4321 * @pred: a function to be called on each character
4322 * @user_data: user data for @pred
4323 * @limit: (allow-none): search limit, or %NULL for none
4325 * Advances @iter, calling @pred on each character. If
4326 * @pred returns %TRUE, returns %TRUE and stops scanning.
4327 * If @pred never returns %TRUE, @iter is set to @limit if
4328 * @limit is non-%NULL, otherwise to the end iterator.
4330 * Return value: whether a match was found
4333 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4334 GtkTextCharPredicate pred,
4336 const GtkTextIter *limit)
4338 g_return_val_if_fail (iter != NULL, FALSE);
4339 g_return_val_if_fail (pred != NULL, FALSE);
4342 gtk_text_iter_compare (iter, limit) >= 0)
4345 while ((limit == NULL ||
4346 !gtk_text_iter_equal (limit, iter)) &&
4347 gtk_text_iter_forward_char (iter))
4349 if (matches_pred (iter, pred, user_data))
4357 * gtk_text_iter_backward_find_char:
4358 * @iter: a #GtkTextIter
4359 * @pred: function to be called on each character
4360 * @user_data: user data for @pred
4361 * @limit: (allow-none): search limit, or %NULL for none
4363 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4365 * Return value: whether a match was found
4368 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4369 GtkTextCharPredicate pred,
4371 const GtkTextIter *limit)
4373 g_return_val_if_fail (iter != NULL, FALSE);
4374 g_return_val_if_fail (pred != NULL, FALSE);
4377 gtk_text_iter_compare (iter, limit) <= 0)
4380 while ((limit == NULL ||
4381 !gtk_text_iter_equal (limit, iter)) &&
4382 gtk_text_iter_backward_char (iter))
4384 if (matches_pred (iter, pred, user_data))
4392 forward_chars_with_skipping (GtkTextIter *iter,
4394 gboolean skip_invisible,
4395 gboolean skip_nontext)
4400 g_return_if_fail (count >= 0);
4406 gboolean ignored = FALSE;
4409 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4414 _gtk_text_btree_char_is_invisible (iter))
4417 gtk_text_iter_forward_char (iter);
4425 lines_match (const GtkTextIter *start,
4426 const gchar **lines,
4427 gboolean visible_only,
4429 GtkTextIter *match_start,
4430 GtkTextIter *match_end)
4437 if (*lines == NULL || **lines == '\0')
4440 *match_start = *start;
4443 *match_end = *start;
4448 gtk_text_iter_forward_line (&next);
4450 /* No more text in buffer, but *lines is nonempty */
4451 if (gtk_text_iter_equal (start, &next))
4459 line_text = gtk_text_iter_get_visible_slice (start, &next);
4461 line_text = gtk_text_iter_get_slice (start, &next);
4466 line_text = gtk_text_iter_get_visible_text (start, &next);
4468 line_text = gtk_text_iter_get_text (start, &next);
4471 if (match_start) /* if this is the first line we're matching */
4472 found = strstr (line_text, *lines);
4475 /* If it's not the first line, we have to match from the
4476 * start of the line.
4478 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4490 /* Get offset to start of search string */
4491 offset = g_utf8_strlen (line_text, found - line_text);
4495 /* If match start needs to be returned, set it to the
4496 * start of the search string.
4500 *match_start = next;
4502 forward_chars_with_skipping (match_start, offset,
4503 visible_only, !slice);
4506 /* Go to end of search string */
4507 offset += g_utf8_strlen (*lines, -1);
4509 forward_chars_with_skipping (&next, offset,
4510 visible_only, !slice);
4519 /* pass NULL for match_start, since we don't need to find the
4522 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4525 /* strsplit () that retains the delimiter as part of the string. */
4527 strbreakup (const char *string,
4528 const char *delimiter,
4531 GSList *string_list = NULL, *slist;
4532 gchar **str_array, *s;
4535 g_return_val_if_fail (string != NULL, NULL);
4536 g_return_val_if_fail (delimiter != NULL, NULL);
4539 max_tokens = G_MAXINT;
4541 s = strstr (string, delimiter);
4544 guint delimiter_len = strlen (delimiter);
4551 len = s - string + delimiter_len;
4552 new_string = g_new (gchar, len + 1);
4553 strncpy (new_string, string, len);
4554 new_string[len] = 0;
4555 string_list = g_slist_prepend (string_list, new_string);
4557 string = s + delimiter_len;
4558 s = strstr (string, delimiter);
4560 while (--max_tokens && s);
4565 string_list = g_slist_prepend (string_list, g_strdup (string));
4568 str_array = g_new (gchar*, n);
4572 str_array[i--] = NULL;
4573 for (slist = string_list; slist; slist = slist->next)
4574 str_array[i--] = slist->data;
4576 g_slist_free (string_list);
4582 * gtk_text_iter_forward_search:
4583 * @iter: start of search
4584 * @str: a search string
4585 * @flags: flags affecting how the search is done
4586 * @match_start: (allow-none): return location for start of match, or %NULL
4587 * @match_end: (allow-none): return location for end of match, or %NULL
4588 * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
4590 * Searches forward for @str. Any match is returned by setting
4591 * @match_start to the first character of the match and @match_end to the
4592 * first character after the match. The search will not continue past
4593 * @limit. Note that a search is a linear or O(n) operation, so you
4594 * may wish to use @limit to avoid locking up your UI on large
4597 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4598 * have invisible text interspersed in @str. i.e. @str will be a
4599 * possibly-noncontiguous subsequence of the matched range. similarly,
4600 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4601 * pixbufs or child widgets mixed inside the matched range. If these
4602 * flags are not given, the match must be exact; the special 0xFFFC
4603 * character in @str will match embedded pixbufs or child widgets.
4605 * Return value: whether a match was found
4608 gtk_text_iter_forward_search (const GtkTextIter *iter,
4610 GtkTextSearchFlags flags,
4611 GtkTextIter *match_start,
4612 GtkTextIter *match_end,
4613 const GtkTextIter *limit)
4615 gchar **lines = NULL;
4617 gboolean retval = FALSE;
4619 gboolean visible_only;
4622 g_return_val_if_fail (iter != NULL, FALSE);
4623 g_return_val_if_fail (str != NULL, FALSE);
4626 gtk_text_iter_compare (iter, limit) >= 0)
4631 /* If we can move one char, return the empty string there */
4634 if (gtk_text_iter_forward_char (&match))
4637 gtk_text_iter_equal (&match, limit))
4641 *match_start = match;
4650 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4651 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4653 /* locate all lines */
4655 lines = strbreakup (str, "\n", -1);
4661 /* This loop has an inefficient worst-case, where
4662 * gtk_text_iter_get_text () is called repeatedly on
4668 gtk_text_iter_compare (&search, limit) >= 0)
4671 if (lines_match (&search, (const gchar**)lines,
4672 visible_only, slice, &match, &end))
4674 if (limit == NULL ||
4676 gtk_text_iter_compare (&end, limit) <= 0))
4681 *match_start = match;
4690 while (gtk_text_iter_forward_line (&search));
4692 g_strfreev ((gchar**)lines);
4698 vectors_equal_ignoring_trailing (gchar **vec1,
4701 /* Ignores trailing chars in vec2's last line */
4710 if (strcmp (*i1, *i2) != 0)
4712 if (*(i2 + 1) == NULL) /* if this is the last line */
4714 gint len1 = strlen (*i1);
4715 gint len2 = strlen (*i2);
4718 strncmp (*i1, *i2, len1) == 0)
4720 /* We matched ignoring the trailing stuff in vec2 */
4745 typedef struct _LinesWindow LinesWindow;
4751 GtkTextIter first_line_start;
4752 GtkTextIter first_line_end;
4754 gboolean visible_only;
4758 lines_window_init (LinesWindow *win,
4759 const GtkTextIter *start)
4762 GtkTextIter line_start;
4763 GtkTextIter line_end;
4765 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4768 if (gtk_text_iter_is_start (start) ||
4769 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4771 /* Already at the end, or not enough lines to match */
4772 win->lines = g_new0 (gchar*, 1);
4777 line_start = *start;
4780 /* Move to start iter to start of line */
4781 gtk_text_iter_set_line_offset (&line_start, 0);
4783 if (gtk_text_iter_equal (&line_start, &line_end))
4785 /* we were already at the start; so go back one line */
4786 gtk_text_iter_backward_line (&line_start);
4789 win->first_line_start = line_start;
4790 win->first_line_end = line_end;
4792 win->lines = g_new0 (gchar*, win->n_lines + 1);
4794 i = win->n_lines - 1;
4801 if (win->visible_only)
4802 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4804 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4808 if (win->visible_only)
4809 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4811 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4814 win->lines[i] = line_text;
4816 line_end = line_start;
4817 gtk_text_iter_backward_line (&line_start);
4824 lines_window_back (LinesWindow *win)
4826 GtkTextIter new_start;
4829 new_start = win->first_line_start;
4831 if (!gtk_text_iter_backward_line (&new_start))
4835 win->first_line_start = new_start;
4836 win->first_line_end = new_start;
4838 gtk_text_iter_forward_line (&win->first_line_end);
4843 if (win->visible_only)
4844 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4845 &win->first_line_end);
4847 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4848 &win->first_line_end);
4852 if (win->visible_only)
4853 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4854 &win->first_line_end);
4856 line_text = gtk_text_iter_get_text (&win->first_line_start,
4857 &win->first_line_end);
4860 /* Move lines to make room for first line. */
4861 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4863 *win->lines = line_text;
4865 /* Free old last line and NULL-terminate */
4866 g_free (win->lines[win->n_lines]);
4867 win->lines[win->n_lines] = NULL;
4873 lines_window_free (LinesWindow *win)
4875 g_strfreev (win->lines);
4879 * gtk_text_iter_backward_search:
4880 * @iter: a #GtkTextIter where the search begins
4881 * @str: search string
4882 * @flags: bitmask of flags affecting the search
4883 * @match_start: (allow-none): return location for start of match, or %NULL
4884 * @match_end: (allow-none): return location for end of match, or %NULL
4885 * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
4887 * Same as gtk_text_iter_forward_search(), but moves backward.
4889 * Return value: whether a match was found
4892 gtk_text_iter_backward_search (const GtkTextIter *iter,
4894 GtkTextSearchFlags flags,
4895 GtkTextIter *match_start,
4896 GtkTextIter *match_end,
4897 const GtkTextIter *limit)
4899 gchar **lines = NULL;
4903 gboolean retval = FALSE;
4904 gboolean visible_only;
4907 g_return_val_if_fail (iter != NULL, FALSE);
4908 g_return_val_if_fail (str != NULL, FALSE);
4911 gtk_text_iter_compare (limit, iter) > 0)
4916 /* If we can move one char, return the empty string there */
4917 GtkTextIter match = *iter;
4919 if (limit && gtk_text_iter_equal (limit, &match))
4922 if (gtk_text_iter_backward_char (&match))
4925 *match_start = match;
4934 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4935 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4937 /* locate all lines */
4939 lines = strbreakup (str, "\n", -1);
4949 win.n_lines = n_lines;
4951 win.visible_only = visible_only;
4953 lines_window_init (&win, iter);
4955 if (*win.lines == NULL)
4960 gchar *first_line_match;
4963 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4965 /* We're now before the search limit, abort. */
4969 /* If there are multiple lines, the first line will
4970 * end in '\n', so this will only match at the
4971 * end of the first line, which is correct.
4973 first_line_match = g_strrstr (*win.lines, *lines);
4975 if (first_line_match &&
4976 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4981 GtkTextIter start_tmp;
4983 /* Offset to start of search string */
4984 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4986 next = win.first_line_start;
4988 forward_chars_with_skipping (&start_tmp, offset,
4989 visible_only, !slice);
4992 gtk_text_iter_compare (limit, &start_tmp) > 0)
4993 goto out; /* match was bogus */
4996 *match_start = start_tmp;
4998 /* Go to end of search string */
5002 offset += g_utf8_strlen (*l, -1);
5006 forward_chars_with_skipping (&next, offset,
5007 visible_only, !slice);
5016 while (lines_window_back (&win));
5019 lines_window_free (&win);
5030 * gtk_text_iter_equal:
5031 * @lhs: a #GtkTextIter
5032 * @rhs: another #GtkTextIter
5034 * Tests whether two iterators are equal, using the fastest possible
5035 * mechanism. This function is very fast; you can expect it to perform
5036 * better than e.g. getting the character offset for each iterator and
5037 * comparing the offsets yourself. Also, it's a bit faster than
5038 * gtk_text_iter_compare().
5040 * Return value: %TRUE if the iterators point to the same place in the buffer
5043 gtk_text_iter_equal (const GtkTextIter *lhs,
5044 const GtkTextIter *rhs)
5046 GtkTextRealIter *real_lhs;
5047 GtkTextRealIter *real_rhs;
5049 real_lhs = (GtkTextRealIter*)lhs;
5050 real_rhs = (GtkTextRealIter*)rhs;
5052 check_invariants (lhs);
5053 check_invariants (rhs);
5055 if (real_lhs->line != real_rhs->line)
5057 else if (real_lhs->line_byte_offset >= 0 &&
5058 real_rhs->line_byte_offset >= 0)
5059 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5062 /* the ensure_char_offsets () calls do nothing if the char offsets
5063 are already up-to-date. */
5064 ensure_char_offsets (real_lhs);
5065 ensure_char_offsets (real_rhs);
5066 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5071 * gtk_text_iter_compare:
5072 * @lhs: a #GtkTextIter
5073 * @rhs: another #GtkTextIter
5075 * A qsort()-style function that returns negative if @lhs is less than
5076 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5077 * Ordering is in character offset order, i.e. the first character in the buffer
5078 * is less than the second character in the buffer.
5080 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5083 gtk_text_iter_compare (const GtkTextIter *lhs,
5084 const GtkTextIter *rhs)
5086 GtkTextRealIter *real_lhs;
5087 GtkTextRealIter *real_rhs;
5089 real_lhs = gtk_text_iter_make_surreal (lhs);
5090 real_rhs = gtk_text_iter_make_surreal (rhs);
5092 if (real_lhs == NULL ||
5094 return -1; /* why not */
5096 check_invariants (lhs);
5097 check_invariants (rhs);
5099 if (real_lhs->line == real_rhs->line)
5101 gint left_index, right_index;
5103 if (real_lhs->line_byte_offset >= 0 &&
5104 real_rhs->line_byte_offset >= 0)
5106 left_index = real_lhs->line_byte_offset;
5107 right_index = real_rhs->line_byte_offset;
5111 /* the ensure_char_offsets () calls do nothing if
5112 the offsets are already up-to-date. */
5113 ensure_char_offsets (real_lhs);
5114 ensure_char_offsets (real_rhs);
5115 left_index = real_lhs->line_char_offset;
5116 right_index = real_rhs->line_char_offset;
5119 if (left_index < right_index)
5121 else if (left_index > right_index)
5130 line1 = gtk_text_iter_get_line (lhs);
5131 line2 = gtk_text_iter_get_line (rhs);
5134 else if (line1 > line2)
5142 * gtk_text_iter_in_range:
5143 * @iter: a #GtkTextIter
5144 * @start: start of range
5145 * @end: end of range
5147 * Checks whether @iter falls in the range [@start, @end).
5148 * @start and @end must be in ascending order.
5150 * Return value: %TRUE if @iter is in the range
5153 gtk_text_iter_in_range (const GtkTextIter *iter,
5154 const GtkTextIter *start,
5155 const GtkTextIter *end)
5157 g_return_val_if_fail (iter != NULL, FALSE);
5158 g_return_val_if_fail (start != NULL, FALSE);
5159 g_return_val_if_fail (end != NULL, FALSE);
5160 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5162 return gtk_text_iter_compare (iter, start) >= 0 &&
5163 gtk_text_iter_compare (iter, end) < 0;
5167 * gtk_text_iter_order:
5168 * @first: a #GtkTextIter
5169 * @second: another #GtkTextIter
5171 * Swaps the value of @first and @second if @second comes before
5172 * @first in the buffer. That is, ensures that @first and @second are
5173 * in sequence. Most text buffer functions that take a range call this
5174 * automatically on your behalf, so there's no real reason to call it yourself
5175 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5176 * that expect a pre-sorted range.
5180 gtk_text_iter_order (GtkTextIter *first,
5181 GtkTextIter *second)
5183 g_return_if_fail (first != NULL);
5184 g_return_if_fail (second != NULL);
5186 if (gtk_text_iter_compare (first, second) > 0)
5197 * Init iterators from the BTree
5201 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5205 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5206 gint real_char_index;
5210 g_return_if_fail (iter != NULL);
5211 g_return_if_fail (tree != NULL);
5213 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5214 &line_start, &real_char_index);
5216 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5218 real->cached_char_index = real_char_index;
5220 check_invariants (iter);
5224 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5229 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5233 g_return_if_fail (iter != NULL);
5234 g_return_if_fail (tree != NULL);
5236 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5238 iter_init_from_char_offset (iter, tree, line, char_on_line);
5240 /* We might as well cache this, since we know it. */
5241 real->cached_line_number = real_line;
5243 check_invariants (iter);
5247 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5252 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5256 g_return_if_fail (iter != NULL);
5257 g_return_if_fail (tree != NULL);
5259 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5261 iter_init_from_byte_offset (iter, tree, line, byte_index);
5263 /* We might as well cache this, since we know it. */
5264 real->cached_line_number = real_line;
5266 check_invariants (iter);
5270 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5275 g_return_if_fail (iter != NULL);
5276 g_return_if_fail (tree != NULL);
5277 g_return_if_fail (line != NULL);
5279 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5281 check_invariants (iter);
5285 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5291 g_return_val_if_fail (iter != NULL, FALSE);
5292 g_return_val_if_fail (tree != NULL, FALSE);
5294 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5298 /* Set iter to last in tree */
5299 _gtk_text_btree_get_end_iter (tree, iter);
5300 check_invariants (iter);
5305 iter_init_from_byte_offset (iter, tree, line, 0);
5307 if (!gtk_text_iter_toggles_tag (iter, tag))
5308 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5310 check_invariants (iter);
5316 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5320 g_return_val_if_fail (iter != NULL, FALSE);
5321 g_return_val_if_fail (tree != NULL, FALSE);
5323 _gtk_text_btree_get_end_iter (tree, iter);
5324 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5325 check_invariants (iter);
5331 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5333 const gchar *mark_name)
5337 g_return_val_if_fail (iter != NULL, FALSE);
5338 g_return_val_if_fail (tree != NULL, FALSE);
5340 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5346 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5347 check_invariants (iter);
5353 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5357 GtkTextLineSegment *seg;
5359 g_return_if_fail (iter != NULL);
5360 g_return_if_fail (tree != NULL);
5361 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5363 seg = mark->segment;
5365 iter_init_from_segment (iter, tree,
5366 seg->body.mark.line, seg);
5367 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5368 check_invariants (iter);
5372 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5374 GtkTextChildAnchor *anchor)
5376 GtkTextLineSegment *seg;
5378 g_return_if_fail (iter != NULL);
5379 g_return_if_fail (tree != NULL);
5380 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5382 seg = anchor->segment;
5384 g_assert (seg->body.child.line != NULL);
5386 iter_init_from_segment (iter, tree,
5387 seg->body.child.line, seg);
5388 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5389 check_invariants (iter);
5393 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5396 g_return_if_fail (iter != NULL);
5397 g_return_if_fail (tree != NULL);
5399 _gtk_text_btree_get_iter_at_char (tree,
5401 _gtk_text_btree_char_count (tree));
5402 check_invariants (iter);
5406 _gtk_text_iter_check (const GtkTextIter *iter)
5408 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5409 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5410 GtkTextLineSegment *byte_segment = NULL;
5411 GtkTextLineSegment *byte_any_segment = NULL;
5412 GtkTextLineSegment *char_segment = NULL;
5413 GtkTextLineSegment *char_any_segment = NULL;
5414 gboolean segments_updated;
5416 /* This function checks our class invariants for the Iter class. */
5418 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5420 if (real->chars_changed_stamp !=
5421 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5422 g_error ("iterator check failed: invalid iterator");
5424 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5425 g_error ("iterator check failed: both char and byte offsets are invalid");
5427 segments_updated = (real->segments_changed_stamp ==
5428 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5431 printf ("checking iter, segments %s updated, byte %d char %d\n",
5432 segments_updated ? "are" : "aren't",
5433 real->line_byte_offset,
5434 real->line_char_offset);
5437 if (segments_updated)
5439 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5440 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5442 if (real->segment->char_count == 0)
5443 g_error ("iterator check failed: segment is not indexable.");
5445 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5446 g_error ("segment char offset is not properly up-to-date");
5448 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5449 g_error ("segment byte offset is not properly up-to-date");
5451 if (real->segment_byte_offset >= 0 &&
5452 real->segment_byte_offset >= real->segment->byte_count)
5453 g_error ("segment byte offset is too large.");
5455 if (real->segment_char_offset >= 0 &&
5456 real->segment_char_offset >= real->segment->char_count)
5457 g_error ("segment char offset is too large.");
5460 if (real->line_byte_offset >= 0)
5462 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5463 &byte_segment, &byte_any_segment,
5464 &seg_byte_offset, &line_byte_offset);
5466 if (line_byte_offset != real->line_byte_offset)
5467 g_error ("wrong byte offset was stored in iterator");
5469 if (segments_updated)
5471 if (real->segment != byte_segment)
5472 g_error ("wrong segment was stored in iterator");
5474 if (real->any_segment != byte_any_segment)
5475 g_error ("wrong any_segment was stored in iterator");
5477 if (seg_byte_offset != real->segment_byte_offset)
5478 g_error ("wrong segment byte offset was stored in iterator");
5480 if (byte_segment->type == >k_text_char_type)
5483 p = byte_segment->body.chars + seg_byte_offset;
5485 if (!gtk_text_byte_begins_utf8_char (p))
5486 g_error ("broken iterator byte index pointed into the middle of a character");
5491 if (real->line_char_offset >= 0)
5493 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5494 &char_segment, &char_any_segment,
5495 &seg_char_offset, &line_char_offset);
5497 if (line_char_offset != real->line_char_offset)
5498 g_error ("wrong char offset was stored in iterator");
5500 if (segments_updated)
5502 if (real->segment != char_segment)
5503 g_error ("wrong segment was stored in iterator");
5505 if (real->any_segment != char_any_segment)
5506 g_error ("wrong any_segment was stored in iterator");
5508 if (seg_char_offset != real->segment_char_offset)
5509 g_error ("wrong segment char offset was stored in iterator");
5511 if (char_segment->type == >k_text_char_type)
5514 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5517 /* hmm, not likely to happen eh */
5518 if (!gtk_text_byte_begins_utf8_char (p))
5519 g_error ("broken iterator char offset pointed into the middle of a character");
5524 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5526 if (byte_segment != char_segment)
5527 g_error ("char and byte offsets did not point to the same segment");
5529 if (byte_any_segment != char_any_segment)
5530 g_error ("char and byte offsets did not point to the same any segment");
5532 /* Make sure the segment offsets are equivalent, if it's a char
5534 if (char_segment->type == >k_text_char_type)
5536 gint byte_offset = 0;
5537 gint char_offset = 0;
5538 while (char_offset < seg_char_offset)
5540 const char * start = char_segment->body.chars + byte_offset;
5541 byte_offset += g_utf8_next_char (start) - start;
5545 if (byte_offset != seg_byte_offset)
5546 g_error ("byte offset did not correspond to char offset");
5549 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5551 if (char_offset != seg_char_offset)
5552 g_error ("char offset did not correspond to byte offset");
5554 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5555 g_error ("byte index for iterator does not index the start of a character");
5559 if (real->cached_line_number >= 0)
5563 should_be = _gtk_text_line_get_number (real->line);
5564 if (real->cached_line_number != should_be)
5565 g_error ("wrong line number was cached");
5568 if (real->cached_char_index >= 0)
5570 if (real->line_char_offset >= 0) /* only way we can check it
5571 efficiently, not a real
5576 char_index = _gtk_text_line_char_index (real->line);
5577 char_index += real->line_char_offset;
5579 if (real->cached_char_index != char_index)
5580 g_error ("wrong char index was cached");
5584 if (_gtk_text_line_is_last (real->line, real->tree))
5585 g_error ("Iterator was on last line (past the end iterator)");
5588 #define __GTK_TEXT_ITER_C__
5589 #include "gtkaliasdef.c"