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"
37 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
39 typedef struct _GtkTextRealIter GtkTextRealIter;
41 struct _GtkTextRealIter
43 /* Always-valid information */
46 /* At least one of these is always valid;
47 if invalid, they are -1.
49 If the line byte offset is valid, so is the segment byte offset;
50 and ditto for char offsets. */
51 gint line_byte_offset;
52 gint line_char_offset;
53 /* These two are valid if >= 0 */
54 gint cached_char_index;
55 gint cached_line_number;
56 /* Stamps to detect the buffer changing under us */
57 gint chars_changed_stamp;
58 gint segments_changed_stamp;
59 /* Valid if the segments_changed_stamp is up-to-date */
60 GtkTextLineSegment *segment; /* indexable segment we index */
61 GtkTextLineSegment *any_segment; /* first segment in our location,
62 maybe same as "segment" */
63 /* One of these will always be valid if segments_changed_stamp is
64 up-to-date. If invalid, they are -1.
66 If the line byte offset is valid, so is the segment byte offset;
67 and ditto for char offsets. */
68 gint segment_byte_offset;
69 gint segment_char_offset;
76 /* These "set" functions should not assume any fields
77 other than the char stamp and the tree are valid.
80 iter_set_common (GtkTextRealIter *iter,
83 /* Update segments stamp */
84 iter->segments_changed_stamp =
85 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
89 iter->line_byte_offset = -1;
90 iter->line_char_offset = -1;
91 iter->segment_byte_offset = -1;
92 iter->segment_char_offset = -1;
93 iter->cached_char_index = -1;
94 iter->cached_line_number = -1;
98 iter_set_from_byte_offset (GtkTextRealIter *iter,
102 iter_set_common (iter, line);
104 if (!_gtk_text_line_byte_locate (iter->line,
108 &iter->segment_byte_offset,
109 &iter->line_byte_offset))
110 g_error ("Byte index %d is off the end of the line",
115 iter_set_from_char_offset (GtkTextRealIter *iter,
119 iter_set_common (iter, line);
121 if (!_gtk_text_line_char_locate (iter->line,
125 &iter->segment_char_offset,
126 &iter->line_char_offset))
127 g_error ("Char offset %d is off the end of the line",
132 iter_set_from_segment (GtkTextRealIter *iter,
134 GtkTextLineSegment *segment)
136 GtkTextLineSegment *seg;
139 /* This could theoretically be optimized by computing all the iter
140 fields in this same loop, but I'm skipping it for now. */
142 seg = line->segments;
143 while (seg != segment)
145 byte_offset += seg->byte_count;
149 iter_set_from_byte_offset (iter, line, byte_offset);
152 /* This function ensures that the segment-dependent information is
153 truly computed lazily; often we don't need to do the full make_real
154 work. This ensures the btree and line are valid, but doesn't
155 update the segments. */
156 static GtkTextRealIter*
157 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
159 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
161 if (iter->chars_changed_stamp !=
162 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
164 g_warning ("Invalid text buffer iterator: either the iterator "
165 "is uninitialized, or the characters/pixbufs/widgets "
166 "in the buffer have been modified since the iterator "
167 "was created.\nYou must use marks, character numbers, "
168 "or line numbers to preserve a position across buffer "
169 "modifications.\nYou can apply tags and insert marks "
170 "without invalidating your iterators,\n"
171 "but any mutation that affects 'indexable' buffer contents "
172 "(contents that can be referred to by character offset)\n"
173 "will invalidate all outstanding iterators");
177 /* We don't update the segments information since we are becoming
178 only surreal. However we do invalidate the segments information
179 if appropriate, to be sure we segfault if we try to use it and we
180 should have used make_real. */
182 if (iter->segments_changed_stamp !=
183 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
185 iter->segment = NULL;
186 iter->any_segment = NULL;
187 /* set to segfault-causing values. */
188 iter->segment_byte_offset = -10000;
189 iter->segment_char_offset = -10000;
195 static GtkTextRealIter*
196 gtk_text_iter_make_real (const GtkTextIter *_iter)
198 GtkTextRealIter *iter;
200 iter = gtk_text_iter_make_surreal (_iter);
202 if (iter->segments_changed_stamp !=
203 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
205 if (iter->line_byte_offset >= 0)
207 iter_set_from_byte_offset (iter,
209 iter->line_byte_offset);
213 g_assert (iter->line_char_offset >= 0);
215 iter_set_from_char_offset (iter,
217 iter->line_char_offset);
221 g_assert (iter->segment != NULL);
222 g_assert (iter->any_segment != NULL);
223 g_assert (iter->segment->char_count > 0);
228 static GtkTextRealIter*
229 iter_init_common (GtkTextIter *_iter,
232 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
234 g_return_val_if_fail (iter != NULL, NULL);
235 g_return_val_if_fail (tree != NULL, NULL);
239 iter->chars_changed_stamp =
240 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
245 static GtkTextRealIter*
246 iter_init_from_segment (GtkTextIter *iter,
249 GtkTextLineSegment *segment)
251 GtkTextRealIter *real;
253 g_return_val_if_fail (line != NULL, NULL);
255 real = iter_init_common (iter, tree);
257 iter_set_from_segment (real, line, segment);
262 static GtkTextRealIter*
263 iter_init_from_byte_offset (GtkTextIter *iter,
266 gint line_byte_offset)
268 GtkTextRealIter *real;
270 g_return_val_if_fail (line != NULL, NULL);
272 real = iter_init_common (iter, tree);
274 iter_set_from_byte_offset (real, line, line_byte_offset);
276 if (real->segment->type == >k_text_char_type &&
277 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
278 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
279 "character; this will crash the text buffer. "
280 "Byte indexes must refer to the start of a character.",
286 static GtkTextRealIter*
287 iter_init_from_char_offset (GtkTextIter *iter,
290 gint line_char_offset)
292 GtkTextRealIter *real;
294 g_return_val_if_fail (line != NULL, NULL);
296 real = iter_init_common (iter, tree);
298 iter_set_from_char_offset (real, line, line_char_offset);
304 invalidate_char_index (GtkTextRealIter *iter)
306 iter->cached_char_index = -1;
310 adjust_char_index (GtkTextRealIter *iter, gint count)
312 if (iter->cached_char_index >= 0)
313 iter->cached_char_index += count;
317 adjust_line_number (GtkTextRealIter *iter, gint count)
319 if (iter->cached_line_number >= 0)
320 iter->cached_line_number += count;
324 ensure_char_offsets (GtkTextRealIter *iter)
326 if (iter->line_char_offset < 0)
328 g_assert (iter->line_byte_offset >= 0);
330 _gtk_text_line_byte_to_char_offsets (iter->line,
331 iter->line_byte_offset,
332 &iter->line_char_offset,
333 &iter->segment_char_offset);
338 ensure_byte_offsets (GtkTextRealIter *iter)
340 if (iter->line_byte_offset < 0)
342 g_assert (iter->line_char_offset >= 0);
344 _gtk_text_line_char_to_byte_offsets (iter->line,
345 iter->line_char_offset,
346 &iter->line_byte_offset,
347 &iter->segment_byte_offset);
351 static inline gboolean
352 is_segment_start (GtkTextRealIter *real)
354 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
357 #ifdef G_ENABLE_DEBUG
359 check_invariants (const GtkTextIter *iter)
361 if (gtk_debug_flags & GTK_DEBUG_TEXT)
362 _gtk_text_iter_check (iter);
365 #define check_invariants(x)
369 * gtk_text_iter_get_buffer:
372 * Returns the #GtkTextBuffer this iterator is associated with.
374 * Return value: the buffer
377 gtk_text_iter_get_buffer (const GtkTextIter *iter)
379 GtkTextRealIter *real;
381 g_return_val_if_fail (iter != NULL, NULL);
383 real = gtk_text_iter_make_surreal (iter);
388 check_invariants (iter);
390 return _gtk_text_btree_get_buffer (real->tree);
394 * gtk_text_iter_copy:
397 * Creates a dynamically-allocated copy of an iterator. This function
398 * is not useful in applications, because iterators can be copied with a
399 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
400 * function is used by language bindings.
402 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
405 gtk_text_iter_copy (const GtkTextIter *iter)
407 GtkTextIter *new_iter;
409 g_return_val_if_fail (iter != NULL, NULL);
411 new_iter = g_slice_new (GtkTextIter);
419 * gtk_text_iter_free:
420 * @iter: a dynamically-allocated iterator
422 * Free an iterator allocated on the heap. This function
423 * is intended for use in language bindings, and is not
424 * especially useful for applications, because iterators can
425 * simply be allocated on the stack.
428 gtk_text_iter_free (GtkTextIter *iter)
430 g_return_if_fail (iter != NULL);
432 g_slice_free (GtkTextIter, iter);
436 gtk_text_iter_get_type (void)
438 static GType our_type = 0;
441 our_type = g_boxed_type_register_static (I_("GtkTextIter"),
442 (GBoxedCopyFunc) gtk_text_iter_copy,
443 (GBoxedFreeFunc) gtk_text_iter_free);
449 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
451 GtkTextRealIter *real;
453 g_return_val_if_fail (iter != NULL, NULL);
455 real = gtk_text_iter_make_real (iter);
460 check_invariants (iter);
462 g_assert (real->segment != NULL);
464 return real->segment;
468 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
470 GtkTextRealIter *real;
472 g_return_val_if_fail (iter != NULL, NULL);
474 real = gtk_text_iter_make_real (iter);
479 check_invariants (iter);
481 g_assert (real->any_segment != NULL);
483 return real->any_segment;
487 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
489 GtkTextRealIter *real;
491 g_return_val_if_fail (iter != NULL, 0);
493 real = gtk_text_iter_make_real (iter);
498 ensure_byte_offsets (real);
500 check_invariants (iter);
502 return real->segment_byte_offset;
506 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
508 GtkTextRealIter *real;
510 g_return_val_if_fail (iter != NULL, 0);
512 real = gtk_text_iter_make_real (iter);
517 ensure_char_offsets (real);
519 check_invariants (iter);
521 return real->segment_char_offset;
524 /* This function does not require a still-valid
527 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
529 const GtkTextRealIter *real;
531 g_return_val_if_fail (iter != NULL, NULL);
533 real = (const GtkTextRealIter*)iter;
538 /* This function does not require a still-valid
541 _gtk_text_iter_get_btree (const GtkTextIter *iter)
543 const GtkTextRealIter *real;
545 g_return_val_if_fail (iter != NULL, NULL);
547 real = (const GtkTextRealIter*)iter;
557 * gtk_text_iter_get_offset:
560 * Returns the character offset of an iterator.
561 * Each character in a #GtkTextBuffer has an offset,
562 * starting with 0 for the first character in the buffer.
563 * Use gtk_text_buffer_get_iter_at_offset () to convert an
564 * offset back into an iterator.
566 * Return value: a character offset
569 gtk_text_iter_get_offset (const GtkTextIter *iter)
571 GtkTextRealIter *real;
573 g_return_val_if_fail (iter != NULL, 0);
575 real = gtk_text_iter_make_surreal (iter);
580 check_invariants (iter);
582 if (real->cached_char_index < 0)
584 ensure_char_offsets (real);
586 real->cached_char_index =
587 _gtk_text_line_char_index (real->line);
588 real->cached_char_index += real->line_char_offset;
591 check_invariants (iter);
593 return real->cached_char_index;
597 * gtk_text_iter_get_line:
600 * Returns the line number containing the iterator. Lines in
601 * a #GtkTextBuffer are numbered beginning with 0 for the first
602 * line in the buffer.
604 * Return value: a line number
607 gtk_text_iter_get_line (const GtkTextIter *iter)
609 GtkTextRealIter *real;
611 g_return_val_if_fail (iter != NULL, 0);
613 real = gtk_text_iter_make_surreal (iter);
618 if (real->cached_line_number < 0)
619 real->cached_line_number =
620 _gtk_text_line_get_number (real->line);
622 check_invariants (iter);
624 return real->cached_line_number;
628 * gtk_text_iter_get_line_offset:
631 * Returns the character offset of the iterator,
632 * counting from the start of a newline-terminated line.
633 * The first character on the line has offset 0.
635 * Return value: offset from start of line
638 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
640 GtkTextRealIter *real;
642 g_return_val_if_fail (iter != NULL, 0);
644 real = gtk_text_iter_make_surreal (iter);
649 ensure_char_offsets (real);
651 check_invariants (iter);
653 return real->line_char_offset;
657 * gtk_text_iter_get_line_index:
660 * Returns the byte index of the iterator, counting
661 * from the start of a newline-terminated line.
662 * Remember that #GtkTextBuffer encodes text in
663 * UTF-8, and that characters can require a variable
664 * number of bytes to represent.
666 * Return value: distance from start of line, in bytes
669 gtk_text_iter_get_line_index (const GtkTextIter *iter)
671 GtkTextRealIter *real;
673 g_return_val_if_fail (iter != NULL, 0);
675 real = gtk_text_iter_make_surreal (iter);
680 ensure_byte_offsets (real);
682 check_invariants (iter);
684 return real->line_byte_offset;
688 * gtk_text_iter_get_visible_line_offset:
689 * @iter: a #GtkTextIter
691 * Returns the offset in characters from the start of the
692 * line to the given @iter, not counting characters that
693 * are invisible due to tags with the "invisible" flag
696 * Return value: offset in visible characters from the start of the line
699 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
701 GtkTextRealIter *real;
703 GtkTextLineSegment *seg;
706 g_return_val_if_fail (iter != NULL, 0);
708 real = gtk_text_iter_make_real (iter);
713 ensure_char_offsets (real);
715 check_invariants (iter);
717 vis_offset = real->line_char_offset;
719 g_assert (vis_offset >= 0);
721 _gtk_text_btree_get_iter_at_line (real->tree,
726 seg = _gtk_text_iter_get_indexable_segment (&pos);
728 while (seg != real->segment)
730 /* This is a pretty expensive call, making the
731 * whole function pretty lame; we could keep track
732 * of current invisibility state by looking at toggle
733 * segments as we loop, and then call this function
734 * only once per line, in order to speed up the loop
737 if (_gtk_text_btree_char_is_invisible (&pos))
738 vis_offset -= seg->char_count;
740 _gtk_text_iter_forward_indexable_segment (&pos);
742 seg = _gtk_text_iter_get_indexable_segment (&pos);
745 if (_gtk_text_btree_char_is_invisible (&pos))
746 vis_offset -= real->segment_char_offset;
753 * gtk_text_iter_get_visible_line_index:
754 * @iter: a #GtkTextIter
756 * Returns the number of bytes from the start of the
757 * line to the given @iter, not counting bytes that
758 * are invisible due to tags with the "invisible" flag
761 * Return value: byte index of @iter with respect to the start of the line
764 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
766 GtkTextRealIter *real;
768 GtkTextLineSegment *seg;
771 g_return_val_if_fail (iter != NULL, 0);
773 real = gtk_text_iter_make_real (iter);
778 ensure_byte_offsets (real);
780 check_invariants (iter);
782 vis_offset = real->line_byte_offset;
784 g_assert (vis_offset >= 0);
786 _gtk_text_btree_get_iter_at_line (real->tree,
791 seg = _gtk_text_iter_get_indexable_segment (&pos);
793 while (seg != real->segment)
795 /* This is a pretty expensive call, making the
796 * whole function pretty lame; we could keep track
797 * of current invisibility state by looking at toggle
798 * segments as we loop, and then call this function
799 * only once per line, in order to speed up the loop
802 if (_gtk_text_btree_char_is_invisible (&pos))
803 vis_offset -= seg->byte_count;
805 _gtk_text_iter_forward_indexable_segment (&pos);
807 seg = _gtk_text_iter_get_indexable_segment (&pos);
810 if (_gtk_text_btree_char_is_invisible (&pos))
811 vis_offset -= real->segment_byte_offset;
821 * gtk_text_iter_get_char:
824 * Returns the Unicode character at this iterator. (Equivalent to
825 * operator* on a C++ iterator.) If the element at this iterator is a
826 * non-character element, such as an image embedded in the buffer, the
827 * Unicode "unknown" character 0xFFFC is returned. If invoked on
828 * the end iterator, zero is returned; zero is not a valid Unicode character.
829 * So you can write a loop which ends when gtk_text_iter_get_char ()
832 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
835 gtk_text_iter_get_char (const GtkTextIter *iter)
837 GtkTextRealIter *real;
839 g_return_val_if_fail (iter != NULL, 0);
841 real = gtk_text_iter_make_real (iter);
846 check_invariants (iter);
848 if (gtk_text_iter_is_end (iter))
850 else if (real->segment->type == >k_text_char_type)
852 ensure_byte_offsets (real);
854 return g_utf8_get_char (real->segment->body.chars +
855 real->segment_byte_offset);
859 /* Unicode "unknown character" 0xFFFC */
860 return GTK_TEXT_UNKNOWN_CHAR;
865 * gtk_text_iter_get_slice:
866 * @start: iterator at start of a range
867 * @end: iterator at end of a range
869 * Returns the text in the given range. A "slice" is an array of
870 * characters encoded in UTF-8 format, including the Unicode "unknown"
871 * character 0xFFFC for iterable non-character elements in the buffer,
872 * such as images. Because images are encoded in the slice, byte and
873 * character offsets in the returned array will correspond to byte
874 * offsets in the text buffer. Note that 0xFFFC can occur in normal
875 * text as well, so it is not a reliable indicator that a pixbuf or
876 * widget is in the buffer.
878 * Return value: slice of text from the buffer
881 gtk_text_iter_get_slice (const GtkTextIter *start,
882 const GtkTextIter *end)
884 g_return_val_if_fail (start != NULL, NULL);
885 g_return_val_if_fail (end != NULL, NULL);
887 check_invariants (start);
888 check_invariants (end);
890 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
894 * gtk_text_iter_get_text:
895 * @start: iterator at start of a range
896 * @end: iterator at end of a range
898 * Returns <emphasis>text</emphasis> in the given range. If the range
899 * contains non-text elements such as images, the character and byte
900 * offsets in the returned string will not correspond to character and
901 * byte offsets in the buffer. If you want offsets to correspond, see
902 * gtk_text_iter_get_slice ().
904 * Return value: array of characters from the buffer
907 gtk_text_iter_get_text (const GtkTextIter *start,
908 const GtkTextIter *end)
910 g_return_val_if_fail (start != NULL, NULL);
911 g_return_val_if_fail (end != NULL, NULL);
913 check_invariants (start);
914 check_invariants (end);
916 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
920 * gtk_text_iter_get_visible_slice:
921 * @start: iterator at start of range
922 * @end: iterator at end of range
924 * Like gtk_text_iter_get_slice (), but invisible text is not included.
925 * Invisible text is usually invisible because a #GtkTextTag with the
926 * "invisible" attribute turned on has been applied to it.
928 * Return value: slice of text from the buffer
931 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
932 const GtkTextIter *end)
934 g_return_val_if_fail (start != NULL, NULL);
935 g_return_val_if_fail (end != NULL, NULL);
937 check_invariants (start);
938 check_invariants (end);
940 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
944 * gtk_text_iter_get_visible_text:
945 * @start: iterator at start of range
946 * @end: iterator at end of range
948 * Like gtk_text_iter_get_text (), but invisible text is not included.
949 * Invisible text is usually invisible because a #GtkTextTag with the
950 * "invisible" attribute turned on has been applied to it.
952 * Return value: string containing visible text in the range
955 gtk_text_iter_get_visible_text (const GtkTextIter *start,
956 const GtkTextIter *end)
958 g_return_val_if_fail (start != NULL, NULL);
959 g_return_val_if_fail (end != NULL, NULL);
961 check_invariants (start);
962 check_invariants (end);
964 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
968 * gtk_text_iter_get_pixbuf:
971 * If the element at @iter is a pixbuf, the pixbuf is returned
972 * (with no new reference count added). Otherwise,
975 * Return value: the pixbuf at @iter
978 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
980 GtkTextRealIter *real;
982 g_return_val_if_fail (iter != NULL, NULL);
984 real = gtk_text_iter_make_real (iter);
989 check_invariants (iter);
991 if (real->segment->type != >k_text_pixbuf_type)
994 return real->segment->body.pixbuf.pixbuf;
998 * gtk_text_iter_get_child_anchor:
1001 * If the location at @iter contains a child anchor, the
1002 * anchor is returned (with no new reference count added). Otherwise,
1003 * %NULL is returned.
1005 * Return value: the anchor at @iter
1008 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1010 GtkTextRealIter *real;
1012 g_return_val_if_fail (iter != NULL, NULL);
1014 real = gtk_text_iter_make_real (iter);
1019 check_invariants (iter);
1021 if (real->segment->type != >k_text_child_type)
1024 return real->segment->body.child.obj;
1028 * gtk_text_iter_get_marks:
1029 * @iter: an iterator
1031 * Returns a list of all #GtkTextMark at this location. Because marks
1032 * are not iterable (they don't take up any "space" in the buffer,
1033 * they are just marks in between iterable locations), multiple marks
1034 * can exist in the same place. The returned list is not in any
1037 * Return value: list of #GtkTextMark
1040 gtk_text_iter_get_marks (const GtkTextIter *iter)
1042 GtkTextRealIter *real;
1043 GtkTextLineSegment *seg;
1046 g_return_val_if_fail (iter != NULL, NULL);
1048 real = gtk_text_iter_make_real (iter);
1053 check_invariants (iter);
1056 seg = real->any_segment;
1057 while (seg != real->segment)
1059 if (seg->type == >k_text_left_mark_type ||
1060 seg->type == >k_text_right_mark_type)
1061 retval = g_slist_prepend (retval, seg->body.mark.obj);
1066 /* The returned list isn't guaranteed to be in any special order,
1072 * gtk_text_iter_get_toggled_tags:
1073 * @iter: an iterator
1074 * @toggled_on: %TRUE to get toggled-on tags
1076 * Returns a list of #GtkTextTag that are toggled on or off at this
1077 * point. (If @toggled_on is %TRUE, the list contains tags that are
1078 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1079 * range of characters following @iter has that tag applied to it. If
1080 * a tag is toggled off, then some non-empty range following @iter
1081 * does <emphasis>not</emphasis> have the tag applied to it.
1083 * Return value: tags toggled at this point
1086 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1087 gboolean toggled_on)
1089 GtkTextRealIter *real;
1090 GtkTextLineSegment *seg;
1093 g_return_val_if_fail (iter != NULL, NULL);
1095 real = gtk_text_iter_make_real (iter);
1100 check_invariants (iter);
1103 seg = real->any_segment;
1104 while (seg != real->segment)
1108 if (seg->type == >k_text_toggle_on_type)
1110 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1115 if (seg->type == >k_text_toggle_off_type)
1117 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1124 /* The returned list isn't guaranteed to be in any special order,
1130 * gtk_text_iter_begins_tag:
1131 * @iter: an iterator
1132 * @tag: a #GtkTextTag, or %NULL
1134 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1135 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1136 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1137 * <emphasis>start</emphasis> of the tagged range;
1138 * gtk_text_iter_has_tag () tells you whether an iterator is
1139 * <emphasis>within</emphasis> a tagged range.
1141 * Return value: whether @iter is the start of a range tagged with @tag
1144 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1147 GtkTextRealIter *real;
1148 GtkTextLineSegment *seg;
1150 g_return_val_if_fail (iter != NULL, FALSE);
1152 real = gtk_text_iter_make_real (iter);
1157 check_invariants (iter);
1159 seg = real->any_segment;
1160 while (seg != real->segment)
1162 if (seg->type == >k_text_toggle_on_type)
1165 seg->body.toggle.info->tag == tag)
1176 * gtk_text_iter_ends_tag:
1177 * @iter: an iterator
1178 * @tag: a #GtkTextTag, or %NULL
1180 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1181 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1182 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1183 * <emphasis>end</emphasis> of the tagged range;
1184 * gtk_text_iter_has_tag () tells you whether an iterator is
1185 * <emphasis>within</emphasis> a tagged range.
1187 * Return value: whether @iter is the end of a range tagged with @tag
1191 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1194 GtkTextRealIter *real;
1195 GtkTextLineSegment *seg;
1197 g_return_val_if_fail (iter != NULL, FALSE);
1199 real = gtk_text_iter_make_real (iter);
1204 check_invariants (iter);
1206 seg = real->any_segment;
1207 while (seg != real->segment)
1209 if (seg->type == >k_text_toggle_off_type)
1212 seg->body.toggle.info->tag == tag)
1223 * gtk_text_iter_toggles_tag:
1224 * @iter: an iterator
1225 * @tag: a #GtkTextTag, or %NULL
1227 * This is equivalent to (gtk_text_iter_begins_tag () ||
1228 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1229 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1231 * Return value: whether @tag is toggled on or off at @iter
1234 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1237 GtkTextRealIter *real;
1238 GtkTextLineSegment *seg;
1240 g_return_val_if_fail (iter != NULL, FALSE);
1242 real = gtk_text_iter_make_real (iter);
1247 check_invariants (iter);
1249 seg = real->any_segment;
1250 while (seg != real->segment)
1252 if ( (seg->type == >k_text_toggle_off_type ||
1253 seg->type == >k_text_toggle_on_type) &&
1255 seg->body.toggle.info->tag == tag) )
1265 * gtk_text_iter_has_tag:
1266 * @iter: an iterator
1267 * @tag: a #GtkTextTag
1269 * Returns %TRUE if @iter is within a range tagged with @tag.
1271 * Return value: whether @iter is tagged with @tag
1274 gtk_text_iter_has_tag (const GtkTextIter *iter,
1277 GtkTextRealIter *real;
1279 g_return_val_if_fail (iter != NULL, FALSE);
1280 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1282 real = gtk_text_iter_make_surreal (iter);
1287 check_invariants (iter);
1289 if (real->line_byte_offset >= 0)
1291 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1292 real->line_byte_offset, tag);
1296 g_assert (real->line_char_offset >= 0);
1297 return _gtk_text_line_char_has_tag (real->line, real->tree,
1298 real->line_char_offset, tag);
1303 * gtk_text_iter_get_tags:
1304 * @iter: a #GtkTextIter
1306 * Returns a list of tags that apply to @iter, in ascending order of
1307 * priority (highest-priority tags are last). The #GtkTextTag in the
1308 * list don't have a reference added, but you have to free the list
1311 * Return value: list of #GtkTextTag
1314 gtk_text_iter_get_tags (const GtkTextIter *iter)
1321 g_return_val_if_fail (iter != NULL, NULL);
1323 /* Get the tags at this spot */
1324 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1326 /* No tags, use default style */
1327 if (tags == NULL || tag_count == 0)
1336 while (i < tag_count)
1338 retval = g_slist_prepend (retval, tags[i]);
1344 /* Return tags in ascending order of priority */
1345 return g_slist_reverse (retval);
1349 * gtk_text_iter_editable:
1350 * @iter: an iterator
1351 * @default_setting: %TRUE if text is editable by default
1353 * Returns whether the character at @iter is within an editable region
1354 * of text. Non-editable text is "locked" and can't be changed by the
1355 * user via #GtkTextView. This function is simply a convenience
1356 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1357 * to this text affect editability, @default_setting will be returned.
1359 * You don't want to use this function to decide whether text can be
1360 * inserted at @iter, because for insertion you don't want to know
1361 * whether the char at @iter is inside an editable range, you want to
1362 * know whether a new character inserted at @iter would be inside an
1363 * editable range. Use gtk_text_iter_can_insert() to handle this
1366 * Return value: whether @iter is inside an editable range
1369 gtk_text_iter_editable (const GtkTextIter *iter,
1370 gboolean default_setting)
1372 GtkTextAttributes *values;
1375 g_return_val_if_fail (iter != NULL, FALSE);
1377 values = gtk_text_attributes_new ();
1379 values->editable = default_setting;
1381 gtk_text_iter_get_attributes (iter, values);
1383 retval = values->editable;
1385 gtk_text_attributes_unref (values);
1391 * gtk_text_iter_can_insert:
1392 * @iter: an iterator
1393 * @default_editability: %TRUE if text is editable by default
1395 * Considering the default editability of the buffer, and tags that
1396 * affect editability, determines whether text inserted at @iter would
1397 * be editable. If text inserted at @iter would be editable then the
1398 * user should be allowed to insert text at @iter.
1399 * gtk_text_buffer_insert_interactive() uses this function to decide
1400 * whether insertions are allowed at a given position.
1402 * Return value: whether text inserted at @iter would be editable
1405 gtk_text_iter_can_insert (const GtkTextIter *iter,
1406 gboolean default_editability)
1408 g_return_val_if_fail (iter != NULL, FALSE);
1410 if (gtk_text_iter_editable (iter, default_editability))
1412 /* If at start/end of buffer, default editability is used */
1413 else if ((gtk_text_iter_is_start (iter) ||
1414 gtk_text_iter_is_end (iter)) &&
1415 default_editability)
1419 /* if iter isn't editable, and the char before iter is,
1420 * then iter is the first char in an editable region
1421 * and thus insertion at iter results in editable text.
1423 GtkTextIter prev = *iter;
1424 gtk_text_iter_backward_char (&prev);
1425 return gtk_text_iter_editable (&prev, default_editability);
1431 * gtk_text_iter_get_language:
1432 * @iter: an iterator
1434 * A convenience wrapper around gtk_text_iter_get_attributes (),
1435 * which returns the language in effect at @iter. If no tags affecting
1436 * language apply to @iter, the return value is identical to that of
1437 * gtk_get_default_language ().
1439 * Return value: language in effect at @iter
1442 gtk_text_iter_get_language (const GtkTextIter *iter)
1444 GtkTextAttributes *values;
1445 PangoLanguage *retval;
1447 values = gtk_text_attributes_new ();
1449 gtk_text_iter_get_attributes (iter, values);
1451 retval = values->language;
1453 gtk_text_attributes_unref (values);
1459 * gtk_text_iter_starts_line:
1460 * @iter: an iterator
1462 * Returns %TRUE if @iter begins a paragraph,
1463 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1464 * However this function is potentially more efficient than
1465 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1466 * the offset, it just has to see whether it's 0.
1468 * Return value: whether @iter begins a line
1471 gtk_text_iter_starts_line (const GtkTextIter *iter)
1473 GtkTextRealIter *real;
1475 g_return_val_if_fail (iter != NULL, FALSE);
1477 real = gtk_text_iter_make_surreal (iter);
1482 check_invariants (iter);
1484 if (real->line_byte_offset >= 0)
1486 return (real->line_byte_offset == 0);
1490 g_assert (real->line_char_offset >= 0);
1491 return (real->line_char_offset == 0);
1496 * gtk_text_iter_ends_line:
1497 * @iter: an iterator
1499 * Returns %TRUE if @iter points to the start of the paragraph
1500 * delimiter characters for a line (delimiters will be either a
1501 * newline, a carriage return, a carriage return followed by a
1502 * newline, or a Unicode paragraph separator character). Note that an
1503 * iterator pointing to the \n of a \r\n pair will not be counted as
1504 * the end of a line, the line ends before the \r. The end iterator is
1505 * considered to be at the end of a line, even though there are no
1506 * paragraph delimiter chars there.
1508 * Return value: whether @iter is at the end of a line
1511 gtk_text_iter_ends_line (const GtkTextIter *iter)
1515 g_return_val_if_fail (iter != NULL, FALSE);
1517 check_invariants (iter);
1519 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1520 * Unicode 3.0; update this if that changes.
1522 #define PARAGRAPH_SEPARATOR 0x2029
1524 wc = gtk_text_iter_get_char (iter);
1526 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1528 else if (wc == '\n')
1530 GtkTextIter tmp = *iter;
1532 /* need to determine if a \r precedes the \n, in which case
1533 * we aren't the end of the line.
1534 * Note however that if \r and \n are on different lines, they
1535 * both are terminators. This for instance may happen after
1536 * deleting some text:
1538 1 some text\r delete 'a' 1 some text\r
1539 2 a\n ---------> 2 \n
1544 if (gtk_text_iter_get_line_offset (&tmp) == 0)
1547 if (!gtk_text_iter_backward_char (&tmp))
1550 return gtk_text_iter_get_char (&tmp) != '\r';
1557 * gtk_text_iter_is_end:
1558 * @iter: an iterator
1560 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1561 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1562 * the most efficient way to check whether an iterator is the end
1565 * Return value: whether @iter is the end iterator
1568 gtk_text_iter_is_end (const GtkTextIter *iter)
1570 GtkTextRealIter *real;
1572 g_return_val_if_fail (iter != NULL, FALSE);
1574 real = gtk_text_iter_make_surreal (iter);
1579 check_invariants (iter);
1581 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1584 /* Now we need the segments validated */
1585 real = gtk_text_iter_make_real (iter);
1590 return _gtk_text_btree_is_end (real->tree, real->line,
1592 real->segment_byte_offset,
1593 real->segment_char_offset);
1597 * gtk_text_iter_is_start:
1598 * @iter: an iterator
1600 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1601 * if @iter has a character offset of 0.
1603 * Return value: whether @iter is the first in the buffer
1606 gtk_text_iter_is_start (const GtkTextIter *iter)
1608 return gtk_text_iter_get_offset (iter) == 0;
1612 * gtk_text_iter_get_chars_in_line:
1613 * @iter: an iterator
1615 * Returns the number of characters in the line containing @iter,
1616 * including the paragraph delimiters.
1618 * Return value: number of characters in the line
1621 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1623 GtkTextRealIter *real;
1625 GtkTextLineSegment *seg;
1627 g_return_val_if_fail (iter != NULL, 0);
1629 real = gtk_text_iter_make_surreal (iter);
1634 check_invariants (iter);
1636 if (real->line_char_offset >= 0)
1638 /* We can start at the segments we've already found. */
1639 count = real->line_char_offset - real->segment_char_offset;
1640 seg = _gtk_text_iter_get_indexable_segment (iter);
1644 /* count whole line. */
1645 seg = real->line->segments;
1652 count += seg->char_count;
1657 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1658 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1664 * gtk_text_iter_get_bytes_in_line:
1665 * @iter: an iterator
1667 * Returns the number of bytes in the line containing @iter,
1668 * including the paragraph delimiters.
1670 * Return value: number of bytes in the line
1673 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1675 GtkTextRealIter *real;
1677 GtkTextLineSegment *seg;
1679 g_return_val_if_fail (iter != NULL, 0);
1681 real = gtk_text_iter_make_surreal (iter);
1686 check_invariants (iter);
1688 if (real->line_byte_offset >= 0)
1690 /* We can start at the segments we've already found. */
1691 count = real->line_byte_offset - real->segment_byte_offset;
1692 seg = _gtk_text_iter_get_indexable_segment (iter);
1696 /* count whole line. */
1697 seg = real->line->segments;
1703 count += seg->byte_count;
1708 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1709 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1715 * gtk_text_iter_get_attributes:
1716 * @iter: an iterator
1717 * @values: a #GtkTextAttributes to be filled in
1719 * Computes the effect of any tags applied to this spot in the
1720 * text. The @values parameter should be initialized to the default
1721 * settings you wish to use if no tags are in effect. You'd typically
1722 * obtain the defaults from gtk_text_view_get_default_attributes().
1724 * gtk_text_iter_get_attributes () will modify @values, applying the
1725 * effects of any tags present at @iter. If any tags affected @values,
1726 * the function returns %TRUE.
1728 * Return value: %TRUE if @values was modified
1731 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1732 GtkTextAttributes *values)
1737 /* Get the tags at this spot */
1738 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1740 /* No tags, use default style */
1741 if (tags == NULL || tag_count == 0)
1748 _gtk_text_attributes_fill_from_tags (values,
1758 * Increments/decrements
1761 /* The return value of this indicates WHETHER WE MOVED.
1762 * The return value of public functions indicates
1763 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1765 * This function will not change the iterator if
1766 * it's already on the last (end iter) line, i.e. it
1767 * won't move to the end of the last line.
1770 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1772 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1774 GtkTextLine *new_line;
1776 new_line = _gtk_text_line_next (real->line);
1777 g_assert (new_line);
1778 g_assert (new_line != real->line);
1779 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1781 real->line = new_line;
1783 real->line_byte_offset = 0;
1784 real->line_char_offset = 0;
1786 real->segment_byte_offset = 0;
1787 real->segment_char_offset = 0;
1789 /* Find first segments in new line */
1790 real->any_segment = real->line->segments;
1791 real->segment = real->any_segment;
1792 while (real->segment->char_count == 0)
1793 real->segment = real->segment->next;
1799 /* There is no way to move forward a line; we were already at
1800 * the line containing the end iterator.
1801 * However we may not be at the end iterator itself.
1809 /* The return value of this indicates WHETHER WE MOVED.
1810 * The return value of public functions indicates
1811 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1813 * This function is currently unused, thus it is #if-0-ed. It is
1814 * left here, since it's non-trivial code that might be useful in
1818 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1820 GtkTextLine *new_line;
1822 new_line = _gtk_text_line_previous (real->line);
1824 g_assert (new_line != real->line);
1826 if (new_line != NULL)
1828 real->line = new_line;
1830 real->line_byte_offset = 0;
1831 real->line_char_offset = 0;
1833 real->segment_byte_offset = 0;
1834 real->segment_char_offset = 0;
1836 /* Find first segments in new line */
1837 real->any_segment = real->line->segments;
1838 real->segment = real->any_segment;
1839 while (real->segment->char_count == 0)
1840 real->segment = real->segment->next;
1846 /* There is no way to move backward; we were already
1847 at the first line. */
1849 /* We leave real->line as-is */
1851 /* Note that we didn't clamp to the start of the first line. */
1858 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1862 forward_char (GtkTextRealIter *real)
1864 GtkTextIter *iter = (GtkTextIter*)real;
1866 check_invariants ((GtkTextIter*)real);
1868 ensure_char_offsets (real);
1870 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1872 /* Need to move to the next segment; if no next segment,
1873 need to move to next line. */
1874 return _gtk_text_iter_forward_indexable_segment (iter);
1878 /* Just moving within a segment. Keep byte count
1879 up-to-date, if it was already up-to-date. */
1881 g_assert (real->segment->type == >k_text_char_type);
1883 if (real->line_byte_offset >= 0)
1886 const char * start =
1887 real->segment->body.chars + real->segment_byte_offset;
1889 bytes = g_utf8_next_char (start) - start;
1891 real->line_byte_offset += bytes;
1892 real->segment_byte_offset += bytes;
1894 g_assert (real->segment_byte_offset < real->segment->byte_count);
1897 real->line_char_offset += 1;
1898 real->segment_char_offset += 1;
1900 adjust_char_index (real, 1);
1902 g_assert (real->segment_char_offset < real->segment->char_count);
1904 /* We moved into the middle of a segment, so the any_segment
1905 must now be the segment we're in the middle of. */
1906 real->any_segment = real->segment;
1908 check_invariants ((GtkTextIter*)real);
1910 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1918 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1920 /* Need to move to the next segment; if no next segment,
1921 need to move to next line. */
1922 GtkTextLineSegment *seg;
1923 GtkTextLineSegment *any_seg;
1924 GtkTextRealIter *real;
1928 g_return_val_if_fail (iter != NULL, FALSE);
1930 real = gtk_text_iter_make_real (iter);
1935 check_invariants (iter);
1937 if (real->line_char_offset >= 0)
1939 chars_skipped = real->segment->char_count - real->segment_char_offset;
1940 g_assert (chars_skipped > 0);
1945 if (real->line_byte_offset >= 0)
1947 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1948 g_assert (bytes_skipped > 0);
1953 /* Get first segment of any kind */
1954 any_seg = real->segment->next;
1955 /* skip non-indexable segments, if any */
1957 while (seg != NULL && seg->char_count == 0)
1962 real->any_segment = any_seg;
1963 real->segment = seg;
1965 if (real->line_byte_offset >= 0)
1967 g_assert (bytes_skipped > 0);
1968 real->segment_byte_offset = 0;
1969 real->line_byte_offset += bytes_skipped;
1972 if (real->line_char_offset >= 0)
1974 g_assert (chars_skipped > 0);
1975 real->segment_char_offset = 0;
1976 real->line_char_offset += chars_skipped;
1977 adjust_char_index (real, chars_skipped);
1980 check_invariants (iter);
1982 return !gtk_text_iter_is_end (iter);
1986 /* End of the line */
1987 if (forward_line_leaving_caches_unmodified (real))
1989 adjust_line_number (real, 1);
1990 if (real->line_char_offset >= 0)
1991 adjust_char_index (real, chars_skipped);
1993 g_assert (real->line_byte_offset == 0);
1994 g_assert (real->line_char_offset == 0);
1995 g_assert (real->segment_byte_offset == 0);
1996 g_assert (real->segment_char_offset == 0);
1997 g_assert (gtk_text_iter_starts_line (iter));
1999 check_invariants (iter);
2001 return !gtk_text_iter_is_end (iter);
2005 /* End of buffer, but iter is still at start of last segment,
2006 * not at the end iterator. We put it on the end iterator.
2009 check_invariants (iter);
2011 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2012 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2014 gtk_text_iter_forward_to_line_end (iter);
2016 g_assert (gtk_text_iter_is_end (iter));
2024 at_last_indexable_segment (GtkTextRealIter *real)
2026 GtkTextLineSegment *seg;
2028 /* Return TRUE if there are no indexable segments after
2032 seg = real->segment->next;
2035 if (seg->char_count > 0)
2042 /* Goes back to the start of the next segment, even if
2043 * we're not at the start of the current segment (always
2044 * ends up on a different segment if it returns TRUE)
2047 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2049 /* Move to the start of the previous segment; if no previous
2050 * segment, to the last segment in the previous line. This is
2051 * inherently a bit inefficient due to the singly-linked list and
2052 * tree nodes, but we can't afford the RAM for doubly-linked.
2054 GtkTextRealIter *real;
2055 GtkTextLineSegment *seg;
2056 GtkTextLineSegment *any_seg;
2057 GtkTextLineSegment *prev_seg;
2058 GtkTextLineSegment *prev_any_seg;
2062 g_return_val_if_fail (iter != NULL, FALSE);
2064 real = gtk_text_iter_make_real (iter);
2069 check_invariants (iter);
2071 /* Find first segments in line */
2072 any_seg = real->line->segments;
2074 while (seg->char_count == 0)
2077 if (seg == real->segment)
2079 /* Could probably do this case faster by hand-coding the
2083 /* We were already at the start of a line;
2084 * go back to the previous line.
2086 if (gtk_text_iter_backward_line (iter))
2088 /* Go forward to last indexable segment in line. */
2089 while (!at_last_indexable_segment (real))
2090 _gtk_text_iter_forward_indexable_segment (iter);
2092 check_invariants (iter);
2097 return FALSE; /* We were at the start of the first line. */
2100 /* We must be in the middle of a line; so find the indexable
2101 * segment just before our current segment.
2103 g_assert (seg != real->segment);
2107 prev_any_seg = any_seg;
2109 any_seg = seg->next;
2111 while (seg->char_count == 0)
2114 while (seg != real->segment);
2116 g_assert (prev_seg != NULL);
2117 g_assert (prev_any_seg != NULL);
2118 g_assert (prev_seg->char_count > 0);
2120 /* We skipped the entire previous segment, plus any
2121 * chars we were into the current segment.
2123 if (real->segment_byte_offset >= 0)
2124 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2128 if (real->segment_char_offset >= 0)
2129 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2133 real->segment = prev_seg;
2134 real->any_segment = prev_any_seg;
2135 real->segment_byte_offset = 0;
2136 real->segment_char_offset = 0;
2138 if (bytes_skipped >= 0)
2140 if (real->line_byte_offset >= 0)
2142 real->line_byte_offset -= bytes_skipped;
2143 g_assert (real->line_byte_offset >= 0);
2147 real->line_byte_offset = -1;
2149 if (chars_skipped >= 0)
2151 if (real->line_char_offset >= 0)
2153 real->line_char_offset -= chars_skipped;
2154 g_assert (real->line_char_offset >= 0);
2157 if (real->cached_char_index >= 0)
2159 real->cached_char_index -= chars_skipped;
2160 g_assert (real->cached_char_index >= 0);
2165 real->line_char_offset = -1;
2166 real->cached_char_index = -1;
2169 /* line number is unchanged. */
2171 check_invariants (iter);
2177 * gtk_text_iter_forward_char:
2178 * @iter: an iterator
2180 * Moves @iter forward by one character offset. Note that images
2181 * embedded in the buffer occupy 1 character slot, so
2182 * gtk_text_iter_forward_char () may actually move onto an image instead
2183 * of a character, if you have images in your buffer. If @iter is the
2184 * end iterator or one character before it, @iter will now point at
2185 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2186 * convenience when writing loops.
2188 * Return value: whether @iter moved and is dereferenceable
2191 gtk_text_iter_forward_char (GtkTextIter *iter)
2193 GtkTextRealIter *real;
2195 g_return_val_if_fail (iter != NULL, FALSE);
2197 real = gtk_text_iter_make_real (iter);
2203 check_invariants (iter);
2204 return forward_char (real);
2209 * gtk_text_iter_backward_char:
2210 * @iter: an iterator
2212 * Moves backward by one character offset. Returns %TRUE if movement
2213 * was possible; if @iter was the first in the buffer (character
2214 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2217 * Return value: whether movement was possible
2220 gtk_text_iter_backward_char (GtkTextIter *iter)
2222 g_return_val_if_fail (iter != NULL, FALSE);
2224 check_invariants (iter);
2226 return gtk_text_iter_backward_chars (iter, 1);
2230 Definitely we should try to linear scan as often as possible for
2231 movement within a single line, because we can't use the BTree to
2232 speed within-line searches up; for movement between lines, we would
2233 like to avoid the linear scan probably.
2235 Instead of using this constant, it might be nice to cache the line
2236 length in the iterator and linear scan if motion is within a single
2239 I guess you'd have to profile the various approaches.
2241 #define MAX_LINEAR_SCAN 150
2245 * gtk_text_iter_forward_chars:
2246 * @iter: an iterator
2247 * @count: number of characters to move, may be negative
2249 * Moves @count characters if possible (if @count would move past the
2250 * start or end of the buffer, moves to the start or end of the
2251 * buffer). The return value indicates whether the new position of
2252 * @iter is different from its original position, and dereferenceable
2253 * (the last iterator in the buffer is not dereferenceable). If @count
2254 * is 0, the function does nothing and returns %FALSE.
2256 * Return value: whether @iter moved and is dereferenceable
2259 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2261 GtkTextRealIter *real;
2263 g_return_val_if_fail (iter != NULL, FALSE);
2265 FIX_OVERFLOWS (count);
2267 real = gtk_text_iter_make_real (iter);
2271 else if (count == 0)
2274 return gtk_text_iter_backward_chars (iter, 0 - count);
2275 else if (count < MAX_LINEAR_SCAN)
2277 check_invariants (iter);
2281 if (!forward_char (real))
2286 return forward_char (real);
2290 gint current_char_index;
2291 gint new_char_index;
2293 check_invariants (iter);
2295 current_char_index = gtk_text_iter_get_offset (iter);
2297 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2298 return FALSE; /* can't move forward */
2300 new_char_index = current_char_index + count;
2301 gtk_text_iter_set_offset (iter, new_char_index);
2303 check_invariants (iter);
2305 /* Return FALSE if we're on the non-dereferenceable end
2308 if (gtk_text_iter_is_end (iter))
2316 * gtk_text_iter_backward_chars:
2317 * @iter: an iterator
2318 * @count: number of characters to move
2320 * Moves @count characters backward, if possible (if @count would move
2321 * past the start or end of the buffer, moves to the start or end of
2322 * the buffer). The return value indicates whether the iterator moved
2323 * onto a dereferenceable position; if the iterator didn't move, or
2324 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2325 * the function does nothing and returns %FALSE.
2327 * Return value: whether @iter moved and is dereferenceable
2331 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2333 GtkTextRealIter *real;
2335 g_return_val_if_fail (iter != NULL, FALSE);
2337 FIX_OVERFLOWS (count);
2339 real = gtk_text_iter_make_real (iter);
2343 else if (count == 0)
2346 return gtk_text_iter_forward_chars (iter, 0 - count);
2348 ensure_char_offsets (real);
2349 check_invariants (iter);
2351 /* <, not <=, because if count == segment_char_offset
2352 * we're going to the front of the segment and the any_segment
2355 if (count < real->segment_char_offset)
2357 /* Optimize the within-segment case */
2358 g_assert (real->segment->char_count > 0);
2359 g_assert (real->segment->type == >k_text_char_type);
2361 if (real->line_byte_offset >= 0)
2364 gint new_byte_offset;
2366 /* if in the last fourth of the segment walk backwards */
2367 if (count < real->segment_char_offset / 4)
2368 p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset,
2371 p = g_utf8_offset_to_pointer (real->segment->body.chars,
2372 real->segment_char_offset - count);
2374 new_byte_offset = p - real->segment->body.chars;
2375 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2376 real->segment_byte_offset = new_byte_offset;
2379 real->segment_char_offset -= count;
2380 real->line_char_offset -= count;
2382 adjust_char_index (real, 0 - count);
2384 check_invariants (iter);
2390 /* We need to go back into previous segments. For now,
2391 * just keep this really simple. FIXME
2392 * use backward_indexable_segment.
2394 if (TRUE || count > MAX_LINEAR_SCAN)
2396 gint current_char_index;
2397 gint new_char_index;
2399 current_char_index = gtk_text_iter_get_offset (iter);
2401 if (current_char_index == 0)
2402 return FALSE; /* can't move backward */
2404 new_char_index = current_char_index - count;
2405 if (new_char_index < 0)
2408 gtk_text_iter_set_offset (iter, new_char_index);
2410 check_invariants (iter);
2416 /* FIXME backward_indexable_segment here */
2425 /* These two can't be implemented efficiently (always have to use
2426 * a linear scan, since that's the only way to find all the non-text
2431 * gtk_text_iter_forward_text_chars:
2432 * @iter: a #GtkTextIter
2433 * @count: number of chars to move
2435 * Moves forward by @count text characters (pixbufs, widgets,
2436 * etc. do not count as characters for this). Equivalent to moving
2437 * through the results of gtk_text_iter_get_text (), rather than
2438 * gtk_text_iter_get_slice ().
2440 * Return value: whether @iter moved and is dereferenceable
2443 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2452 * gtk_text_iter_forward_text_chars:
2453 * @iter: a #GtkTextIter
2454 * @count: number of chars to move
2456 * Moves backward by @count text characters (pixbufs, widgets,
2457 * etc. do not count as characters for this). Equivalent to moving
2458 * through the results of gtk_text_iter_get_text (), rather than
2459 * gtk_text_iter_get_slice ().
2461 * Return value: whether @iter moved and is dereferenceable
2464 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2473 * gtk_text_iter_forward_line:
2474 * @iter: an iterator
2476 * Moves @iter to the start of the next line. If the iter is already on the
2477 * last line of the buffer, moves the iter to the end of the current line.
2478 * If after the operation, the iter is at the end of the buffer and not
2479 * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
2481 * Return value: whether @iter can be dereferenced
2484 gtk_text_iter_forward_line (GtkTextIter *iter)
2486 GtkTextRealIter *real;
2488 g_return_val_if_fail (iter != NULL, FALSE);
2490 real = gtk_text_iter_make_real (iter);
2495 check_invariants (iter);
2497 if (forward_line_leaving_caches_unmodified (real))
2499 invalidate_char_index (real);
2500 adjust_line_number (real, 1);
2502 check_invariants (iter);
2504 if (gtk_text_iter_is_end (iter))
2511 /* On the last line, move to end of it */
2513 if (!gtk_text_iter_is_end (iter))
2514 gtk_text_iter_forward_to_end (iter);
2516 check_invariants (iter);
2522 * gtk_text_iter_backward_line:
2523 * @iter: an iterator
2525 * Moves @iter to the start of the previous line. Returns %TRUE if
2526 * @iter could be moved; i.e. if @iter was at character offset 0, this
2527 * function returns %FALSE. Therefore if @iter was already on line 0,
2528 * but not at the start of the line, @iter is snapped to the start of
2529 * the line and the function returns %TRUE. (Note that this implies that
2530 * in a loop calling this function, the line number may not change on
2531 * every iteration, if your first iteration is on line 0.)
2533 * Return value: whether @iter moved
2536 gtk_text_iter_backward_line (GtkTextIter *iter)
2538 GtkTextLine *new_line;
2539 GtkTextRealIter *real;
2540 gboolean offset_will_change;
2543 g_return_val_if_fail (iter != NULL, FALSE);
2545 real = gtk_text_iter_make_real (iter);
2550 check_invariants (iter);
2552 new_line = _gtk_text_line_previous (real->line);
2554 offset_will_change = FALSE;
2555 if (real->line_char_offset > 0)
2556 offset_will_change = TRUE;
2558 if (new_line != NULL)
2560 real->line = new_line;
2562 adjust_line_number (real, -1);
2566 if (!offset_will_change)
2570 invalidate_char_index (real);
2572 real->line_byte_offset = 0;
2573 real->line_char_offset = 0;
2575 real->segment_byte_offset = 0;
2576 real->segment_char_offset = 0;
2578 /* Find first segment in line */
2579 real->any_segment = real->line->segments;
2580 real->segment = _gtk_text_line_byte_to_segment (real->line,
2583 g_assert (offset == 0);
2585 /* Note that if we are on the first line, we snap to the start of
2586 * the first line and return TRUE, so TRUE means the iterator
2587 * changed, not that the line changed; this is maybe a bit
2588 * weird. I'm not sure there's an obvious right thing to do though.
2591 check_invariants (iter);
2598 * gtk_text_iter_forward_lines:
2599 * @iter: a #GtkTextIter
2600 * @count: number of lines to move forward
2602 * Moves @count lines forward, if possible (if @count would move
2603 * past the start or end of the buffer, moves to the start or end of
2604 * the buffer). The return value indicates whether the iterator moved
2605 * onto a dereferenceable position; if the iterator didn't move, or
2606 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2607 * the function does nothing and returns %FALSE. If @count is negative,
2608 * moves backward by 0 - @count lines.
2610 * Return value: whether @iter moved and is dereferenceable
2613 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2615 FIX_OVERFLOWS (count);
2618 return gtk_text_iter_backward_lines (iter, 0 - count);
2619 else if (count == 0)
2621 else if (count == 1)
2623 check_invariants (iter);
2624 return gtk_text_iter_forward_line (iter);
2630 if (gtk_text_iter_is_end (iter))
2633 old_line = gtk_text_iter_get_line (iter);
2635 gtk_text_iter_set_line (iter, old_line + count);
2637 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2639 /* count went past the last line, so move to end of last line */
2640 if (!gtk_text_iter_is_end (iter))
2641 gtk_text_iter_forward_to_end (iter);
2644 return !gtk_text_iter_is_end (iter);
2649 * gtk_text_iter_backward_lines:
2650 * @iter: a #GtkTextIter
2651 * @count: number of lines to move backward
2653 * Moves @count lines backward, if possible (if @count would move
2654 * past the start or end of the buffer, moves to the start or end of
2655 * the buffer). The return value indicates whether the iterator moved
2656 * onto a dereferenceable position; if the iterator didn't move, or
2657 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2658 * the function does nothing and returns %FALSE. If @count is negative,
2659 * moves forward by 0 - @count lines.
2661 * Return value: whether @iter moved and is dereferenceable
2664 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2666 FIX_OVERFLOWS (count);
2669 return gtk_text_iter_forward_lines (iter, 0 - count);
2670 else if (count == 0)
2672 else if (count == 1)
2674 return gtk_text_iter_backward_line (iter);
2680 old_line = gtk_text_iter_get_line (iter);
2682 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2684 return (gtk_text_iter_get_line (iter) != old_line);
2689 * gtk_text_iter_forward_visible_line:
2690 * @iter: an iterator
2692 * Moves @iter to the start of the next visible line. Returns %TRUE if there
2693 * was a next line to move to, and %FALSE if @iter was simply moved to
2694 * the end of the buffer and is now not dereferenceable, or if @iter was
2695 * already at the end of the buffer.
2697 * Return value: whether @iter can be dereferenced
2702 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2704 while (gtk_text_iter_forward_line (iter))
2706 if (!_gtk_text_btree_char_is_invisible (iter))
2712 if (!gtk_text_iter_forward_char (iter))
2715 if (!_gtk_text_btree_char_is_invisible (iter))
2718 while (!gtk_text_iter_ends_line (iter));
2726 * gtk_text_iter_backward_visible_line:
2727 * @iter: an iterator
2729 * Moves @iter to the start of the previous visible line. Returns %TRUE if
2730 * @iter could be moved; i.e. if @iter was at character offset 0, this
2731 * function returns %FALSE. Therefore if @iter was already on line 0,
2732 * but not at the start of the line, @iter is snapped to the start of
2733 * the line and the function returns %TRUE. (Note that this implies that
2734 * in a loop calling this function, the line number may not change on
2735 * every iteration, if your first iteration is on line 0.)
2737 * Return value: whether @iter moved
2742 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2744 while (gtk_text_iter_backward_line (iter))
2746 if (!_gtk_text_btree_char_is_invisible (iter))
2752 if (!gtk_text_iter_backward_char (iter))
2755 if (!_gtk_text_btree_char_is_invisible (iter))
2758 while (!gtk_text_iter_starts_line (iter));
2766 * gtk_text_iter_forward_visible_lines:
2767 * @iter: a #GtkTextIter
2768 * @count: number of lines to move forward
2770 * Moves @count visible lines forward, if possible (if @count would move
2771 * past the start or end of the buffer, moves to the start or end of
2772 * the buffer). The return value indicates whether the iterator moved
2773 * onto a dereferenceable position; if the iterator didn't move, or
2774 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2775 * the function does nothing and returns %FALSE. If @count is negative,
2776 * moves backward by 0 - @count lines.
2778 * Return value: whether @iter moved and is dereferenceable
2783 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2786 FIX_OVERFLOWS (count);
2789 return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2790 else if (count == 0)
2792 else if (count == 1)
2794 check_invariants (iter);
2795 return gtk_text_iter_forward_visible_line (iter);
2799 while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2806 * gtk_text_iter_backward_visible_lines:
2807 * @iter: a #GtkTextIter
2808 * @count: number of lines to move backward
2810 * Moves @count visible lines backward, if possible (if @count would move
2811 * past the start or end of the buffer, moves to the start or end of
2812 * the buffer). The return value indicates whether the iterator moved
2813 * onto a dereferenceable position; if the iterator didn't move, or
2814 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2815 * the function does nothing and returns %FALSE. If @count is negative,
2816 * moves forward by 0 - @count lines.
2818 * Return value: whether @iter moved and is dereferenceable
2823 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2826 FIX_OVERFLOWS (count);
2829 return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2830 else if (count == 0)
2832 else if (count == 1)
2834 return gtk_text_iter_backward_visible_line (iter);
2838 while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2844 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2849 gboolean already_moved_initially);
2851 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2859 find_word_end_func (const PangoLogAttr *attrs,
2864 gboolean already_moved_initially)
2866 if (!already_moved_initially)
2869 /* Find end of next word */
2870 while (offset < min_offset + len &&
2871 !attrs[offset].is_word_end)
2874 *found_offset = offset;
2876 return offset < min_offset + len;
2880 is_word_end_func (const PangoLogAttr *attrs,
2885 return attrs[offset].is_word_end;
2889 find_word_start_func (const PangoLogAttr *attrs,
2894 gboolean already_moved_initially)
2896 if (!already_moved_initially)
2899 /* Find start of prev word */
2900 while (offset >= min_offset &&
2901 !attrs[offset].is_word_start)
2904 *found_offset = offset;
2906 return offset >= min_offset;
2910 is_word_start_func (const PangoLogAttr *attrs,
2915 return attrs[offset].is_word_start;
2919 inside_word_func (const PangoLogAttr *attrs,
2924 /* Find next word start or end */
2925 while (offset >= min_offset &&
2926 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2930 return attrs[offset].is_word_start;
2935 /* Sentence funcs */
2938 find_sentence_end_func (const PangoLogAttr *attrs,
2943 gboolean already_moved_initially)
2945 if (!already_moved_initially)
2948 /* Find end of next sentence */
2949 while (offset < min_offset + len &&
2950 !attrs[offset].is_sentence_end)
2953 *found_offset = offset;
2955 return offset < min_offset + len;
2959 is_sentence_end_func (const PangoLogAttr *attrs,
2964 return attrs[offset].is_sentence_end;
2968 find_sentence_start_func (const PangoLogAttr *attrs,
2973 gboolean already_moved_initially)
2975 if (!already_moved_initially)
2978 /* Find start of prev sentence */
2979 while (offset >= min_offset &&
2980 !attrs[offset].is_sentence_start)
2983 *found_offset = offset;
2985 return offset >= min_offset;
2989 is_sentence_start_func (const PangoLogAttr *attrs,
2994 return attrs[offset].is_sentence_start;
2998 inside_sentence_func (const PangoLogAttr *attrs,
3003 /* Find next sentence start or end */
3004 while (offset >= min_offset &&
3005 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3008 return attrs[offset].is_sentence_start;
3012 test_log_attrs (const GtkTextIter *iter,
3013 TestLogAttrFunc func)
3016 const PangoLogAttr *attrs;
3018 gboolean result = FALSE;
3020 g_return_val_if_fail (iter != NULL, FALSE);
3022 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3025 offset = gtk_text_iter_get_line_offset (iter);
3027 /* char_len may be 0 and attrs will be NULL if so, if
3028 * iter is the end iter and the last line is empty.
3030 * offset may be equal to char_len, since attrs contains an entry
3031 * for one past the end
3034 if (attrs && offset <= char_len)
3035 result = (* func) (attrs, offset, 0, char_len);
3041 find_line_log_attrs (const GtkTextIter *iter,
3042 FindLogAttrFunc func,
3044 gboolean already_moved_initially)
3047 const PangoLogAttr *attrs;
3049 gboolean result = FALSE;
3051 g_return_val_if_fail (iter != NULL, FALSE);
3053 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3056 offset = gtk_text_iter_get_line_offset (iter);
3058 /* char_len may be 0 and attrs will be NULL if so, if
3059 * iter is the end iter and the last line is empty
3063 result = (* func) (attrs, offset, 0, char_len, found_offset,
3064 already_moved_initially);
3069 /* FIXME this function is very, very gratuitously slow */
3071 find_by_log_attrs (GtkTextIter *iter,
3072 FindLogAttrFunc func,
3074 gboolean already_moved_initially)
3078 gboolean found = FALSE;
3080 g_return_val_if_fail (iter != NULL, FALSE);
3084 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3090 if (gtk_text_iter_forward_line (iter))
3091 return find_by_log_attrs (iter, func, forward,
3098 /* go to end of previous line. need to check that
3099 * line is > 0 because backward_line snaps to start of
3100 * line 0 if it's on line 0
3102 if (gtk_text_iter_get_line (iter) > 0 &&
3103 gtk_text_iter_backward_line (iter))
3105 if (!gtk_text_iter_ends_line (iter))
3106 gtk_text_iter_forward_to_line_end (iter);
3108 return find_by_log_attrs (iter, func, forward,
3117 gtk_text_iter_set_line_offset (iter, offset);
3120 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3121 !gtk_text_iter_is_end (iter);
3126 find_visible_by_log_attrs (GtkTextIter *iter,
3127 FindLogAttrFunc func,
3129 gboolean already_moved_initially)
3133 g_return_val_if_fail (iter != NULL, FALSE);
3137 while (find_by_log_attrs (&pos, func, forward, already_moved_initially))
3139 if (!_gtk_text_btree_char_is_invisible (&pos))
3149 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3150 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3153 move_multiple_steps (GtkTextIter *iter,
3155 OneStepFunc step_forward,
3156 MultipleStepFunc n_steps_backward)
3158 g_return_val_if_fail (iter != NULL, FALSE);
3160 FIX_OVERFLOWS (count);
3166 return n_steps_backward (iter, -count);
3168 if (!step_forward (iter))
3174 if (!step_forward (iter))
3179 return !gtk_text_iter_is_end (iter);
3184 * gtk_text_iter_forward_word_end:
3185 * @iter: a #GtkTextIter
3187 * Moves forward to the next word end. (If @iter is currently on a
3188 * word end, moves forward to the next one after that.) Word breaks
3189 * are determined by Pango and should be correct for nearly any
3190 * language (if not, the correct fix would be to the Pango word break
3193 * Return value: %TRUE if @iter moved and is not the end iterator
3196 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3198 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3202 * gtk_text_iter_backward_word_start:
3203 * @iter: a #GtkTextIter
3205 * Moves backward to the previous word start. (If @iter is currently on a
3206 * word start, moves backward to the next one after that.) Word breaks
3207 * are determined by Pango and should be correct for nearly any
3208 * language (if not, the correct fix would be to the Pango word break
3211 * Return value: %TRUE if @iter moved and is not the end iterator
3214 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3216 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3219 /* FIXME a loop around a truly slow function means
3220 * a truly spectacularly slow function.
3224 * gtk_text_iter_forward_word_ends:
3225 * @iter: a #GtkTextIter
3226 * @count: number of times to move
3228 * Calls gtk_text_iter_forward_word_end() up to @count times.
3230 * Return value: %TRUE if @iter moved and is not the end iterator
3233 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3236 return move_multiple_steps (iter, count,
3237 gtk_text_iter_forward_word_end,
3238 gtk_text_iter_backward_word_starts);
3242 * gtk_text_iter_backward_word_starts
3243 * @iter: a #GtkTextIter
3244 * @count: number of times to move
3246 * Calls gtk_text_iter_backward_word_start() up to @count times.
3248 * Return value: %TRUE if @iter moved and is not the end iterator
3251 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3254 return move_multiple_steps (iter, count,
3255 gtk_text_iter_backward_word_start,
3256 gtk_text_iter_forward_word_ends);
3260 * gtk_text_iter_forward_visible_word_end:
3261 * @iter: a #GtkTextIter
3263 * Moves forward to the next visible word end. (If @iter is currently on a
3264 * word end, moves forward to the next one after that.) Word breaks
3265 * are determined by Pango and should be correct for nearly any
3266 * language (if not, the correct fix would be to the Pango word break
3269 * Return value: %TRUE if @iter moved and is not the end iterator
3274 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3276 return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3280 * gtk_text_iter_backward_visible_word_start:
3281 * @iter: a #GtkTextIter
3283 * Moves backward to the previous visible word start. (If @iter is currently
3284 * on a word start, moves backward to the next one after that.) Word breaks
3285 * are determined by Pango and should be correct for nearly any
3286 * language (if not, the correct fix would be to the Pango word break
3289 * Return value: %TRUE if @iter moved and is not the end iterator
3294 gtk_text_iter_backward_visible_word_start (GtkTextIter *iter)
3296 return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3300 * gtk_text_iter_forward_visible_word_ends:
3301 * @iter: a #GtkTextIter
3302 * @count: number of times to move
3304 * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3306 * Return value: %TRUE if @iter moved and is not the end iterator
3311 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3314 return move_multiple_steps (iter, count,
3315 gtk_text_iter_forward_visible_word_end,
3316 gtk_text_iter_backward_visible_word_starts);
3320 * gtk_text_iter_backward_visible_word_starts
3321 * @iter: a #GtkTextIter
3322 * @count: number of times to move
3324 * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3326 * Return value: %TRUE if @iter moved and is not the end iterator
3331 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3334 return move_multiple_steps (iter, count,
3335 gtk_text_iter_backward_visible_word_start,
3336 gtk_text_iter_forward_visible_word_ends);
3340 * gtk_text_iter_starts_word:
3341 * @iter: a #GtkTextIter
3343 * Determines whether @iter begins a natural-language word. Word
3344 * breaks are determined by Pango and should be correct for nearly any
3345 * language (if not, the correct fix would be to the Pango word break
3348 * Return value: %TRUE if @iter is at the start of a word
3351 gtk_text_iter_starts_word (const GtkTextIter *iter)
3353 return test_log_attrs (iter, is_word_start_func);
3357 * gtk_text_iter_ends_word:
3358 * @iter: a #GtkTextIter
3360 * Determines whether @iter ends a natural-language word. Word breaks
3361 * are determined by Pango and should be correct for nearly any
3362 * language (if not, the correct fix would be to the Pango word break
3365 * Return value: %TRUE if @iter is at the end of a word
3368 gtk_text_iter_ends_word (const GtkTextIter *iter)
3370 return test_log_attrs (iter, is_word_end_func);
3374 * gtk_text_iter_inside_word:
3375 * @iter: a #GtkTextIter
3377 * Determines whether @iter is inside a natural-language word (as
3378 * opposed to say inside some whitespace). Word breaks are determined
3379 * by Pango and should be correct for nearly any language (if not, the
3380 * correct fix would be to the Pango word break algorithms).
3382 * Return value: %TRUE if @iter is inside a word
3385 gtk_text_iter_inside_word (const GtkTextIter *iter)
3387 return test_log_attrs (iter, inside_word_func);
3391 * gtk_text_iter_starts_sentence:
3392 * @iter: a #GtkTextIter
3394 * Determines whether @iter begins a sentence. Sentence boundaries are
3395 * determined by Pango and should be correct for nearly any language
3396 * (if not, the correct fix would be to the Pango text boundary
3399 * Return value: %TRUE if @iter is at the start of a sentence.
3402 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3404 return test_log_attrs (iter, is_sentence_start_func);
3408 * gtk_text_iter_ends_sentence:
3409 * @iter: a #GtkTextIter
3411 * Determines whether @iter ends a sentence. Sentence boundaries are
3412 * determined by Pango and should be correct for nearly any language
3413 * (if not, the correct fix would be to the Pango text boundary
3416 * Return value: %TRUE if @iter is at the end of a sentence.
3419 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3421 return test_log_attrs (iter, is_sentence_end_func);
3425 * gtk_text_iter_inside_sentence:
3426 * @iter: a #GtkTextIter
3428 * Determines whether @iter is inside a sentence (as opposed to in
3429 * between two sentences, e.g. after a period and before the first
3430 * letter of the next sentence). Sentence boundaries are determined
3431 * by Pango and should be correct for nearly any language (if not, the
3432 * correct fix would be to the Pango text boundary algorithms).
3434 * Return value: %TRUE if @iter is inside a sentence.
3437 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3439 return test_log_attrs (iter, inside_sentence_func);
3443 * gtk_text_iter_forward_sentence_end:
3444 * @iter: a #GtkTextIter
3446 * Moves forward to the next sentence end. (If @iter is at the end of
3447 * a sentence, moves to the next end of sentence.) Sentence
3448 * boundaries are determined by Pango and should be correct for nearly
3449 * any language (if not, the correct fix would be to the Pango text
3450 * boundary algorithms).
3452 * Return value: %TRUE if @iter moved and is not the end iterator
3455 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3457 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3461 * gtk_text_iter_backward_sentence_start:
3462 * @iter: a #GtkTextIter
3464 * Moves backward to the previous sentence start; if @iter is already at
3465 * the start of a sentence, moves backward to the next one. Sentence
3466 * boundaries are determined by Pango and should be correct for nearly
3467 * any language (if not, the correct fix would be to the Pango text
3468 * boundary algorithms).
3470 * Return value: %TRUE if @iter moved and is not the end iterator
3473 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3475 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3478 /* FIXME a loop around a truly slow function means
3479 * a truly spectacularly slow function.
3482 * gtk_text_iter_forward_sentence_ends:
3483 * @iter: a #GtkTextIter
3484 * @count: number of sentences to move
3486 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3487 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3488 * negative, moves backward instead of forward.
3490 * Return value: %TRUE if @iter moved and is not the end iterator
3493 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3496 return move_multiple_steps (iter, count,
3497 gtk_text_iter_forward_sentence_end,
3498 gtk_text_iter_backward_sentence_starts);
3502 * gtk_text_iter_backward_sentence_starts:
3503 * @iter: a #GtkTextIter
3504 * @count: number of sentences to move
3506 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3507 * or until it returns %FALSE. If @count is negative, moves forward
3508 * instead of backward.
3510 * Return value: %TRUE if @iter moved and is not the end iterator
3513 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3516 return move_multiple_steps (iter, count,
3517 gtk_text_iter_backward_sentence_start,
3518 gtk_text_iter_forward_sentence_ends);
3522 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3527 gboolean already_moved_initially)
3529 if (!already_moved_initially)
3532 while (offset < (min_offset + len) &&
3533 !attrs[offset].is_cursor_position)
3536 *found_offset = offset;
3538 return offset < (min_offset + len);
3542 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3547 gboolean already_moved_initially)
3549 if (!already_moved_initially)
3552 while (offset > min_offset &&
3553 !attrs[offset].is_cursor_position)
3556 *found_offset = offset;
3558 return offset >= min_offset;
3562 is_cursor_pos_func (const PangoLogAttr *attrs,
3567 return attrs[offset].is_cursor_position;
3571 * gtk_text_iter_forward_cursor_position:
3572 * @iter: a #GtkTextIter
3574 * Moves @iter forward by a single cursor position. Cursor positions
3575 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3576 * surprisingly, there may not be a cursor position between all
3577 * characters. The most common example for European languages would be
3578 * a carriage return/newline sequence. For some Unicode characters,
3579 * the equivalent of say the letter "a" with an accent mark will be
3580 * represented as two characters, first the letter then a "combining
3581 * mark" that causes the accent to be rendered; so the cursor can't go
3582 * between those two characters. See also the #PangoLogAttr structure and
3583 * pango_break() function.
3585 * Return value: %TRUE if we moved and the new position is dereferenceable
3588 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3590 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3594 * gtk_text_iter_backward_cursor_position:
3595 * @iter: a #GtkTextIter
3597 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3599 * Return value: %TRUE if we moved
3602 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3604 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3608 * gtk_text_iter_forward_cursor_positions:
3609 * @iter: a #GtkTextIter
3610 * @count: number of positions to move
3612 * Moves up to @count cursor positions. See
3613 * gtk_text_iter_forward_cursor_position() for details.
3615 * Return value: %TRUE if we moved and the new position is dereferenceable
3618 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3621 return move_multiple_steps (iter, count,
3622 gtk_text_iter_forward_cursor_position,
3623 gtk_text_iter_backward_cursor_positions);
3627 * gtk_text_iter_backward_cursor_positions:
3628 * @iter: a #GtkTextIter
3629 * @count: number of positions to move
3631 * Moves up to @count cursor positions. See
3632 * gtk_text_iter_forward_cursor_position() for details.
3634 * Return value: %TRUE if we moved and the new position is dereferenceable
3637 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3640 return move_multiple_steps (iter, count,
3641 gtk_text_iter_backward_cursor_position,
3642 gtk_text_iter_forward_cursor_positions);
3646 * gtk_text_iter_forward_visible_cursor_position:
3647 * @iter: a #GtkTextIter
3649 * Moves @iter forward to the next visible cursor position. See
3650 * gtk_text_iter_forward_cursor_position() for details.
3652 * Return value: %TRUE if we moved and the new position is dereferenceable
3657 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3659 return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3663 * gtk_text_iter_backward_visible_cursor_position:
3664 * @iter: a #GtkTextIter
3666 * Moves @iter forward to the previous visible cursor position. See
3667 * gtk_text_iter_backward_cursor_position() for details.
3669 * Return value: %TRUE if we moved and the new position is dereferenceable
3674 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3676 return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3680 * gtk_text_iter_forward_visible_cursor_positions:
3681 * @iter: a #GtkTextIter
3682 * @count: number of positions to move
3684 * Moves up to @count visible cursor positions. See
3685 * gtk_text_iter_forward_cursor_position() for details.
3687 * Return value: %TRUE if we moved and the new position is dereferenceable
3692 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3695 return move_multiple_steps (iter, count,
3696 gtk_text_iter_forward_visible_cursor_position,
3697 gtk_text_iter_backward_visible_cursor_positions);
3701 * gtk_text_iter_backward_visible_cursor_positions:
3702 * @iter: a #GtkTextIter
3703 * @count: number of positions to move
3705 * Moves up to @count visible cursor positions. See
3706 * gtk_text_iter_backward_cursor_position() for details.
3708 * Return value: %TRUE if we moved and the new position is dereferenceable
3713 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3716 return move_multiple_steps (iter, count,
3717 gtk_text_iter_backward_visible_cursor_position,
3718 gtk_text_iter_forward_visible_cursor_positions);
3722 * gtk_text_iter_is_cursor_position:
3723 * @iter: a #GtkTextIter
3725 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3726 * pango_break() for details on what a cursor position is.
3728 * Return value: %TRUE if the cursor can be placed at @iter
3731 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3733 return test_log_attrs (iter, is_cursor_pos_func);
3737 * gtk_text_iter_set_line_offset:
3738 * @iter: a #GtkTextIter
3739 * @char_on_line: a character offset relative to the start of @iter's current line
3741 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3742 * (not byte) offset. The given character offset must be less than or
3743 * equal to the number of characters in the line; if equal, @iter
3744 * moves to the start of the next line. See
3745 * gtk_text_iter_set_line_index() if you have a byte index rather than
3746 * a character offset.
3750 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3753 GtkTextRealIter *real;
3756 g_return_if_fail (iter != NULL);
3758 real = gtk_text_iter_make_surreal (iter);
3763 check_invariants (iter);
3765 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3767 g_return_if_fail (char_on_line <= chars_in_line);
3769 if (char_on_line < chars_in_line)
3770 iter_set_from_char_offset (real, real->line, char_on_line);
3772 gtk_text_iter_forward_line (iter); /* set to start of next line */
3774 check_invariants (iter);
3778 * gtk_text_iter_set_line_index:
3779 * @iter: a #GtkTextIter
3780 * @byte_on_line: a byte index relative to the start of @iter's current line
3782 * Same as gtk_text_iter_set_line_offset(), but works with a
3783 * <emphasis>byte</emphasis> index. The given byte index must be at
3784 * the start of a character, it can't be in the middle of a UTF-8
3785 * encoded character.
3789 gtk_text_iter_set_line_index (GtkTextIter *iter,
3792 GtkTextRealIter *real;
3795 g_return_if_fail (iter != NULL);
3797 real = gtk_text_iter_make_surreal (iter);
3802 check_invariants (iter);
3804 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3806 g_return_if_fail (byte_on_line <= bytes_in_line);
3808 if (byte_on_line < bytes_in_line)
3809 iter_set_from_byte_offset (real, real->line, byte_on_line);
3811 gtk_text_iter_forward_line (iter);
3813 if (real->segment->type == >k_text_char_type &&
3814 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3815 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3816 "character; this will crash the text buffer. "
3817 "Byte indexes must refer to the start of a character.",
3818 G_STRLOC, byte_on_line);
3820 check_invariants (iter);
3825 * gtk_text_iter_set_visible_line_offset:
3826 * @iter: a #GtkTextIter
3827 * @char_on_line: a character offset
3829 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3830 * characters, i.e. text with a tag making it invisible is not
3831 * counted in the offset.
3834 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3837 gint chars_seen = 0;
3840 g_return_if_fail (iter != NULL);
3842 gtk_text_iter_set_line_offset (iter, 0);
3846 /* For now we use a ludicrously slow implementation */
3847 while (chars_seen < char_on_line)
3849 if (!_gtk_text_btree_char_is_invisible (&pos))
3852 if (!gtk_text_iter_forward_char (&pos))
3855 if (chars_seen == char_on_line)
3859 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3862 gtk_text_iter_forward_line (iter);
3866 * gtk_text_iter_set_visible_line_index:
3867 * @iter: a #GtkTextIter
3868 * @byte_on_line: a byte index
3870 * Like gtk_text_iter_set_line_index(), but the index is in visible
3871 * bytes, i.e. text with a tag making it invisible is not counted
3875 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3878 GtkTextRealIter *real;
3881 GtkTextLineSegment *seg;
3883 g_return_if_fail (iter != NULL);
3885 gtk_text_iter_set_line_offset (iter, 0);
3889 real = gtk_text_iter_make_real (&pos);
3894 ensure_byte_offsets (real);
3896 check_invariants (&pos);
3898 seg = _gtk_text_iter_get_indexable_segment (&pos);
3900 while (seg != NULL && byte_on_line > 0)
3902 if (!_gtk_text_btree_char_is_invisible (&pos))
3904 if (byte_on_line < seg->byte_count)
3906 iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3911 byte_on_line -= seg->byte_count;
3914 offset += seg->byte_count;
3915 _gtk_text_iter_forward_indexable_segment (&pos);
3916 seg = _gtk_text_iter_get_indexable_segment (&pos);
3919 if (byte_on_line == 0)
3922 gtk_text_iter_forward_line (iter);
3926 * gtk_text_iter_set_line:
3927 * @iter: a #GtkTextIter
3928 * @line_number: line number (counted from 0)
3930 * Moves iterator @iter to the start of the line @line_number. If
3931 * @line_number is negative or larger than the number of lines in the
3932 * buffer, moves @iter to the start of the last line in the buffer.
3936 gtk_text_iter_set_line (GtkTextIter *iter,
3941 GtkTextRealIter *real;
3943 g_return_if_fail (iter != NULL);
3945 real = gtk_text_iter_make_surreal (iter);
3950 check_invariants (iter);
3952 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3954 iter_set_from_char_offset (real, line, 0);
3956 /* We might as well cache this, since we know it. */
3957 real->cached_line_number = real_line;
3959 check_invariants (iter);
3963 * gtk_text_iter_set_offset:
3964 * @iter: a #GtkTextIter
3965 * @char_offset: a character number
3967 * Sets @iter to point to @char_offset. @char_offset counts from the start
3968 * of the entire text buffer, starting with 0.
3971 gtk_text_iter_set_offset (GtkTextIter *iter,
3975 GtkTextRealIter *real;
3977 gint real_char_index;
3979 g_return_if_fail (iter != NULL);
3981 real = gtk_text_iter_make_surreal (iter);
3986 check_invariants (iter);
3988 if (real->cached_char_index >= 0 &&
3989 real->cached_char_index == char_offset)
3992 line = _gtk_text_btree_get_line_at_char (real->tree,
3997 iter_set_from_char_offset (real, line, real_char_index - line_start);
3999 /* Go ahead and cache this since we have it. */
4000 real->cached_char_index = real_char_index;
4002 check_invariants (iter);
4006 * gtk_text_iter_forward_to_end:
4007 * @iter: a #GtkTextIter
4009 * Moves @iter forward to the "end iterator," which points one past the last
4010 * valid character in the buffer. gtk_text_iter_get_char() called on the
4011 * end iterator returns 0, which is convenient for writing loops.
4014 gtk_text_iter_forward_to_end (GtkTextIter *iter)
4016 GtkTextBuffer *buffer;
4017 GtkTextRealIter *real;
4019 g_return_if_fail (iter != NULL);
4021 real = gtk_text_iter_make_surreal (iter);
4026 buffer = _gtk_text_btree_get_buffer (real->tree);
4028 gtk_text_buffer_get_end_iter (buffer, iter);
4031 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4032 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4033 * If all else fails we could cache the para delimiter pos in the iter.
4034 * I think forward_to_line_end() actually gets called fairly often.
4037 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4042 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4043 _gtk_text_iter_get_btree (&end)))
4045 gtk_text_iter_forward_to_end (&end);
4049 /* if we aren't on the last line, go forward to start of next line, then scan
4050 * back for the delimiters on the previous line
4052 gtk_text_iter_forward_line (&end);
4053 gtk_text_iter_backward_char (&end);
4054 while (!gtk_text_iter_ends_line (&end))
4055 gtk_text_iter_backward_char (&end);
4058 return gtk_text_iter_get_line_offset (&end);
4062 * gtk_text_iter_forward_to_line_end:
4063 * @iter: a #GtkTextIter
4065 * Moves the iterator to point to the paragraph delimiter characters,
4066 * which will be either a newline, a carriage return, a carriage
4067 * return/newline in sequence, or the Unicode paragraph separator
4068 * character. If the iterator is already at the paragraph delimiter
4069 * characters, moves to the paragraph delimiter characters for the
4070 * next line. If @iter is on the last line in the buffer, which does
4071 * not end in paragraph delimiters, moves to the end iterator (end of
4072 * the last line), and returns %FALSE.
4074 * Return value: %TRUE if we moved and the new location is not the end iterator
4077 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4079 gint current_offset;
4083 g_return_val_if_fail (iter != NULL, FALSE);
4085 current_offset = gtk_text_iter_get_line_offset (iter);
4086 new_offset = find_paragraph_delimiter_for_line (iter);
4088 if (current_offset < new_offset)
4090 /* Move to end of this line. */
4091 gtk_text_iter_set_line_offset (iter, new_offset);
4092 return !gtk_text_iter_is_end (iter);
4096 /* Move to end of next line. */
4097 if (gtk_text_iter_forward_line (iter))
4099 /* We don't want to move past all
4102 if (!gtk_text_iter_ends_line (iter))
4103 gtk_text_iter_forward_to_line_end (iter);
4104 return !gtk_text_iter_is_end (iter);
4112 * gtk_text_iter_forward_to_tag_toggle:
4113 * @iter: a #GtkTextIter
4114 * @tag: a #GtkTextTag, or %NULL
4116 * Moves forward to the next toggle (on or off) of the
4117 * #GtkTextTag @tag, or to the next toggle of any tag if
4118 * @tag is %NULL. If no matching tag toggles are found,
4119 * returns %FALSE, otherwise %TRUE. Does not return toggles
4120 * located at @iter, only toggles after @iter. Sets @iter to
4121 * the location of the toggle, or to the end of the buffer
4122 * if no toggle is found.
4124 * Return value: whether we found a tag toggle after @iter
4127 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4130 GtkTextLine *next_line;
4131 GtkTextLine *current_line;
4132 GtkTextRealIter *real;
4134 g_return_val_if_fail (iter != NULL, FALSE);
4136 real = gtk_text_iter_make_real (iter);
4141 check_invariants (iter);
4143 current_line = real->line;
4144 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4147 while (_gtk_text_iter_forward_indexable_segment (iter))
4149 /* If we went forward to a line that couldn't contain a toggle
4150 for the tag, then skip forward to a line that could contain
4151 it. This potentially skips huge hunks of the tree, so we
4152 aren't a purely linear search. */
4153 if (real->line != current_line)
4155 if (next_line == NULL)
4157 /* End of search. Set to end of buffer. */
4158 _gtk_text_btree_get_end_iter (real->tree, iter);
4162 if (real->line != next_line)
4163 iter_set_from_byte_offset (real, next_line, 0);
4165 current_line = real->line;
4166 next_line = _gtk_text_line_next_could_contain_tag (current_line,
4171 if (gtk_text_iter_toggles_tag (iter, tag))
4173 /* If there's a toggle here, it isn't indexable so
4174 any_segment can't be the indexable segment. */
4175 g_assert (real->any_segment != real->segment);
4180 /* Check end iterator for tags */
4181 if (gtk_text_iter_toggles_tag (iter, tag))
4183 /* If there's a toggle here, it isn't indexable so
4184 any_segment can't be the indexable segment. */
4185 g_assert (real->any_segment != real->segment);
4189 /* Reached end of buffer */
4194 * gtk_text_iter_backward_to_tag_toggle:
4195 * @iter: a #GtkTextIter
4196 * @tag: a #GtkTextTag, or %NULL
4198 * Moves backward to the next toggle (on or off) of the
4199 * #GtkTextTag @tag, or to the next toggle of any tag if
4200 * @tag is %NULL. If no matching tag toggles are found,
4201 * returns %FALSE, otherwise %TRUE. Does not return toggles
4202 * located at @iter, only toggles before @iter. Sets @iter
4203 * to the location of the toggle, or the start of the buffer
4204 * if no toggle is found.
4206 * Return value: whether we found a tag toggle before @iter
4209 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4212 GtkTextLine *prev_line;
4213 GtkTextLine *current_line;
4214 GtkTextRealIter *real;
4216 g_return_val_if_fail (iter != NULL, FALSE);
4218 real = gtk_text_iter_make_real (iter);
4223 check_invariants (iter);
4225 current_line = real->line;
4226 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4230 /* If we're at segment start, go to the previous segment;
4231 * if mid-segment, snap to start of current segment.
4233 if (is_segment_start (real))
4235 if (!_gtk_text_iter_backward_indexable_segment (iter))
4240 ensure_char_offsets (real);
4242 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4248 /* If we went backward to a line that couldn't contain a toggle
4249 * for the tag, then skip backward further to a line that
4250 * could contain it. This potentially skips huge hunks of the
4251 * tree, so we aren't a purely linear search.
4253 if (real->line != current_line)
4255 if (prev_line == NULL)
4257 /* End of search. Set to start of buffer. */
4258 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4262 if (real->line != prev_line)
4264 /* Set to last segment in prev_line (could do this
4267 iter_set_from_byte_offset (real, prev_line, 0);
4269 while (!at_last_indexable_segment (real))
4270 _gtk_text_iter_forward_indexable_segment (iter);
4273 current_line = real->line;
4274 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4279 if (gtk_text_iter_toggles_tag (iter, tag))
4281 /* If there's a toggle here, it isn't indexable so
4282 * any_segment can't be the indexable segment.
4284 g_assert (real->any_segment != real->segment);
4288 while (_gtk_text_iter_backward_indexable_segment (iter));
4290 /* Reached front of buffer */
4295 matches_pred (GtkTextIter *iter,
4296 GtkTextCharPredicate pred,
4301 ch = gtk_text_iter_get_char (iter);
4303 return (*pred) (ch, user_data);
4307 * gtk_text_iter_forward_find_char:
4308 * @iter: a #GtkTextIter
4309 * @pred: a function to be called on each character
4310 * @user_data: user data for @pred
4311 * @limit: search limit, or %NULL for none
4313 * Advances @iter, calling @pred on each character. If
4314 * @pred returns %TRUE, returns %TRUE and stops scanning.
4315 * If @pred never returns %TRUE, @iter is set to @limit if
4316 * @limit is non-%NULL, otherwise to the end iterator.
4318 * Return value: whether a match was found
4321 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4322 GtkTextCharPredicate pred,
4324 const GtkTextIter *limit)
4326 g_return_val_if_fail (iter != NULL, FALSE);
4327 g_return_val_if_fail (pred != NULL, FALSE);
4330 gtk_text_iter_compare (iter, limit) >= 0)
4333 while ((limit == NULL ||
4334 !gtk_text_iter_equal (limit, iter)) &&
4335 gtk_text_iter_forward_char (iter))
4337 if (matches_pred (iter, pred, user_data))
4345 * gtk_text_iter_backward_find_char:
4346 * @iter: a #GtkTextIter
4347 * @pred: function to be called on each character
4348 * @user_data: user data for @pred
4349 * @limit: search limit, or %NULL for none
4351 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4353 * Return value: whether a match was found
4356 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4357 GtkTextCharPredicate pred,
4359 const GtkTextIter *limit)
4361 g_return_val_if_fail (iter != NULL, FALSE);
4362 g_return_val_if_fail (pred != NULL, FALSE);
4365 gtk_text_iter_compare (iter, limit) <= 0)
4368 while ((limit == NULL ||
4369 !gtk_text_iter_equal (limit, iter)) &&
4370 gtk_text_iter_backward_char (iter))
4372 if (matches_pred (iter, pred, user_data))
4380 forward_chars_with_skipping (GtkTextIter *iter,
4382 gboolean skip_invisible,
4383 gboolean skip_nontext)
4388 g_return_if_fail (count >= 0);
4394 gboolean ignored = FALSE;
4397 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4402 _gtk_text_btree_char_is_invisible (iter))
4405 gtk_text_iter_forward_char (iter);
4413 lines_match (const GtkTextIter *start,
4414 const gchar **lines,
4415 gboolean visible_only,
4417 GtkTextIter *match_start,
4418 GtkTextIter *match_end)
4425 if (*lines == NULL || **lines == '\0')
4428 *match_start = *start;
4431 *match_end = *start;
4436 gtk_text_iter_forward_line (&next);
4438 /* No more text in buffer, but *lines is nonempty */
4439 if (gtk_text_iter_equal (start, &next))
4447 line_text = gtk_text_iter_get_visible_slice (start, &next);
4449 line_text = gtk_text_iter_get_slice (start, &next);
4454 line_text = gtk_text_iter_get_visible_text (start, &next);
4456 line_text = gtk_text_iter_get_text (start, &next);
4459 if (match_start) /* if this is the first line we're matching */
4460 found = strstr (line_text, *lines);
4463 /* If it's not the first line, we have to match from the
4464 * start of the line.
4466 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4478 /* Get offset to start of search string */
4479 offset = g_utf8_strlen (line_text, found - line_text);
4483 /* If match start needs to be returned, set it to the
4484 * start of the search string.
4488 *match_start = next;
4490 forward_chars_with_skipping (match_start, offset,
4491 visible_only, !slice);
4494 /* Go to end of search string */
4495 offset += g_utf8_strlen (*lines, -1);
4497 forward_chars_with_skipping (&next, offset,
4498 visible_only, !slice);
4507 /* pass NULL for match_start, since we don't need to find the
4510 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4513 /* strsplit () that retains the delimiter as part of the string. */
4515 strbreakup (const char *string,
4516 const char *delimiter,
4519 GSList *string_list = NULL, *slist;
4520 gchar **str_array, *s;
4523 g_return_val_if_fail (string != NULL, NULL);
4524 g_return_val_if_fail (delimiter != NULL, NULL);
4527 max_tokens = G_MAXINT;
4529 s = strstr (string, delimiter);
4532 guint delimiter_len = strlen (delimiter);
4539 len = s - string + delimiter_len;
4540 new_string = g_new (gchar, len + 1);
4541 strncpy (new_string, string, len);
4542 new_string[len] = 0;
4543 string_list = g_slist_prepend (string_list, new_string);
4545 string = s + delimiter_len;
4546 s = strstr (string, delimiter);
4548 while (--max_tokens && s);
4553 string_list = g_slist_prepend (string_list, g_strdup (string));
4556 str_array = g_new (gchar*, n);
4560 str_array[i--] = NULL;
4561 for (slist = string_list; slist; slist = slist->next)
4562 str_array[i--] = slist->data;
4564 g_slist_free (string_list);
4570 * gtk_text_iter_forward_search:
4571 * @iter: start of search
4572 * @str: a search string
4573 * @flags: flags affecting how the search is done
4574 * @match_start: return location for start of match, or %NULL
4575 * @match_end: return location for end of match, or %NULL
4576 * @limit: bound for the search, or %NULL for the end of the buffer
4578 * Searches forward for @str. Any match is returned by setting
4579 * @match_start to the first character of the match and @match_end to the
4580 * first character after the match. The search will not continue past
4581 * @limit. Note that a search is a linear or O(n) operation, so you
4582 * may wish to use @limit to avoid locking up your UI on large
4585 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4586 * have invisible text interspersed in @str. i.e. @str will be a
4587 * possibly-noncontiguous subsequence of the matched range. similarly,
4588 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4589 * pixbufs or child widgets mixed inside the matched range. If these
4590 * flags are not given, the match must be exact; the special 0xFFFC
4591 * character in @str will match embedded pixbufs or child widgets.
4593 * Return value: whether a match was found
4596 gtk_text_iter_forward_search (const GtkTextIter *iter,
4598 GtkTextSearchFlags flags,
4599 GtkTextIter *match_start,
4600 GtkTextIter *match_end,
4601 const GtkTextIter *limit)
4603 gchar **lines = NULL;
4605 gboolean retval = FALSE;
4607 gboolean visible_only;
4610 g_return_val_if_fail (iter != NULL, FALSE);
4611 g_return_val_if_fail (str != NULL, FALSE);
4614 gtk_text_iter_compare (iter, limit) >= 0)
4619 /* If we can move one char, return the empty string there */
4622 if (gtk_text_iter_forward_char (&match))
4625 gtk_text_iter_equal (&match, limit))
4629 *match_start = match;
4638 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4639 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4641 /* locate all lines */
4643 lines = strbreakup (str, "\n", -1);
4649 /* This loop has an inefficient worst-case, where
4650 * gtk_text_iter_get_text () is called repeatedly on
4656 gtk_text_iter_compare (&search, limit) >= 0)
4659 if (lines_match (&search, (const gchar**)lines,
4660 visible_only, slice, &match, &end))
4662 if (limit == NULL ||
4664 gtk_text_iter_compare (&end, limit) <= 0))
4669 *match_start = match;
4678 while (gtk_text_iter_forward_line (&search));
4680 g_strfreev ((gchar**)lines);
4686 vectors_equal_ignoring_trailing (gchar **vec1,
4689 /* Ignores trailing chars in vec2's last line */
4698 if (strcmp (*i1, *i2) != 0)
4700 if (*(i2 + 1) == NULL) /* if this is the last line */
4702 gint len1 = strlen (*i1);
4703 gint len2 = strlen (*i2);
4706 strncmp (*i1, *i2, len1) == 0)
4708 /* We matched ignoring the trailing stuff in vec2 */
4733 typedef struct _LinesWindow LinesWindow;
4739 GtkTextIter first_line_start;
4740 GtkTextIter first_line_end;
4742 gboolean visible_only;
4746 lines_window_init (LinesWindow *win,
4747 const GtkTextIter *start)
4750 GtkTextIter line_start;
4751 GtkTextIter line_end;
4753 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4756 if (gtk_text_iter_is_start (start) ||
4757 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4759 /* Already at the end, or not enough lines to match */
4760 win->lines = g_new0 (gchar*, 1);
4765 line_start = *start;
4768 /* Move to start iter to start of line */
4769 gtk_text_iter_set_line_offset (&line_start, 0);
4771 if (gtk_text_iter_equal (&line_start, &line_end))
4773 /* we were already at the start; so go back one line */
4774 gtk_text_iter_backward_line (&line_start);
4777 win->first_line_start = line_start;
4778 win->first_line_end = line_end;
4780 win->lines = g_new0 (gchar*, win->n_lines + 1);
4782 i = win->n_lines - 1;
4789 if (win->visible_only)
4790 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4792 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4796 if (win->visible_only)
4797 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4799 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4802 win->lines[i] = line_text;
4804 line_end = line_start;
4805 gtk_text_iter_backward_line (&line_start);
4812 lines_window_back (LinesWindow *win)
4814 GtkTextIter new_start;
4817 new_start = win->first_line_start;
4819 if (!gtk_text_iter_backward_line (&new_start))
4823 win->first_line_start = new_start;
4824 win->first_line_end = new_start;
4826 gtk_text_iter_forward_line (&win->first_line_end);
4831 if (win->visible_only)
4832 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4833 &win->first_line_end);
4835 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4836 &win->first_line_end);
4840 if (win->visible_only)
4841 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4842 &win->first_line_end);
4844 line_text = gtk_text_iter_get_text (&win->first_line_start,
4845 &win->first_line_end);
4848 /* Move lines to make room for first line. */
4849 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4851 *win->lines = line_text;
4853 /* Free old last line and NULL-terminate */
4854 g_free (win->lines[win->n_lines]);
4855 win->lines[win->n_lines] = NULL;
4861 lines_window_free (LinesWindow *win)
4863 g_strfreev (win->lines);
4867 * gtk_text_iter_backward_search:
4868 * @iter: a #GtkTextIter where the search begins
4869 * @str: search string
4870 * @flags: bitmask of flags affecting the search
4871 * @match_start: return location for start of match, or %NULL
4872 * @match_end: return location for end of match, or %NULL
4873 * @limit: location of last possible @match_start, or %NULL for start of buffer
4875 * Same as gtk_text_iter_forward_search(), but moves backward.
4877 * Return value: whether a match was found
4880 gtk_text_iter_backward_search (const GtkTextIter *iter,
4882 GtkTextSearchFlags flags,
4883 GtkTextIter *match_start,
4884 GtkTextIter *match_end,
4885 const GtkTextIter *limit)
4887 gchar **lines = NULL;
4891 gboolean retval = FALSE;
4892 gboolean visible_only;
4895 g_return_val_if_fail (iter != NULL, FALSE);
4896 g_return_val_if_fail (str != NULL, FALSE);
4899 gtk_text_iter_compare (limit, iter) > 0)
4904 /* If we can move one char, return the empty string there */
4905 GtkTextIter match = *iter;
4907 if (limit && gtk_text_iter_equal (limit, &match))
4910 if (gtk_text_iter_backward_char (&match))
4913 *match_start = match;
4922 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4923 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4925 /* locate all lines */
4927 lines = strbreakup (str, "\n", -1);
4937 win.n_lines = n_lines;
4939 win.visible_only = visible_only;
4941 lines_window_init (&win, iter);
4943 if (*win.lines == NULL)
4948 gchar *first_line_match;
4951 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4953 /* We're now before the search limit, abort. */
4957 /* If there are multiple lines, the first line will
4958 * end in '\n', so this will only match at the
4959 * end of the first line, which is correct.
4961 first_line_match = g_strrstr (*win.lines, *lines);
4963 if (first_line_match &&
4964 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4969 GtkTextIter start_tmp;
4971 /* Offset to start of search string */
4972 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4974 next = win.first_line_start;
4976 forward_chars_with_skipping (&start_tmp, offset,
4977 visible_only, !slice);
4980 gtk_text_iter_compare (limit, &start_tmp) > 0)
4981 goto out; /* match was bogus */
4984 *match_start = start_tmp;
4986 /* Go to end of search string */
4990 offset += g_utf8_strlen (*l, -1);
4994 forward_chars_with_skipping (&next, offset,
4995 visible_only, !slice);
5004 while (lines_window_back (&win));
5007 lines_window_free (&win);
5018 * gtk_text_iter_equal:
5019 * @lhs: a #GtkTextIter
5020 * @rhs: another #GtkTextIter
5022 * Tests whether two iterators are equal, using the fastest possible
5023 * mechanism. This function is very fast; you can expect it to perform
5024 * better than e.g. getting the character offset for each iterator and
5025 * comparing the offsets yourself. Also, it's a bit faster than
5026 * gtk_text_iter_compare().
5028 * Return value: %TRUE if the iterators point to the same place in the buffer
5031 gtk_text_iter_equal (const GtkTextIter *lhs,
5032 const GtkTextIter *rhs)
5034 GtkTextRealIter *real_lhs;
5035 GtkTextRealIter *real_rhs;
5037 real_lhs = (GtkTextRealIter*)lhs;
5038 real_rhs = (GtkTextRealIter*)rhs;
5040 check_invariants (lhs);
5041 check_invariants (rhs);
5043 if (real_lhs->line != real_rhs->line)
5045 else if (real_lhs->line_byte_offset >= 0 &&
5046 real_rhs->line_byte_offset >= 0)
5047 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5050 /* the ensure_char_offsets () calls do nothing if the char offsets
5051 are already up-to-date. */
5052 ensure_char_offsets (real_lhs);
5053 ensure_char_offsets (real_rhs);
5054 return real_lhs->line_char_offset == real_rhs->line_char_offset;
5059 * gtk_text_iter_compare:
5060 * @lhs: a #GtkTextIter
5061 * @rhs: another #GtkTextIter
5063 * A qsort()-style function that returns negative if @lhs is less than
5064 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5065 * Ordering is in character offset order, i.e. the first character in the buffer
5066 * is less than the second character in the buffer.
5068 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5071 gtk_text_iter_compare (const GtkTextIter *lhs,
5072 const GtkTextIter *rhs)
5074 GtkTextRealIter *real_lhs;
5075 GtkTextRealIter *real_rhs;
5077 real_lhs = gtk_text_iter_make_surreal (lhs);
5078 real_rhs = gtk_text_iter_make_surreal (rhs);
5080 if (real_lhs == NULL ||
5082 return -1; /* why not */
5084 check_invariants (lhs);
5085 check_invariants (rhs);
5087 if (real_lhs->line == real_rhs->line)
5089 gint left_index, right_index;
5091 if (real_lhs->line_byte_offset >= 0 &&
5092 real_rhs->line_byte_offset >= 0)
5094 left_index = real_lhs->line_byte_offset;
5095 right_index = real_rhs->line_byte_offset;
5099 /* the ensure_char_offsets () calls do nothing if
5100 the offsets are already up-to-date. */
5101 ensure_char_offsets (real_lhs);
5102 ensure_char_offsets (real_rhs);
5103 left_index = real_lhs->line_char_offset;
5104 right_index = real_rhs->line_char_offset;
5107 if (left_index < right_index)
5109 else if (left_index > right_index)
5118 line1 = gtk_text_iter_get_line (lhs);
5119 line2 = gtk_text_iter_get_line (rhs);
5122 else if (line1 > line2)
5130 * gtk_text_iter_in_range:
5131 * @iter: a #GtkTextIter
5132 * @start: start of range
5133 * @end: end of range
5135 * Checks whether @iter falls in the range [@start, @end).
5136 * @start and @end must be in ascending order.
5138 * Return value: %TRUE if @iter is in the range
5141 gtk_text_iter_in_range (const GtkTextIter *iter,
5142 const GtkTextIter *start,
5143 const GtkTextIter *end)
5145 g_return_val_if_fail (iter != NULL, FALSE);
5146 g_return_val_if_fail (start != NULL, FALSE);
5147 g_return_val_if_fail (end != NULL, FALSE);
5148 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5150 return gtk_text_iter_compare (iter, start) >= 0 &&
5151 gtk_text_iter_compare (iter, end) < 0;
5155 * gtk_text_iter_order:
5156 * @first: a #GtkTextIter
5157 * @second: another #GtkTextIter
5159 * Swaps the value of @first and @second if @second comes before
5160 * @first in the buffer. That is, ensures that @first and @second are
5161 * in sequence. Most text buffer functions that take a range call this
5162 * automatically on your behalf, so there's no real reason to call it yourself
5163 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5164 * that expect a pre-sorted range.
5168 gtk_text_iter_order (GtkTextIter *first,
5169 GtkTextIter *second)
5171 g_return_if_fail (first != NULL);
5172 g_return_if_fail (second != NULL);
5174 if (gtk_text_iter_compare (first, second) > 0)
5185 * Init iterators from the BTree
5189 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5193 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5194 gint real_char_index;
5198 g_return_if_fail (iter != NULL);
5199 g_return_if_fail (tree != NULL);
5201 line = _gtk_text_btree_get_line_at_char (tree, char_index,
5202 &line_start, &real_char_index);
5204 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5206 real->cached_char_index = real_char_index;
5208 check_invariants (iter);
5212 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5217 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5221 g_return_if_fail (iter != NULL);
5222 g_return_if_fail (tree != NULL);
5224 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5226 iter_init_from_char_offset (iter, tree, line, char_on_line);
5228 /* We might as well cache this, since we know it. */
5229 real->cached_line_number = real_line;
5231 check_invariants (iter);
5235 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5240 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5244 g_return_if_fail (iter != NULL);
5245 g_return_if_fail (tree != NULL);
5247 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5249 iter_init_from_byte_offset (iter, tree, line, byte_index);
5251 /* We might as well cache this, since we know it. */
5252 real->cached_line_number = real_line;
5254 check_invariants (iter);
5258 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5263 g_return_if_fail (iter != NULL);
5264 g_return_if_fail (tree != NULL);
5265 g_return_if_fail (line != NULL);
5267 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5269 check_invariants (iter);
5273 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5279 g_return_val_if_fail (iter != NULL, FALSE);
5280 g_return_val_if_fail (tree != NULL, FALSE);
5282 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5286 /* Set iter to last in tree */
5287 _gtk_text_btree_get_end_iter (tree, iter);
5288 check_invariants (iter);
5293 iter_init_from_byte_offset (iter, tree, line, 0);
5295 if (!gtk_text_iter_toggles_tag (iter, tag))
5296 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5298 check_invariants (iter);
5304 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5308 g_return_val_if_fail (iter != NULL, FALSE);
5309 g_return_val_if_fail (tree != NULL, FALSE);
5311 _gtk_text_btree_get_end_iter (tree, iter);
5312 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5313 check_invariants (iter);
5319 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5321 const gchar *mark_name)
5325 g_return_val_if_fail (iter != NULL, FALSE);
5326 g_return_val_if_fail (tree != NULL, FALSE);
5328 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5334 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5335 check_invariants (iter);
5341 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5345 GtkTextLineSegment *seg;
5347 g_return_if_fail (iter != NULL);
5348 g_return_if_fail (tree != NULL);
5349 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5351 seg = mark->segment;
5353 iter_init_from_segment (iter, tree,
5354 seg->body.mark.line, seg);
5355 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5356 check_invariants (iter);
5360 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5362 GtkTextChildAnchor *anchor)
5364 GtkTextLineSegment *seg;
5366 g_return_if_fail (iter != NULL);
5367 g_return_if_fail (tree != NULL);
5368 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5370 seg = anchor->segment;
5372 g_assert (seg->body.child.line != NULL);
5374 iter_init_from_segment (iter, tree,
5375 seg->body.child.line, seg);
5376 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5377 check_invariants (iter);
5381 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5384 g_return_if_fail (iter != NULL);
5385 g_return_if_fail (tree != NULL);
5387 _gtk_text_btree_get_iter_at_char (tree,
5389 _gtk_text_btree_char_count (tree));
5390 check_invariants (iter);
5394 _gtk_text_iter_check (const GtkTextIter *iter)
5396 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5397 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5398 GtkTextLineSegment *byte_segment = NULL;
5399 GtkTextLineSegment *byte_any_segment = NULL;
5400 GtkTextLineSegment *char_segment = NULL;
5401 GtkTextLineSegment *char_any_segment = NULL;
5402 gboolean segments_updated;
5404 /* This function checks our class invariants for the Iter class. */
5406 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5408 if (real->chars_changed_stamp !=
5409 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5410 g_error ("iterator check failed: invalid iterator");
5412 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5413 g_error ("iterator check failed: both char and byte offsets are invalid");
5415 segments_updated = (real->segments_changed_stamp ==
5416 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5419 printf ("checking iter, segments %s updated, byte %d char %d\n",
5420 segments_updated ? "are" : "aren't",
5421 real->line_byte_offset,
5422 real->line_char_offset);
5425 if (segments_updated)
5427 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5428 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5430 if (real->segment->char_count == 0)
5431 g_error ("iterator check failed: segment is not indexable.");
5433 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5434 g_error ("segment char offset is not properly up-to-date");
5436 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5437 g_error ("segment byte offset is not properly up-to-date");
5439 if (real->segment_byte_offset >= 0 &&
5440 real->segment_byte_offset >= real->segment->byte_count)
5441 g_error ("segment byte offset is too large.");
5443 if (real->segment_char_offset >= 0 &&
5444 real->segment_char_offset >= real->segment->char_count)
5445 g_error ("segment char offset is too large.");
5448 if (real->line_byte_offset >= 0)
5450 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5451 &byte_segment, &byte_any_segment,
5452 &seg_byte_offset, &line_byte_offset);
5454 if (line_byte_offset != real->line_byte_offset)
5455 g_error ("wrong byte offset was stored in iterator");
5457 if (segments_updated)
5459 if (real->segment != byte_segment)
5460 g_error ("wrong segment was stored in iterator");
5462 if (real->any_segment != byte_any_segment)
5463 g_error ("wrong any_segment was stored in iterator");
5465 if (seg_byte_offset != real->segment_byte_offset)
5466 g_error ("wrong segment byte offset was stored in iterator");
5468 if (byte_segment->type == >k_text_char_type)
5471 p = byte_segment->body.chars + seg_byte_offset;
5473 if (!gtk_text_byte_begins_utf8_char (p))
5474 g_error ("broken iterator byte index pointed into the middle of a character");
5479 if (real->line_char_offset >= 0)
5481 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5482 &char_segment, &char_any_segment,
5483 &seg_char_offset, &line_char_offset);
5485 if (line_char_offset != real->line_char_offset)
5486 g_error ("wrong char offset was stored in iterator");
5488 if (segments_updated)
5490 if (real->segment != char_segment)
5491 g_error ("wrong segment was stored in iterator");
5493 if (real->any_segment != char_any_segment)
5494 g_error ("wrong any_segment was stored in iterator");
5496 if (seg_char_offset != real->segment_char_offset)
5497 g_error ("wrong segment char offset was stored in iterator");
5499 if (char_segment->type == >k_text_char_type)
5502 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5505 /* hmm, not likely to happen eh */
5506 if (!gtk_text_byte_begins_utf8_char (p))
5507 g_error ("broken iterator char offset pointed into the middle of a character");
5512 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5514 if (byte_segment != char_segment)
5515 g_error ("char and byte offsets did not point to the same segment");
5517 if (byte_any_segment != char_any_segment)
5518 g_error ("char and byte offsets did not point to the same any segment");
5520 /* Make sure the segment offsets are equivalent, if it's a char
5522 if (char_segment->type == >k_text_char_type)
5524 gint byte_offset = 0;
5525 gint char_offset = 0;
5526 while (char_offset < seg_char_offset)
5528 const char * start = char_segment->body.chars + byte_offset;
5529 byte_offset += g_utf8_next_char (start) - start;
5533 if (byte_offset != seg_byte_offset)
5534 g_error ("byte offset did not correspond to char offset");
5537 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5539 if (char_offset != seg_char_offset)
5540 g_error ("char offset did not correspond to byte offset");
5542 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5543 g_error ("byte index for iterator does not index the start of a character");
5547 if (real->cached_line_number >= 0)
5551 should_be = _gtk_text_line_get_number (real->line);
5552 if (real->cached_line_number != should_be)
5553 g_error ("wrong line number was cached");
5556 if (real->cached_char_index >= 0)
5558 if (real->line_char_offset >= 0) /* only way we can check it
5559 efficiently, not a real
5564 char_index = _gtk_text_line_char_index (real->line);
5565 char_index += real->line_char_offset;
5567 if (real->cached_char_index != char_index)
5568 g_error ("wrong char index was cached");
5572 if (_gtk_text_line_is_last (real->line, real->tree))
5573 g_error ("Iterator was on last line (past the end iterator)");
5576 #define __GTK_TEXT_ITER_C__
5577 #include "gtkaliasdef.c"