1 /* GTK - The GIMP Toolkit
2 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "gtktextiter.h"
28 #include "gtktextbtree.h"
29 #include "gtktextiterprivate.h"
34 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
36 typedef struct _GtkTextRealIter GtkTextRealIter;
38 struct _GtkTextRealIter
40 /* Always-valid information */
43 /* At least one of these is always valid;
44 if invalid, they are -1.
46 If the line byte offset is valid, so is the segment byte offset;
47 and ditto for char offsets. */
48 gint line_byte_offset;
49 gint line_char_offset;
50 /* These two are valid if >= 0 */
51 gint cached_char_index;
52 gint cached_line_number;
53 /* Stamps to detect the buffer changing under us */
54 gint chars_changed_stamp;
55 gint segments_changed_stamp;
56 /* Valid if the segments_changed_stamp is up-to-date */
57 GtkTextLineSegment *segment; /* indexable segment we index */
58 GtkTextLineSegment *any_segment; /* first segment in our location,
59 maybe same as "segment" */
60 /* One of these will always be valid if segments_changed_stamp is
61 up-to-date. If invalid, they are -1.
63 If the line byte offset is valid, so is the segment byte offset;
64 and ditto for char offsets. */
65 gint segment_byte_offset;
66 gint segment_char_offset;
69 /* These "set" functions should not assume any fields
70 other than the char stamp and the tree are valid.
73 iter_set_common (GtkTextRealIter *iter,
76 /* Update segments stamp */
77 iter->segments_changed_stamp =
78 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
82 iter->line_byte_offset = -1;
83 iter->line_char_offset = -1;
84 iter->segment_byte_offset = -1;
85 iter->segment_char_offset = -1;
86 iter->cached_char_index = -1;
87 iter->cached_line_number = -1;
91 iter_set_from_byte_offset (GtkTextRealIter *iter,
95 iter_set_common (iter, line);
97 if (!_gtk_text_line_byte_locate (iter->line,
101 &iter->segment_byte_offset,
102 &iter->line_byte_offset))
103 g_error ("Byte index %d is off the end of the line",
108 iter_set_from_char_offset (GtkTextRealIter *iter,
112 iter_set_common (iter, line);
114 if (!_gtk_text_line_char_locate (iter->line,
118 &iter->segment_char_offset,
119 &iter->line_char_offset))
120 g_error ("Char offset %d is off the end of the line",
125 iter_set_from_segment (GtkTextRealIter *iter,
127 GtkTextLineSegment *segment)
129 GtkTextLineSegment *seg;
132 /* This could theoretically be optimized by computing all the iter
133 fields in this same loop, but I'm skipping it for now. */
135 seg = line->segments;
136 while (seg != segment)
138 byte_offset += seg->byte_count;
142 iter_set_from_byte_offset (iter, line, byte_offset);
145 /* This function ensures that the segment-dependent information is
146 truly computed lazily; often we don't need to do the full make_real
147 work. This ensures the btree and line are valid, but doesn't
148 update the segments. */
149 static GtkTextRealIter*
150 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
152 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
154 if (iter->chars_changed_stamp !=
155 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
157 g_warning ("Invalid text buffer iterator: either the iterator "
158 "is uninitialized, or the characters/pixbufs/widgets "
159 "in the buffer have been modified since the iterator "
160 "was created.\nYou must use marks, character numbers, "
161 "or line numbers to preserve a position across buffer "
162 "modifications.\nYou can apply tags and insert marks "
163 "without invalidating your iterators,\n"
164 "but any mutation that affects 'indexable' buffer contents "
165 "(contents that can be referred to by character offset)\n"
166 "will invalidate all outstanding iterators");
170 /* We don't update the segments information since we are becoming
171 only surreal. However we do invalidate the segments information
172 if appropriate, to be sure we segfault if we try to use it and we
173 should have used make_real. */
175 if (iter->segments_changed_stamp !=
176 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
178 iter->segment = NULL;
179 iter->any_segment = NULL;
180 /* set to segfault-causing values. */
181 iter->segment_byte_offset = -10000;
182 iter->segment_char_offset = -10000;
188 static GtkTextRealIter*
189 gtk_text_iter_make_real (const GtkTextIter *_iter)
191 GtkTextRealIter *iter;
193 iter = gtk_text_iter_make_surreal (_iter);
195 if (iter->segments_changed_stamp !=
196 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
198 if (iter->line_byte_offset >= 0)
200 iter_set_from_byte_offset (iter,
202 iter->line_byte_offset);
206 g_assert (iter->line_char_offset >= 0);
208 iter_set_from_char_offset (iter,
210 iter->line_char_offset);
214 g_assert (iter->segment != NULL);
215 g_assert (iter->any_segment != NULL);
216 g_assert (iter->segment->char_count > 0);
221 static GtkTextRealIter*
222 iter_init_common (GtkTextIter *_iter,
225 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
227 g_return_val_if_fail (iter != NULL, NULL);
228 g_return_val_if_fail (tree != NULL, NULL);
232 iter->chars_changed_stamp =
233 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
238 static GtkTextRealIter*
239 iter_init_from_segment (GtkTextIter *iter,
242 GtkTextLineSegment *segment)
244 GtkTextRealIter *real;
246 g_return_val_if_fail (line != NULL, NULL);
248 real = iter_init_common (iter, tree);
250 iter_set_from_segment (real, line, segment);
255 static GtkTextRealIter*
256 iter_init_from_byte_offset (GtkTextIter *iter,
259 gint line_byte_offset)
261 GtkTextRealIter *real;
263 g_return_val_if_fail (line != NULL, NULL);
265 real = iter_init_common (iter, tree);
267 iter_set_from_byte_offset (real, line, line_byte_offset);
269 if (real->segment->type == >k_text_char_type &&
270 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
271 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
272 "character; this will crash the text buffer. "
273 "Byte indexes must refer to the start of a character.",
279 static GtkTextRealIter*
280 iter_init_from_char_offset (GtkTextIter *iter,
283 gint line_char_offset)
285 GtkTextRealIter *real;
287 g_return_val_if_fail (line != NULL, NULL);
289 real = iter_init_common (iter, tree);
291 iter_set_from_char_offset (real, line, line_char_offset);
297 invalidate_segment (GtkTextRealIter *iter)
299 iter->segments_changed_stamp -= 1;
303 invalidate_char_index (GtkTextRealIter *iter)
305 iter->cached_char_index = -1;
309 invalidate_line_number (GtkTextRealIter *iter)
311 iter->cached_line_number = -1;
315 adjust_char_index (GtkTextRealIter *iter, gint count)
317 if (iter->cached_char_index >= 0)
318 iter->cached_char_index += count;
322 adjust_line_number (GtkTextRealIter *iter, gint count)
324 if (iter->cached_line_number >= 0)
325 iter->cached_line_number += count;
329 adjust_char_offsets (GtkTextRealIter *iter, gint count)
331 if (iter->line_char_offset >= 0)
333 iter->line_char_offset += count;
334 g_assert (iter->segment_char_offset >= 0);
335 iter->segment_char_offset += count;
340 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
342 if (iter->line_byte_offset >= 0)
344 iter->line_byte_offset += count;
345 g_assert (iter->segment_byte_offset >= 0);
346 iter->segment_byte_offset += count;
351 ensure_char_offsets (GtkTextRealIter *iter)
353 if (iter->line_char_offset < 0)
355 g_assert (iter->line_byte_offset >= 0);
357 _gtk_text_line_byte_to_char_offsets (iter->line,
358 iter->line_byte_offset,
359 &iter->line_char_offset,
360 &iter->segment_char_offset);
365 ensure_byte_offsets (GtkTextRealIter *iter)
367 if (iter->line_byte_offset < 0)
369 g_assert (iter->line_char_offset >= 0);
371 _gtk_text_line_char_to_byte_offsets (iter->line,
372 iter->line_char_offset,
373 &iter->line_byte_offset,
374 &iter->segment_byte_offset);
378 static inline gboolean
379 is_segment_start (GtkTextRealIter *real)
381 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
386 check_invariants (const GtkTextIter *iter)
388 if (gtk_debug_flags & GTK_DEBUG_TEXT)
389 _gtk_text_iter_check (iter);
392 #define check_invariants (x)
396 * gtk_text_iter_get_buffer:
399 * Return the #GtkTextBuffer this iterator is associated with
401 * Return value: the buffer
404 gtk_text_iter_get_buffer (const GtkTextIter *iter)
406 GtkTextRealIter *real;
408 g_return_val_if_fail (iter != NULL, NULL);
410 real = gtk_text_iter_make_surreal (iter);
415 check_invariants (iter);
417 return _gtk_text_btree_get_buffer (real->tree);
421 * gtk_text_iter_copy:
424 * Create a dynamically-allocated copy of an iterator. This function
425 * is not useful in applications, because iterators can be copied with a
426 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
427 * function is used by language bindings.
429 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
432 gtk_text_iter_copy (const GtkTextIter *iter)
434 GtkTextIter *new_iter;
436 g_return_val_if_fail (iter != NULL, NULL);
438 new_iter = g_new (GtkTextIter, 1);
446 * gtk_text_iter_free:
447 * @iter: a dynamically-allocated iterator
449 * Free an iterator allocated on the heap. This function
450 * is intended for use in language bindings, and is not
451 * especially useful for applications, because iterators can
452 * simply be allocated on the stack.
456 gtk_text_iter_free (GtkTextIter *iter)
458 g_return_if_fail (iter != NULL);
464 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
466 GtkTextRealIter *real;
468 g_return_val_if_fail (iter != NULL, 0);
470 real = gtk_text_iter_make_real (iter);
475 check_invariants (iter);
477 g_assert (real->segment != NULL);
479 return real->segment;
483 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
485 GtkTextRealIter *real;
487 g_return_val_if_fail (iter != NULL, 0);
489 real = gtk_text_iter_make_real (iter);
494 check_invariants (iter);
496 g_assert (real->any_segment != NULL);
498 return real->any_segment;
502 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
504 GtkTextRealIter *real;
506 g_return_val_if_fail (iter != NULL, 0);
508 real = gtk_text_iter_make_real (iter);
513 ensure_byte_offsets (real);
515 check_invariants (iter);
517 return real->segment_byte_offset;
521 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
523 GtkTextRealIter *real;
525 g_return_val_if_fail (iter != NULL, 0);
527 real = gtk_text_iter_make_real (iter);
532 ensure_char_offsets (real);
534 check_invariants (iter);
536 return real->segment_char_offset;
539 /* This function does not require a still-valid
542 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
544 const GtkTextRealIter *real;
546 g_return_val_if_fail (iter != NULL, 0);
548 real = (const GtkTextRealIter*)iter;
553 /* This function does not require a still-valid
556 _gtk_text_iter_get_btree (const GtkTextIter *iter)
558 const GtkTextRealIter *real;
560 g_return_val_if_fail (iter != NULL, 0);
562 real = (const GtkTextRealIter*)iter;
572 * gtk_text_iter_get_offset:
575 * Returns the character offset of an iterator.
576 * Each character in a #GtkTextBuffer has an offset,
577 * starting with 0 for the first character in the buffer.
578 * Use gtk_text_buffer_get_iter_at_offset () to convert an
579 * offset back into an iterator.
581 * Return value: a character offset
584 gtk_text_iter_get_offset (const GtkTextIter *iter)
586 GtkTextRealIter *real;
588 g_return_val_if_fail (iter != NULL, 0);
590 real = gtk_text_iter_make_surreal (iter);
595 check_invariants (iter);
597 if (real->cached_char_index < 0)
599 ensure_char_offsets (real);
601 real->cached_char_index =
602 _gtk_text_line_char_index (real->line);
603 real->cached_char_index += real->line_char_offset;
606 check_invariants (iter);
608 return real->cached_char_index;
612 * gtk_text_iter_get_line:
615 * Returns the line number containing the iterator. Lines in
616 * a #GtkTextBuffer are numbered beginning with 0 for the first
617 * line in the buffer.
619 * Return value: a line number
622 gtk_text_iter_get_line (const GtkTextIter *iter)
624 GtkTextRealIter *real;
626 g_return_val_if_fail (iter != NULL, 0);
628 real = gtk_text_iter_make_surreal (iter);
633 if (real->cached_line_number < 0)
634 real->cached_line_number =
635 _gtk_text_line_get_number (real->line);
637 check_invariants (iter);
639 return real->cached_line_number;
643 * gtk_text_iter_get_line_offset:
646 * Returns the character offset of the iterator,
647 * counting from the start of a newline-terminated line.
648 * The first character on the line has offset 0.
650 * Return value: offset from start of line
653 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
655 GtkTextRealIter *real;
657 g_return_val_if_fail (iter != NULL, 0);
659 real = gtk_text_iter_make_surreal (iter);
664 ensure_char_offsets (real);
666 check_invariants (iter);
668 return real->line_char_offset;
672 * gtk_text_iter_get_line_index:
675 * Returns the byte index of the iterator, counting
676 * from the start of a newline-terminated line.
677 * Remember that #GtkTextBuffer encodes text in
678 * UTF-8, and that characters can require a variable
679 * number of bytes to represent.
681 * Return value: distance from start of line, in bytes
684 gtk_text_iter_get_line_index (const GtkTextIter *iter)
686 GtkTextRealIter *real;
688 g_return_val_if_fail (iter != NULL, 0);
690 real = gtk_text_iter_make_surreal (iter);
695 ensure_byte_offsets (real);
697 check_invariants (iter);
699 return real->line_byte_offset;
703 * gtk_text_iter_get_visible_line_offset:
704 * @iter: a #GtkTextIter
706 * Returns the offset in characters from the start of the
707 * line to the given @iter, not counting characters that
708 * are invisible due to tags with the "invisible" flag
711 * Return value: offset in visible characters from the start of the line
714 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
716 GtkTextRealIter *real;
718 GtkTextLineSegment *seg;
721 g_return_val_if_fail (iter != NULL, 0);
723 real = gtk_text_iter_make_real (iter);
728 ensure_char_offsets (real);
730 check_invariants (iter);
732 vis_offset = real->line_char_offset;
734 _gtk_text_btree_get_iter_at_line (real->tree,
739 seg = _gtk_text_iter_get_indexable_segment (&pos);
741 while (seg != real->segment)
743 /* This is a pretty expensive call, making the
744 * whole function pretty lame; we could keep track
745 * of current invisibility state by looking at toggle
746 * segments as we loop, and then call this function
747 * only once per line, in order to speed up the loop
750 if (_gtk_text_btree_char_is_invisible (&pos))
751 vis_offset -= seg->char_count;
753 _gtk_text_iter_forward_indexable_segment (&pos);
755 seg = _gtk_text_iter_get_indexable_segment (&pos);
758 if (_gtk_text_btree_char_is_invisible (&pos))
759 vis_offset -= real->segment_char_offset;
766 * gtk_text_iter_get_visible_line_index:
767 * @iter: a #GtkTextIter
769 * Returns the number of bytes from the start of the
770 * line to the given @iter, not counting bytes that
771 * are invisible due to tags with the "invisible" flag
774 * Return value: byte index of @iter with respect to the start of the line
777 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
779 GtkTextRealIter *real;
781 GtkTextLineSegment *seg;
784 g_return_val_if_fail (iter != NULL, 0);
786 real = gtk_text_iter_make_real (iter);
791 ensure_char_offsets (real);
793 check_invariants (iter);
795 vis_offset = real->line_byte_offset;
797 _gtk_text_btree_get_iter_at_line (real->tree,
802 seg = _gtk_text_iter_get_indexable_segment (&pos);
804 while (seg != real->segment)
806 /* This is a pretty expensive call, making the
807 * whole function pretty lame; we could keep track
808 * of current invisibility state by looking at toggle
809 * segments as we loop, and then call this function
810 * only once per line, in order to speed up the loop
813 if (_gtk_text_btree_char_is_invisible (&pos))
814 vis_offset -= seg->byte_count;
816 _gtk_text_iter_forward_indexable_segment (&pos);
818 seg = _gtk_text_iter_get_indexable_segment (&pos);
821 if (_gtk_text_btree_char_is_invisible (&pos))
822 vis_offset -= real->segment_byte_offset;
832 * gtk_text_iter_get_char:
835 * Returns the Unicode character at this iterator. (Equivalent to
836 * operator* on a C++ iterator.) If the iterator points at a
837 * non-character element, such as an image embedded in the buffer, the
838 * Unicode "unknown" character 0xFFFC is returned. If invoked on
839 * the end iterator, zero is returned; zero is not a valid Unicode character.
840 * So you can write a loop which ends when gtk_text_iter_get_char ()
843 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
846 gtk_text_iter_get_char (const GtkTextIter *iter)
848 GtkTextRealIter *real;
850 g_return_val_if_fail (iter != NULL, 0);
852 real = gtk_text_iter_make_real (iter);
857 check_invariants (iter);
859 if (gtk_text_iter_is_end (iter))
861 else if (real->segment->type == >k_text_char_type)
863 ensure_byte_offsets (real);
865 return g_utf8_get_char (real->segment->body.chars +
866 real->segment_byte_offset);
870 /* Unicode "unknown character" 0xFFFC */
871 return GTK_TEXT_UNKNOWN_CHAR;
876 * gtk_text_iter_get_slice:
877 * @start: iterator at start of a range
878 * @end: iterator at end of a range
880 * Returns the text in the given range. A "slice" is an array of
881 * characters encoded in UTF-8 format, including the Unicode "unknown"
882 * character 0xFFFC for iterable non-character elements in the buffer,
883 * such as images. Because images are encoded in the slice, byte and
884 * character offsets in the returned array will correspond to byte
885 * offsets in the text buffer. Note that 0xFFFC can occur in normal
886 * text as well, so it is not a reliable indicator that a pixbuf or
887 * widget is in the buffer.
889 * Return value: slice of text from the buffer
892 gtk_text_iter_get_slice (const GtkTextIter *start,
893 const GtkTextIter *end)
895 g_return_val_if_fail (start != NULL, NULL);
896 g_return_val_if_fail (end != NULL, NULL);
898 check_invariants (start);
899 check_invariants (end);
901 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
905 * gtk_text_iter_get_text:
906 * @start: iterator at start of a range
907 * @end: iterator at end of a range
909 * Returns <emphasis>text</emphasis> in the given range. If the range
910 * contains non-text elements such as images, the character and byte
911 * offsets in the returned string will not correspond to character and
912 * byte offsets in the buffer. If you want offsets to correspond, see
913 * gtk_text_iter_get_slice ().
915 * Return value: array of characters from the buffer
918 gtk_text_iter_get_text (const GtkTextIter *start,
919 const GtkTextIter *end)
921 g_return_val_if_fail (start != NULL, NULL);
922 g_return_val_if_fail (end != NULL, NULL);
924 check_invariants (start);
925 check_invariants (end);
927 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
931 * gtk_text_iter_get_visible_slice:
932 * @start: iterator at start of range
933 * @end: iterator at end of range
935 * Like gtk_text_iter_get_slice (), but invisible text is not included.
936 * Invisible text is usually invisible because a #GtkTextTag with the
937 * "invisible" attribute turned on has been applied to it.
939 * Return value: slice of text from the buffer
942 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
943 const GtkTextIter *end)
945 g_return_val_if_fail (start != NULL, NULL);
946 g_return_val_if_fail (end != NULL, NULL);
948 check_invariants (start);
949 check_invariants (end);
951 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
955 * gtk_text_iter_get_visible_text:
956 * @start: iterator at start of range
957 * @end: iterator at end of range
959 * Like gtk_text_iter_get_text (), but invisible text is not included.
960 * Invisible text is usually invisible because a #GtkTextTag with the
961 * "invisible" attribute turned on has been applied to it.
963 * Return value: string containing visible text in the range
966 gtk_text_iter_get_visible_text (const GtkTextIter *start,
967 const GtkTextIter *end)
969 g_return_val_if_fail (start != NULL, NULL);
970 g_return_val_if_fail (end != NULL, NULL);
972 check_invariants (start);
973 check_invariants (end);
975 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
979 * gtk_text_iter_get_pixbuf:
982 * If the location pointed to by @iter contains a pixbuf, the pixbuf
983 * is returned (with no new reference count added). Otherwise,
986 * Return value: the pixbuf at @iter
989 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
991 GtkTextRealIter *real;
993 g_return_val_if_fail (iter != NULL, NULL);
995 real = gtk_text_iter_make_real (iter);
1000 check_invariants (iter);
1002 if (real->segment->type != >k_text_pixbuf_type)
1005 return real->segment->body.pixbuf.pixbuf;
1009 * gtk_text_iter_get_child_anchor:
1010 * @iter: an iterator
1012 * If the location pointed to by @iter contains a child anchor, the
1013 * anchor is returned (with no new reference count added). Otherwise,
1016 * Return value: the anchor at @iter
1019 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1021 GtkTextRealIter *real;
1023 g_return_val_if_fail (iter != NULL, NULL);
1025 real = gtk_text_iter_make_real (iter);
1030 check_invariants (iter);
1032 if (real->segment->type != >k_text_child_type)
1035 return real->segment->body.child.obj;
1039 * gtk_text_iter_get_marks:
1040 * @iter: an iterator
1042 * Returns a list of all #GtkTextMark at this location. Because marks
1043 * are not iterable (they don't take up any "space" in the buffer,
1044 * they are just marks in between iterable locations), multiple marks
1045 * can exist in the same place. The returned list is not in any
1048 * Return value: list of #GtkTextMark
1051 gtk_text_iter_get_marks (const GtkTextIter *iter)
1053 GtkTextRealIter *real;
1054 GtkTextLineSegment *seg;
1057 g_return_val_if_fail (iter != NULL, NULL);
1059 real = gtk_text_iter_make_real (iter);
1064 check_invariants (iter);
1067 seg = real->any_segment;
1068 while (seg != real->segment)
1070 if (seg->type == >k_text_left_mark_type ||
1071 seg->type == >k_text_right_mark_type)
1072 retval = g_slist_prepend (retval, seg->body.mark.obj);
1077 /* The returned list isn't guaranteed to be in any special order,
1083 * gtk_text_iter_get_toggled_tags:
1084 * @iter: an iterator
1085 * @toggled_on: TRUE to get toggled-on tags
1087 * Returns a list of #GtkTextTag that are toggled on or off at this
1088 * point. (If @toggled_on is TRUE, the list contains tags that are
1089 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1090 * range of characters following @iter has that tag applied to it. If
1091 * a tag is toggled off, then some non-empty range following @iter
1092 * does <emphasis>not</emphasis> have the tag applied to it.
1094 * Return value: tags toggled at this point
1097 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1098 gboolean toggled_on)
1100 GtkTextRealIter *real;
1101 GtkTextLineSegment *seg;
1104 g_return_val_if_fail (iter != NULL, NULL);
1106 real = gtk_text_iter_make_real (iter);
1111 check_invariants (iter);
1114 seg = real->any_segment;
1115 while (seg != real->segment)
1119 if (seg->type == >k_text_toggle_on_type)
1121 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1126 if (seg->type == >k_text_toggle_off_type)
1128 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1135 /* The returned list isn't guaranteed to be in any special order,
1141 * gtk_text_iter_begins_tag:
1142 * @iter: an iterator
1143 * @tag: a #GtkTextTag, or NULL
1145 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
1146 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1147 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1148 * <emphasis>start</emphasis> of the tagged range;
1149 * gtk_text_iter_has_tag () tells you whether an iterator is
1150 * <emphasis>within</emphasis> a tagged range.
1152 * Return value: whether @iter is the start of a range tagged with @tag
1155 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1158 GtkTextRealIter *real;
1159 GtkTextLineSegment *seg;
1161 g_return_val_if_fail (iter != NULL, FALSE);
1163 real = gtk_text_iter_make_real (iter);
1168 check_invariants (iter);
1170 seg = real->any_segment;
1171 while (seg != real->segment)
1173 if (seg->type == >k_text_toggle_on_type)
1176 seg->body.toggle.info->tag == tag)
1187 * gtk_text_iter_ends_tag:
1188 * @iter: an iterator
1189 * @tag: a #GtkTextTag, or NULL
1191 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1192 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1193 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1194 * <emphasis>end</emphasis> of the tagged range;
1195 * gtk_text_iter_has_tag () tells you whether an iterator is
1196 * <emphasis>within</emphasis> a tagged range.
1198 * Return value: whether @iter is the end of a range tagged with @tag
1202 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1205 GtkTextRealIter *real;
1206 GtkTextLineSegment *seg;
1208 g_return_val_if_fail (iter != NULL, FALSE);
1210 real = gtk_text_iter_make_real (iter);
1215 check_invariants (iter);
1217 seg = real->any_segment;
1218 while (seg != real->segment)
1220 if (seg->type == >k_text_toggle_off_type)
1223 seg->body.toggle.info->tag == tag)
1234 * gtk_text_iter_toggles_tag:
1235 * @iter: an iterator
1236 * @tag: a #GtkTextTag, or NULL
1238 * This is equivalent to (gtk_text_iter_begins_tag () ||
1239 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1240 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1242 * Return value: whether @tag is toggled on or off at @iter
1245 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1248 GtkTextRealIter *real;
1249 GtkTextLineSegment *seg;
1251 g_return_val_if_fail (iter != NULL, FALSE);
1253 real = gtk_text_iter_make_real (iter);
1258 check_invariants (iter);
1260 seg = real->any_segment;
1261 while (seg != real->segment)
1263 if ( (seg->type == >k_text_toggle_off_type ||
1264 seg->type == >k_text_toggle_on_type) &&
1266 seg->body.toggle.info->tag == tag) )
1276 * gtk_text_iter_has_tag:
1277 * @iter: an iterator
1278 * @tag: a #GtkTextTag
1280 * Returns TRUE if @iter is within a range tagged with @tag.
1282 * Return value: whether @iter is tagged with @tag
1285 gtk_text_iter_has_tag (const GtkTextIter *iter,
1288 GtkTextRealIter *real;
1290 g_return_val_if_fail (iter != NULL, FALSE);
1291 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1293 real = gtk_text_iter_make_surreal (iter);
1298 check_invariants (iter);
1300 if (real->line_byte_offset >= 0)
1302 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1303 real->line_byte_offset, tag);
1307 g_assert (real->line_char_offset >= 0);
1308 return _gtk_text_line_char_has_tag (real->line, real->tree,
1309 real->line_char_offset, tag);
1314 * gtk_text_iter_get_tags:
1315 * @iter: a #GtkTextIter
1317 * Returns a list of tags that apply to @iter, in ascending order of
1318 * priority (highest-priority tags are last). The #GtkTextTag in the
1319 * list don't have a reference added, but you have to free the list
1322 * Return value: list of #GtkTextTag
1325 gtk_text_iter_get_tags (const GtkTextIter *iter)
1332 g_return_val_if_fail (iter != NULL, NULL);
1334 /* Get the tags at this spot */
1335 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1337 /* No tags, use default style */
1338 if (tags == NULL || tag_count == 0)
1346 /* Sort tags in ascending order of priority */
1347 _gtk_text_tag_array_sort (tags, tag_count);
1351 while (i < tag_count)
1353 retval = g_slist_prepend (retval, tags[i]);
1359 /* Return tags in ascending order of priority */
1360 return g_slist_reverse (retval);
1364 * gtk_text_iter_editable:
1365 * @iter: an iterator
1366 * @default_setting: %TRUE if text is editable by default
1368 * Returns whether the character at @iter is within an editable region
1369 * of text. Non-editable text is "locked" and can't be changed by the
1370 * user via #GtkTextView. This function is simply a convenience
1371 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1372 * to this text affect editability, @default_setting will be returned.
1374 * You don't want to use this function to decide whether text can be
1375 * inserted at @iter, because for insertion you don't want to know
1376 * whether the char at @iter is inside an editable range, you want to
1377 * know whether a new character inserted at @iter would be inside an
1378 * editable range. Use gtk_text_iter_can_insert() to handle this
1381 * Return value: whether @iter is inside an editable range
1384 gtk_text_iter_editable (const GtkTextIter *iter,
1385 gboolean default_setting)
1387 GtkTextAttributes *values;
1390 g_return_val_if_fail (iter != NULL, FALSE);
1392 values = gtk_text_attributes_new ();
1394 values->editable = default_setting;
1396 gtk_text_iter_get_attributes (iter, values);
1398 retval = values->editable;
1400 gtk_text_attributes_unref (values);
1406 * gtk_text_iter_can_insert:
1407 * @iter: an iterator
1408 * @default_editability: %TRUE if text is editable by default
1410 * Considering the default editability of the buffer, and tags that
1411 * affect editability, determines whether text inserted at @iter would
1412 * be editable. If text inserted at @iter would be editable then the
1413 * user should be allowed to insert text at @iter.
1414 * gtk_text_buffer_insert_interactive() uses this function to decide
1415 * whether insertions are allowed at a given position.
1417 * Return value: whether text inserted at @iter would be editable
1420 gtk_text_iter_can_insert (const GtkTextIter *iter,
1421 gboolean default_editability)
1423 g_return_val_if_fail (iter != NULL, FALSE);
1425 if (gtk_text_iter_editable (iter, default_editability))
1427 /* If at start/end of buffer, default editability is used */
1428 else if ((gtk_text_iter_is_start (iter) ||
1429 gtk_text_iter_is_end (iter)) &&
1430 default_editability)
1434 /* if iter isn't editable, and the char before iter is,
1435 * then iter is the first char in an editable region
1436 * and thus insertion at iter results in editable text.
1438 GtkTextIter prev = *iter;
1439 gtk_text_iter_backward_char (&prev);
1440 return gtk_text_iter_editable (&prev, default_editability);
1446 * gtk_text_iter_get_language:
1447 * @iter: an iterator
1449 * A convenience wrapper around gtk_text_iter_get_attributes (),
1450 * which returns the language in effect at @iter. If no tags affecting
1451 * language * apply to @iter, the return value is identical to that of
1452 * gtk_get_default_language ().
1454 * Return value: language in effect at @iter
1457 gtk_text_iter_get_language (const GtkTextIter *iter)
1459 GtkTextAttributes *values;
1460 PangoLanguage *retval;
1462 values = gtk_text_attributes_new ();
1464 gtk_text_iter_get_attributes (iter, values);
1466 retval = values->language;
1468 gtk_text_attributes_unref (values);
1474 * gtk_text_iter_starts_line:
1475 * @iter: an iterator
1477 * Returns TRUE if @iter begins a paragraph,
1478 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1479 * However this function is potentially more efficient than
1480 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1481 * the offset, it just has to see whether it's 0.
1483 * Return value: whether @iter begins a line
1486 gtk_text_iter_starts_line (const GtkTextIter *iter)
1488 GtkTextRealIter *real;
1490 g_return_val_if_fail (iter != NULL, FALSE);
1492 real = gtk_text_iter_make_surreal (iter);
1497 check_invariants (iter);
1499 if (real->line_byte_offset >= 0)
1501 return (real->line_byte_offset == 0);
1505 g_assert (real->line_char_offset >= 0);
1506 return (real->line_char_offset == 0);
1511 * gtk_text_iter_ends_line:
1512 * @iter: an iterator
1514 * Returns TRUE if @iter points to the start of the paragraph delimiter
1515 * characters for a line (delimiters will be either a newline, a
1516 * carriage return, a carriage return followed by a newline, or a
1517 * Unicode paragraph separator character). Note that an iterator pointing
1518 * to the \n of a \r\n pair will not be counted as the end of a line,
1519 * the line ends before the \r.
1521 * Return value: whether @iter is at the end of a line
1524 gtk_text_iter_ends_line (const GtkTextIter *iter)
1526 GtkTextRealIter *real;
1529 g_return_val_if_fail (iter != NULL, FALSE);
1531 real = gtk_text_iter_make_real (iter);
1533 check_invariants (iter);
1535 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1536 * Unicode 3.0; update this if that changes.
1538 #define PARAGRAPH_SEPARATOR 0x2029
1540 wc = gtk_text_iter_get_char (iter);
1542 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1544 else if (wc == '\n')
1546 /* need to determine if a \r precedes the \n, in which case
1547 * we aren't the end of the line
1549 GtkTextIter tmp = *iter;
1550 if (!gtk_text_iter_backward_char (&tmp))
1553 return gtk_text_iter_get_char (&tmp) != '\r';
1560 * gtk_text_iter_is_end:
1561 * @iter: an iterator
1563 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1564 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1565 * the most efficient way to check whether an iterator is the end
1568 * Return value: whether @iter is the end iterator
1571 gtk_text_iter_is_end (const GtkTextIter *iter)
1573 GtkTextRealIter *real;
1575 g_return_val_if_fail (iter != NULL, FALSE);
1577 real = gtk_text_iter_make_surreal (iter);
1582 check_invariants (iter);
1584 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1587 /* Now we need the segments validated */
1588 real = gtk_text_iter_make_real (iter);
1593 return _gtk_text_btree_is_end (real->tree, real->line,
1595 real->segment_byte_offset,
1596 real->segment_char_offset);
1600 * gtk_text_iter_is_start:
1601 * @iter: an iterator
1603 * Returns TRUE if @iter is the first iterator in the buffer, that is
1604 * if @iter has a character offset of 0.
1606 * Return value: whether @iter is the first in the buffer
1609 gtk_text_iter_is_start (const GtkTextIter *iter)
1611 return gtk_text_iter_get_offset (iter) == 0;
1615 * gtk_text_iter_get_chars_in_line:
1616 * @iter: an iterator
1618 * Returns the number of characters in the line containing @iter,
1619 * including the paragraph delimiters.
1621 * Return value: number of characters in the line
1624 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1626 GtkTextRealIter *real;
1628 GtkTextLineSegment *seg;
1630 g_return_val_if_fail (iter != NULL, FALSE);
1632 real = gtk_text_iter_make_surreal (iter);
1637 check_invariants (iter);
1639 if (real->line_char_offset >= 0)
1641 /* We can start at the segments we've already found. */
1642 count = real->line_char_offset - real->segment_char_offset;
1643 seg = _gtk_text_iter_get_indexable_segment (iter);
1647 /* count whole line. */
1648 seg = real->line->segments;
1655 count += seg->char_count;
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, FALSE);
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;
1712 * gtk_text_iter_get_attributes:
1713 * @iter: an iterator
1714 * @values: a #GtkTextAttributes to be filled in
1716 * Computes the effect of any tags applied to this spot in the
1717 * text. The @values parameter should be initialized to the default
1718 * settings you wish to use if no tags are in effect. You'd typically
1719 * obtain the defaults from gtk_text_view_get_default_attributes().
1721 * gtk_text_iter_get_attributes () will modify @values, applying the
1722 * effects of any tags present at @iter. If any tags affected @values,
1723 * the function returns %TRUE.
1725 * Return value: %TRUE if @values was modified
1728 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1729 GtkTextAttributes *values)
1734 /* Get the tags at this spot */
1735 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1737 /* No tags, use default style */
1738 if (tags == NULL || tag_count == 0)
1746 /* Sort tags in ascending order of priority */
1747 _gtk_text_tag_array_sort (tags, tag_count);
1749 _gtk_text_attributes_fill_from_tags (values,
1759 * Increments/decrements
1762 /* The return value of this indicates WHETHER WE MOVED.
1763 * The return value of public functions indicates
1764 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1766 * This function will not change the iterator if
1767 * it's already on the last (end iter) line, i.e. it
1768 * won't move to the end of the last line.
1771 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1773 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1775 GtkTextLine *new_line;
1777 new_line = _gtk_text_line_next (real->line);
1778 g_assert (new_line);
1779 g_assert (new_line != real->line);
1780 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1782 real->line = new_line;
1784 real->line_byte_offset = 0;
1785 real->line_char_offset = 0;
1787 real->segment_byte_offset = 0;
1788 real->segment_char_offset = 0;
1790 /* Find first segments in new line */
1791 real->any_segment = real->line->segments;
1792 real->segment = real->any_segment;
1793 while (real->segment->char_count == 0)
1794 real->segment = real->segment->next;
1800 /* There is no way to move forward a line; we were already at
1801 * the line containing the end iterator.
1802 * However we may not be at the end iterator itself.
1810 /* The return value of this indicates WHETHER WE MOVED.
1811 * The return value of public functions indicates
1812 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1815 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1817 GtkTextLine *new_line;
1819 new_line = _gtk_text_line_previous (real->line);
1821 g_assert (new_line != real->line);
1823 if (new_line != NULL)
1825 real->line = new_line;
1827 real->line_byte_offset = 0;
1828 real->line_char_offset = 0;
1830 real->segment_byte_offset = 0;
1831 real->segment_char_offset = 0;
1833 /* Find first segments in new line */
1834 real->any_segment = real->line->segments;
1835 real->segment = real->any_segment;
1836 while (real->segment->char_count == 0)
1837 real->segment = real->segment->next;
1843 /* There is no way to move backward; we were already
1844 at the first line. */
1846 /* We leave real->line as-is */
1848 /* Note that we didn't clamp to the start of the first line. */
1854 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1858 forward_char (GtkTextRealIter *real)
1860 GtkTextIter *iter = (GtkTextIter*)real;
1862 check_invariants ((GtkTextIter*)real);
1864 ensure_char_offsets (real);
1866 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1868 /* Need to move to the next segment; if no next segment,
1869 need to move to next line. */
1870 return _gtk_text_iter_forward_indexable_segment (iter);
1874 /* Just moving within a segment. Keep byte count
1875 up-to-date, if it was already up-to-date. */
1877 g_assert (real->segment->type == >k_text_char_type);
1879 if (real->line_byte_offset >= 0)
1882 const char * start =
1883 real->segment->body.chars + real->segment_byte_offset;
1885 bytes = g_utf8_next_char (start) - start;
1887 real->line_byte_offset += bytes;
1888 real->segment_byte_offset += bytes;
1890 g_assert (real->segment_byte_offset < real->segment->byte_count);
1893 real->line_char_offset += 1;
1894 real->segment_char_offset += 1;
1896 adjust_char_index (real, 1);
1898 g_assert (real->segment_char_offset < real->segment->char_count);
1900 /* We moved into the middle of a segment, so the any_segment
1901 must now be the segment we're in the middle of. */
1902 real->any_segment = real->segment;
1904 check_invariants ((GtkTextIter*)real);
1906 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1914 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1916 /* Need to move to the next segment; if no next segment,
1917 need to move to next line. */
1918 GtkTextLineSegment *seg;
1919 GtkTextLineSegment *any_seg;
1920 GtkTextRealIter *real;
1924 g_return_val_if_fail (iter != NULL, FALSE);
1926 real = gtk_text_iter_make_real (iter);
1931 check_invariants (iter);
1933 if (real->line_char_offset >= 0)
1935 chars_skipped = real->segment->char_count - real->segment_char_offset;
1936 g_assert (chars_skipped > 0);
1941 if (real->line_byte_offset >= 0)
1943 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1944 g_assert (bytes_skipped > 0);
1949 /* Get first segment of any kind */
1950 any_seg = real->segment->next;
1951 /* skip non-indexable segments, if any */
1953 while (seg != NULL && seg->char_count == 0)
1958 real->any_segment = any_seg;
1959 real->segment = seg;
1961 if (real->line_byte_offset >= 0)
1963 g_assert (bytes_skipped > 0);
1964 real->segment_byte_offset = 0;
1965 real->line_byte_offset += bytes_skipped;
1968 if (real->line_char_offset >= 0)
1970 g_assert (chars_skipped > 0);
1971 real->segment_char_offset = 0;
1972 real->line_char_offset += chars_skipped;
1973 adjust_char_index (real, chars_skipped);
1976 check_invariants (iter);
1982 /* End of the line */
1983 if (forward_line_leaving_caches_unmodified (real))
1985 adjust_line_number (real, 1);
1986 if (real->line_char_offset >= 0)
1987 adjust_char_index (real, chars_skipped);
1989 g_assert (real->line_byte_offset == 0);
1990 g_assert (real->line_char_offset == 0);
1991 g_assert (real->segment_byte_offset == 0);
1992 g_assert (real->segment_char_offset == 0);
1993 g_assert (gtk_text_iter_starts_line (iter));
1995 check_invariants (iter);
1997 if (gtk_text_iter_is_end (iter))
2006 g_assert (gtk_text_iter_is_end (iter));
2008 check_invariants (iter);
2016 at_last_indexable_segment (GtkTextRealIter *real)
2018 GtkTextLineSegment *seg;
2020 /* Return TRUE if there are no indexable segments after
2024 seg = real->segment->next;
2027 if (seg->char_count > 0)
2034 /* Goes back to the start of the next segment, even if
2035 * we're not at the start of the current segment (always
2036 * ends up on a different segment if it returns TRUE)
2039 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2041 /* Move to the start of the previous segment; if no previous
2042 * segment, to the last segment in the previous line. This is
2043 * inherently a bit inefficient due to the singly-linked list and
2044 * tree nodes, but we can't afford the RAM for doubly-linked.
2046 GtkTextRealIter *real;
2047 GtkTextLineSegment *seg;
2048 GtkTextLineSegment *any_seg;
2049 GtkTextLineSegment *prev_seg;
2050 GtkTextLineSegment *prev_any_seg;
2054 g_return_val_if_fail (iter != NULL, FALSE);
2056 real = gtk_text_iter_make_real (iter);
2061 check_invariants (iter);
2063 /* Find first segments in line */
2064 any_seg = real->line->segments;
2066 while (seg->char_count == 0)
2069 if (seg == real->segment)
2071 /* Could probably do this case faster by hand-coding the
2075 /* We were already at the start of a line;
2076 * go back to the previous line.
2078 if (gtk_text_iter_backward_line (iter))
2080 /* Go forward to last indexable segment in line. */
2081 while (!at_last_indexable_segment (real))
2082 _gtk_text_iter_forward_indexable_segment (iter);
2084 check_invariants (iter);
2089 return FALSE; /* We were at the start of the first line. */
2092 /* We must be in the middle of a line; so find the indexable
2093 * segment just before our current segment.
2095 g_assert (seg != real->segment);
2096 while (seg != real->segment)
2099 prev_any_seg = any_seg;
2101 any_seg = seg->next;
2103 while (seg->char_count == 0)
2107 g_assert (prev_seg != NULL);
2108 g_assert (prev_any_seg != NULL);
2109 g_assert (prev_seg->char_count > 0);
2111 /* We skipped the entire previous segment, plus any
2112 * chars we were into the current segment.
2114 if (real->segment_byte_offset >= 0)
2115 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2119 if (real->segment_char_offset >= 0)
2120 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2124 real->segment = prev_seg;
2125 real->any_segment = prev_any_seg;
2126 real->segment_byte_offset = 0;
2127 real->segment_char_offset = 0;
2129 if (bytes_skipped >= 0)
2131 if (real->line_byte_offset >= 0)
2133 real->line_byte_offset -= bytes_skipped;
2134 g_assert (real->line_byte_offset >= 0);
2138 real->line_byte_offset = -1;
2140 if (chars_skipped >= 0)
2142 if (real->line_char_offset >= 0)
2144 real->line_char_offset -= chars_skipped;
2145 g_assert (real->line_char_offset >= 0);
2148 if (real->cached_char_index >= 0)
2150 real->cached_char_index -= chars_skipped;
2151 g_assert (real->cached_char_index >= 0);
2156 real->line_char_offset = -1;
2157 real->cached_char_index = -1;
2160 /* line number is unchanged. */
2162 check_invariants (iter);
2168 * gtk_text_iter_forward_char:
2169 * @iter: an iterator
2171 * Moves @iter forward by one character offset. Note that images
2172 * embedded in the buffer occupy 1 character slot, so
2173 * gtk_text_iter_forward_char () may actually move onto an image instead
2174 * of a character, if you have images in your buffer. If @iter is the
2175 * end iterator or one character before it, @iter will now point at
2176 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2177 * convenience when writing loops.
2179 * Return value: whether the new position is the end iterator
2182 gtk_text_iter_forward_char (GtkTextIter *iter)
2184 GtkTextRealIter *real;
2186 g_return_val_if_fail (iter != NULL, FALSE);
2188 real = gtk_text_iter_make_real (iter);
2194 check_invariants (iter);
2195 return forward_char (real);
2200 * gtk_text_iter_backward_char:
2201 * @iter: an iterator
2203 * Moves backward by one character offset. Returns TRUE if movement
2204 * was possible; if @iter was the first in the buffer (character
2205 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2208 * Return value: whether movement was possible
2211 gtk_text_iter_backward_char (GtkTextIter *iter)
2213 g_return_val_if_fail (iter != NULL, FALSE);
2215 check_invariants (iter);
2217 return gtk_text_iter_backward_chars (iter, 1);
2221 Definitely we should try to linear scan as often as possible for
2222 movement within a single line, because we can't use the BTree to
2223 speed within-line searches up; for movement between lines, we would
2224 like to avoid the linear scan probably.
2226 Instead of using this constant, it might be nice to cache the line
2227 length in the iterator and linear scan if motion is within a single
2230 I guess you'd have to profile the various approaches.
2232 #define MAX_LINEAR_SCAN 150
2236 * gtk_text_iter_forward_chars:
2237 * @iter: an iterator
2238 * @count: number of characters to move, may be negative
2240 * Moves @count characters if possible (if @count would move past the
2241 * start or end of the buffer, moves to the start or end of the
2242 * buffer). The return value indicates whether the new position of
2243 * @iter is different from its original position, and dereferenceable
2244 * (the last iterator in the buffer is not dereferenceable). If @count
2245 * is 0, the function does nothing and returns FALSE.
2247 * Return value: whether @iter moved and is dereferenceable
2250 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2252 GtkTextRealIter *real;
2254 g_return_val_if_fail (iter != NULL, FALSE);
2256 FIX_OVERFLOWS (count);
2258 real = gtk_text_iter_make_real (iter);
2262 else if (count == 0)
2265 return gtk_text_iter_backward_chars (iter, 0 - count);
2266 else if (count < MAX_LINEAR_SCAN)
2268 check_invariants (iter);
2272 if (!forward_char (real))
2277 return forward_char (real);
2281 gint current_char_index;
2282 gint new_char_index;
2284 check_invariants (iter);
2286 current_char_index = gtk_text_iter_get_offset (iter);
2288 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2289 return FALSE; /* can't move forward */
2291 new_char_index = current_char_index + count;
2292 gtk_text_iter_set_offset (iter, new_char_index);
2294 check_invariants (iter);
2296 /* Return FALSE if we're on the non-dereferenceable end
2299 if (gtk_text_iter_is_end (iter))
2307 * gtk_text_iter_backward_chars:
2308 * @iter: an iterator
2309 * @count: number of characters to move
2311 * Moves @count characters backward, if possible (if @count would move
2312 * past the start or end of the buffer, moves to the start or end of
2313 * the buffer). The return value indicates whether the iterator moved
2314 * onto a dereferenceable position; if the iterator didn't move, or
2315 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2316 * the function does nothing and returns FALSE.
2318 * Return value: whether @iter moved and is dereferenceable
2322 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2324 GtkTextRealIter *real;
2326 g_return_val_if_fail (iter != NULL, FALSE);
2328 FIX_OVERFLOWS (count);
2330 real = gtk_text_iter_make_real (iter);
2334 else if (count == 0)
2337 return gtk_text_iter_forward_chars (iter, 0 - count);
2339 ensure_char_offsets (real);
2340 check_invariants (iter);
2342 if (count <= real->segment_char_offset)
2344 /* Optimize the within-segment case */
2345 g_assert (real->segment->char_count > 0);
2346 g_assert (real->segment->type == >k_text_char_type);
2348 real->segment_char_offset -= count;
2349 g_assert (real->segment_char_offset >= 0);
2351 if (real->line_byte_offset >= 0)
2353 gint new_byte_offset;
2356 new_byte_offset = 0;
2358 while (i < real->segment_char_offset)
2360 const char * start = real->segment->body.chars + new_byte_offset;
2361 new_byte_offset += g_utf8_next_char (start) - start;
2366 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2367 real->segment_byte_offset = new_byte_offset;
2370 real->line_char_offset -= count;
2372 adjust_char_index (real, 0 - count);
2374 check_invariants (iter);
2380 /* We need to go back into previous segments. For now,
2381 * just keep this really simple. FIXME
2382 * use backward_indexable_segment.
2384 if (TRUE || count > MAX_LINEAR_SCAN)
2386 gint current_char_index;
2387 gint new_char_index;
2389 current_char_index = gtk_text_iter_get_offset (iter);
2391 if (current_char_index == 0)
2392 return FALSE; /* can't move backward */
2394 new_char_index = current_char_index - count;
2395 if (new_char_index < 0)
2397 gtk_text_iter_set_offset (iter, new_char_index);
2399 check_invariants (iter);
2405 /* FIXME backward_indexable_segment here */
2414 /* These two can't be implemented efficiently (always have to use
2415 * a linear scan, since that's the only way to find all the non-text
2420 * gtk_text_iter_forward_text_chars:
2421 * @iter: a #GtkTextIter
2422 * @count: number of chars to move
2424 * Moves forward by @count text characters (pixbufs, widgets,
2425 * etc. do not count as characters for this). Equivalent to moving
2426 * through the results of gtk_text_iter_get_text (), rather than
2427 * gtk_text_iter_get_slice ().
2429 * Return value: whether @iter moved and is dereferenceable
2432 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2441 * gtk_text_iter_forward_text_chars:
2442 * @iter: a #GtkTextIter
2443 * @count: number of chars to move
2445 * Moves backward by @count text characters (pixbufs, widgets,
2446 * etc. do not count as characters for this). Equivalent to moving
2447 * through the results of gtk_text_iter_get_text (), rather than
2448 * gtk_text_iter_get_slice ().
2450 * Return value: whether @iter moved and is dereferenceable
2453 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2462 * gtk_text_iter_forward_line:
2463 * @iter: an iterator
2465 * Moves @iter to the start of the next line. Returns TRUE if there
2466 * was a next line to move to, and FALSE if @iter was simply moved to
2467 * the end of the buffer and is now not dereferenceable, or if @iter was
2468 * already at the end of the buffer.
2470 * Return value: whether @iter can be dereferenced
2473 gtk_text_iter_forward_line (GtkTextIter *iter)
2475 GtkTextRealIter *real;
2477 g_return_val_if_fail (iter != NULL, FALSE);
2479 real = gtk_text_iter_make_real (iter);
2484 check_invariants (iter);
2486 if (forward_line_leaving_caches_unmodified (real))
2488 invalidate_char_index (real);
2489 adjust_line_number (real, 1);
2491 check_invariants (iter);
2493 if (gtk_text_iter_is_end (iter))
2500 /* On the last line, move to end of it */
2502 if (!gtk_text_iter_is_end (iter))
2503 gtk_text_iter_forward_to_end (iter);
2505 check_invariants (iter);
2511 * gtk_text_iter_backward_line:
2512 * @iter: an iterator
2514 * Moves @iter to the start of the previous line. Returns TRUE if
2515 * @iter could be moved; i.e. if @iter was at character offset 0, this
2516 * function returns FALSE. Therefore if @iter was already on line 0,
2517 * but not at the start of the line, @iter is snapped to the start of
2518 * the line and the function returns TRUE. (Note that this implies that
2519 * in a loop calling this function, the line number may not change on
2520 * every iteration, if your first iteration is on line 0.)
2522 * Return value: whether @iter moved
2525 gtk_text_iter_backward_line (GtkTextIter *iter)
2527 GtkTextLine *new_line;
2528 GtkTextRealIter *real;
2529 gboolean offset_will_change;
2532 g_return_val_if_fail (iter != NULL, FALSE);
2534 real = gtk_text_iter_make_real (iter);
2539 check_invariants (iter);
2541 new_line = _gtk_text_line_previous (real->line);
2543 offset_will_change = FALSE;
2544 if (real->line_char_offset > 0)
2545 offset_will_change = TRUE;
2547 if (new_line != NULL)
2549 real->line = new_line;
2551 adjust_line_number (real, -1);
2555 if (!offset_will_change)
2559 invalidate_char_index (real);
2561 real->line_byte_offset = 0;
2562 real->line_char_offset = 0;
2564 real->segment_byte_offset = 0;
2565 real->segment_char_offset = 0;
2567 /* Find first segment in line */
2568 real->any_segment = real->line->segments;
2569 real->segment = _gtk_text_line_byte_to_segment (real->line,
2572 g_assert (offset == 0);
2574 /* Note that if we are on the first line, we snap to the start of
2575 * the first line and return TRUE, so TRUE means the iterator
2576 * changed, not that the line changed; this is maybe a bit
2577 * weird. I'm not sure there's an obvious right thing to do though.
2580 check_invariants (iter);
2587 * gtk_text_iter_forward_lines:
2588 * @iter: a #GtkTextIter
2589 * @count: number of lines to move forward
2591 * Moves @count lines forward, if possible (if @count would move
2592 * past the start or end of the buffer, moves to the start or end of
2593 * the buffer). The return value indicates whether the iterator moved
2594 * onto a dereferenceable position; if the iterator didn't move, or
2595 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2596 * the function does nothing and returns FALSE. If @count is negative,
2597 * moves backward by 0 - @count lines.
2599 * Return value: whether @iter moved and is dereferenceable
2602 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2604 FIX_OVERFLOWS (count);
2607 return gtk_text_iter_backward_lines (iter, 0 - count);
2608 else if (count == 0)
2610 else if (count == 1)
2612 check_invariants (iter);
2613 return gtk_text_iter_forward_line (iter);
2619 old_line = gtk_text_iter_get_line (iter);
2621 gtk_text_iter_set_line (iter, old_line + count);
2623 check_invariants (iter);
2625 /* return whether it moved, and is dereferenceable. */
2627 (gtk_text_iter_get_line (iter) != old_line) &&
2628 !gtk_text_iter_is_end (iter);
2633 * gtk_text_iter_backward_lines:
2634 * @iter: a #GtkTextIter
2635 * @count: number of lines to move backward
2637 * Moves @count lines backward, if possible (if @count would move
2638 * past the start or end of the buffer, moves to the start or end of
2639 * the buffer). The return value indicates whether the iterator moved
2640 * onto a dereferenceable position; if the iterator didn't move, or
2641 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2642 * the function does nothing and returns FALSE. If @count is negative,
2643 * moves forward by 0 - @count lines.
2645 * Return value: whether @iter moved and is dereferenceable
2648 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2650 FIX_OVERFLOWS (count);
2653 return gtk_text_iter_forward_lines (iter, 0 - count);
2654 else if (count == 0)
2656 else if (count == 1)
2658 return gtk_text_iter_backward_line (iter);
2664 old_line = gtk_text_iter_get_line (iter);
2666 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2668 return (gtk_text_iter_get_line (iter) != old_line);
2672 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2677 gboolean already_moved_initially);
2679 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2687 find_word_end_func (const PangoLogAttr *attrs,
2692 gboolean already_moved_initially)
2694 if (!already_moved_initially)
2697 /* Find end of next word */
2698 while (offset < min_offset + len &&
2699 !attrs[offset].is_word_end)
2702 *found_offset = offset;
2704 return offset < min_offset + len;
2708 is_word_end_func (const PangoLogAttr *attrs,
2713 return attrs[offset].is_word_end;
2717 find_word_start_func (const PangoLogAttr *attrs,
2722 gboolean already_moved_initially)
2724 if (!already_moved_initially)
2727 /* Find start of prev word */
2728 while (offset >= min_offset &&
2729 !attrs[offset].is_word_start)
2732 *found_offset = offset;
2734 return offset >= min_offset;
2738 is_word_start_func (const PangoLogAttr *attrs,
2743 return attrs[offset].is_word_start;
2747 inside_word_func (const PangoLogAttr *attrs,
2752 /* Find next word start or end */
2753 while (offset >= min_offset &&
2754 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2757 return attrs[offset].is_word_start;
2760 /* Sentence funcs */
2763 find_sentence_end_func (const PangoLogAttr *attrs,
2768 gboolean already_moved_initially)
2770 if (!already_moved_initially)
2773 /* Find end of next sentence */
2774 while (offset < min_offset + len &&
2775 !attrs[offset].is_sentence_end)
2778 *found_offset = offset;
2780 return offset < min_offset + len;
2784 is_sentence_end_func (const PangoLogAttr *attrs,
2789 return attrs[offset].is_sentence_end;
2793 find_sentence_start_func (const PangoLogAttr *attrs,
2798 gboolean already_moved_initially)
2800 if (!already_moved_initially)
2803 /* Find start of prev sentence */
2804 while (offset >= min_offset &&
2805 !attrs[offset].is_sentence_start)
2808 *found_offset = offset;
2810 return offset >= min_offset;
2814 is_sentence_start_func (const PangoLogAttr *attrs,
2819 return attrs[offset].is_sentence_start;
2823 inside_sentence_func (const PangoLogAttr *attrs,
2828 /* Find next sentence start or end */
2829 while (offset >= min_offset &&
2830 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2833 return attrs[offset].is_sentence_start;
2837 test_log_attrs (const GtkTextIter *iter,
2838 TestLogAttrFunc func)
2841 const PangoLogAttr *attrs;
2843 gboolean result = FALSE;
2845 g_return_val_if_fail (iter != NULL, FALSE);
2847 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2850 offset = gtk_text_iter_get_line_offset (iter);
2852 /* char_len may be 0 and attrs will be NULL if so, if
2853 * iter is the end iter and the last line is empty
2856 if (offset < char_len)
2857 result = (* func) (attrs, offset, 0, char_len);
2863 find_line_log_attrs (const GtkTextIter *iter,
2864 FindLogAttrFunc func,
2866 gboolean already_moved_initially)
2869 const PangoLogAttr *attrs;
2871 gboolean result = FALSE;
2873 g_return_val_if_fail (iter != NULL, FALSE);
2875 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2878 offset = gtk_text_iter_get_line_offset (iter);
2880 /* char_len may be 0 and attrs will be NULL if so, if
2881 * iter is the end iter and the last line is empty
2885 result = (* func) (attrs, offset, 0, char_len, found_offset,
2886 already_moved_initially);
2891 /* FIXME this function is very, very gratuitously slow */
2893 find_by_log_attrs (GtkTextIter *iter,
2894 FindLogAttrFunc func,
2896 gboolean already_moved_initially)
2900 gboolean found = FALSE;
2902 g_return_val_if_fail (iter != NULL, FALSE);
2906 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2912 if (gtk_text_iter_forward_line (iter))
2913 return find_by_log_attrs (iter, func, forward,
2920 /* go to end of previous line. need to check that
2921 * line is > 0 because backward_line snaps to start of
2922 * line 0 if it's on line 0
2924 if (gtk_text_iter_get_line (iter) > 0 &&
2925 gtk_text_iter_backward_line (iter))
2927 if (!gtk_text_iter_ends_line (iter))
2928 gtk_text_iter_forward_to_line_end (iter);
2930 return find_by_log_attrs (iter, func, forward,
2939 gtk_text_iter_set_line_offset (iter, offset);
2942 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2943 !gtk_text_iter_is_end (iter);
2948 * gtk_text_iter_forward_word_end:
2949 * @iter: a #GtkTextIter
2951 * Moves forward to the next word end. (If @iter is currently on a
2952 * word end, moves forward to the next one after that.) Word breaks
2953 * are determined by Pango and should be correct for nearly any
2954 * language (if not, the correct fix would be to the Pango word break
2957 * Return value: %TRUE if @iter moved and is not the end iterator
2960 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2962 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2966 * gtk_text_iter_backward_word_start:
2967 * @iter: a #GtkTextIter
2969 * Moves backward to the next word start. (If @iter is currently on a
2970 * word start, moves backward to the next one after that.) Word breaks
2971 * are determined by Pango and should be correct for nearly any
2972 * language (if not, the correct fix would be to the Pango word break
2975 * Return value: %TRUE if @iter moved and is not the end iterator
2978 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2980 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2983 /* FIXME a loop around a truly slow function means
2984 * a truly spectacularly slow function.
2988 * gtk_text_iter_forward_word_ends:
2989 * @iter: a #GtkTextIter
2990 * @count: number of times to move
2992 * Calls gtk_text_iter_forward_word_end() up to @count times.
2994 * Return value: %TRUE if @iter moved and is not the end iterator
2997 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3000 g_return_val_if_fail (iter != NULL, FALSE);
3002 FIX_OVERFLOWS (count);
3008 return gtk_text_iter_backward_word_starts (iter, -count);
3010 if (!gtk_text_iter_forward_word_end (iter))
3016 if (!gtk_text_iter_forward_word_end (iter))
3024 * gtk_text_iter_backward_word_starts
3025 * @iter: a #GtkTextIter
3026 * @count: number of times to move
3028 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3030 * Return value: %TRUE if @iter moved and is not the end iterator
3033 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3036 g_return_val_if_fail (iter != NULL, FALSE);
3038 FIX_OVERFLOWS (count);
3041 return gtk_text_iter_forward_word_ends (iter, -count);
3043 if (!gtk_text_iter_backward_word_start (iter))
3049 if (!gtk_text_iter_backward_word_start (iter))
3057 * gtk_text_iter_starts_word:
3058 * @iter: a #GtkTextIter
3060 * Determines whether @iter begins a natural-language word. Word
3061 * breaks are determined by Pango and should be correct for nearly any
3062 * language (if not, the correct fix would be to the Pango word break
3065 * Return value: %TRUE if @iter is at the start of a word
3068 gtk_text_iter_starts_word (const GtkTextIter *iter)
3070 return test_log_attrs (iter, is_word_start_func);
3074 * gtk_text_iter_ends_word:
3075 * @iter: a #GtkTextIter
3077 * Determines whether @iter ends a natural-language word. Word breaks
3078 * are determined by Pango and should be correct for nearly any
3079 * language (if not, the correct fix would be to the Pango word break
3082 * Return value: %TRUE if @iter is at the end of a word
3085 gtk_text_iter_ends_word (const GtkTextIter *iter)
3087 return test_log_attrs (iter, is_word_end_func);
3091 * gtk_text_iter_inside_word:
3092 * @iter: a #GtkTextIter
3094 * Determines whether @iter is inside a natural-language word (as
3095 * opposed to say inside some whitespace). Word breaks are determined
3096 * by Pango and should be correct for nearly any language (if not, the
3097 * correct fix would be to the Pango word break algorithms).
3099 * Return value: %TRUE if @iter is inside a word
3102 gtk_text_iter_inside_word (const GtkTextIter *iter)
3104 return test_log_attrs (iter, inside_word_func);
3108 * gtk_text_iter_starts_sentence:
3109 * @iter: a #GtkTextIter
3111 * Determines whether @iter begins a sentence. Sentence boundaries are
3112 * determined by Pango and should be correct for nearly any language
3113 * (if not, the correct fix would be to the Pango text boundary
3116 * Return value: %TRUE if @iter is at the start of a sentence.
3119 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3121 return test_log_attrs (iter, is_sentence_start_func);
3125 * gtk_text_iter_ends_sentence:
3126 * @iter: a #GtkTextIter
3128 * Determines whether @iter ends a sentence. Sentence boundaries are
3129 * determined by Pango and should be correct for nearly any language
3130 * (if not, the correct fix would be to the Pango text boundary
3133 * Return value: %TRUE if @iter is at the end of a sentence.
3136 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3138 return test_log_attrs (iter, is_sentence_end_func);
3142 * gtk_text_iter_inside_sentence:
3143 * @iter: a #GtkTextIter
3145 * Determines whether @iter is inside a sentence (as opposed to in
3146 * between two sentences, e.g. after a period and before the first
3147 * letter of the next sentence). Sentence boundaries are determined
3148 * by Pango and should be correct for nearly any language (if not, the
3149 * correct fix would be to the Pango text boundary algorithms).
3151 * Return value: %TRUE if @iter is inside a sentence.
3154 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3156 return test_log_attrs (iter, inside_sentence_func);
3160 * gtk_text_iter_forward_sentence_end:
3161 * @iter: a #GtkTextIter
3163 * Moves forward to the next sentence end. (If @iter is at the end of
3164 * a sentence, moves to the next end of sentence.) Sentence
3165 * boundaries are determined by Pango and should be correct for nearly
3166 * any language (if not, the correct fix would be to the Pango text
3167 * boundary algorithms).
3169 * Return value: %TRUE if @iter moved and is not the end iterator
3172 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3174 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3178 * gtk_text_iter_backward_sentence_start:
3179 * @iter: a #GtkTextIter
3181 * Moves backward to the next sentence start; if @iter is already at
3182 * the start of a sentence, moves backward to the next one. Sentence
3183 * boundaries are determined by Pango and should be correct for nearly
3184 * any language (if not, the correct fix would be to the Pango text
3185 * boundary algorithms).
3187 * Return value: %TRUE if @iter moved and is not the end iterator
3190 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3192 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3195 /* FIXME a loop around a truly slow function means
3196 * a truly spectacularly slow function.
3199 * gtk_text_iter_forward_sentence_ends:
3200 * @iter: a #GtkTextIter
3201 * @count: number of sentences to move
3203 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3204 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3205 * negative, moves backward instead of forward.
3207 * Return value: %TRUE if @iter moved and is not the end iterator
3210 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3213 g_return_val_if_fail (iter != NULL, FALSE);
3219 return gtk_text_iter_backward_sentence_starts (iter, -count);
3221 if (!gtk_text_iter_forward_sentence_end (iter))
3227 if (!gtk_text_iter_forward_sentence_end (iter))
3235 * gtk_text_iter_backward_sentence_starts:
3236 * @iter: a #GtkTextIter
3237 * @count: number of sentences to move
3239 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3240 * or until it returns %FALSE. If @count is negative, moves forward
3241 * instead of backward.
3243 * Return value: %TRUE if @iter moved and is not the end iterator
3246 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3249 g_return_val_if_fail (iter != NULL, FALSE);
3252 return gtk_text_iter_forward_sentence_ends (iter, -count);
3254 if (!gtk_text_iter_backward_sentence_start (iter))
3260 if (!gtk_text_iter_backward_sentence_start (iter))
3268 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3273 gboolean already_moved_initially)
3275 if (!already_moved_initially)
3278 while (offset < (min_offset + len) &&
3279 !attrs[offset].is_cursor_position)
3282 *found_offset = offset;
3284 return offset < (min_offset + len);
3288 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3293 gboolean already_moved_initially)
3295 if (!already_moved_initially)
3298 while (offset > min_offset &&
3299 !attrs[offset].is_cursor_position)
3302 *found_offset = offset;
3304 return offset >= min_offset;
3308 is_cursor_pos_func (const PangoLogAttr *attrs,
3313 return attrs[offset].is_cursor_position;
3317 * gtk_text_iter_forward_cursor_position:
3318 * @iter: a #GtkTextIter
3320 * Moves @iter forward by a single cursor position. Cursor positions
3321 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3322 * surprisingly, there may not be a cursor position between all
3323 * characters. The most common example for European languages would be
3324 * a carriage return/newline sequence. For some Unicode characters,
3325 * the equivalent of say the letter "a" with an accent mark will be
3326 * represented as two characters, first the letter then a "combining
3327 * mark" that causes the accent to be rendered; so the cursor can't go
3328 * between those two characters. See also the #PangoLogAttr structure and
3329 * pango_break() function.
3331 * Return value: %TRUE if we moved and the new position is dereferenceable
3334 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3336 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3340 * gtk_text_iter_backward_cursor_position:
3341 * @iter: a #GtkTextIter
3343 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3345 * Return value: %TRUE if we moved and the new position is dereferenceable
3348 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3350 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3354 * gtk_text_iter_forward_cursor_positions:
3355 * @iter: a #GtkTextIter
3356 * @count: number of positions to move
3358 * Moves up to @count cursor positions. See
3359 * gtk_text_iter_forward_cursor_position() for details.
3361 * Return value: %TRUE if we moved and the new position is dereferenceable
3364 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3367 g_return_val_if_fail (iter != NULL, FALSE);
3369 FIX_OVERFLOWS (count);
3375 return gtk_text_iter_backward_cursor_positions (iter, -count);
3377 if (!gtk_text_iter_forward_cursor_position (iter))
3383 if (!gtk_text_iter_forward_cursor_position (iter))
3391 * gtk_text_iter_backward_cursor_positions:
3392 * @iter: a #GtkTextIter
3393 * @count: number of positions to move
3395 * Moves up to @count cursor positions. See
3396 * gtk_text_iter_forward_cursor_position() for details.
3398 * Return value: %TRUE if we moved and the new position is dereferenceable
3401 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3404 g_return_val_if_fail (iter != NULL, FALSE);
3406 FIX_OVERFLOWS (count);
3412 return gtk_text_iter_forward_cursor_positions (iter, -count);
3414 if (!gtk_text_iter_backward_cursor_position (iter))
3420 if (!gtk_text_iter_backward_cursor_position (iter))
3428 * gtk_text_iter_is_cursor_position:
3429 * @iter: a #GtkTextIter
3431 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3432 * pango_break() for details on what a cursor position is.
3434 * Return value: %TRUE if the cursor can be placed at @iter
3437 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3439 return test_log_attrs (iter, is_cursor_pos_func);
3443 * gtk_text_iter_set_line_offset:
3444 * @iter: a #GtkTextIter
3445 * @char_on_line: a character offset relative to the start of @iter's current line
3447 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3448 * (not byte) offset. The given character offset must be less than or
3449 * equal to the number of characters in the line; if equal, @iter
3450 * moves to the start of the next line. See
3451 * gtk_text_iter_set_line_index() if you have a byte index rather than
3452 * a character offset.
3456 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3459 GtkTextRealIter *real;
3462 g_return_if_fail (iter != NULL);
3464 real = gtk_text_iter_make_surreal (iter);
3469 check_invariants (iter);
3471 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3473 g_return_if_fail (char_on_line <= chars_in_line);
3475 if (char_on_line < chars_in_line)
3476 iter_set_from_char_offset (real, real->line, char_on_line);
3478 gtk_text_iter_forward_line (iter); /* set to start of next line */
3480 check_invariants (iter);
3484 * gtk_text_iter_set_line_index:
3485 * @iter: a #GtkTextIter
3486 * @byte_on_line: a byte index relative to the start of @iter's current line
3488 * Same as gtk_text_iter_set_line_offset(), but works with a
3489 * <emphasis>byte</emphasis> index. The given byte index must be at
3490 * the start of a character, it can't be in the middle of a UTF-8
3491 * encoded character.
3495 gtk_text_iter_set_line_index (GtkTextIter *iter,
3498 GtkTextRealIter *real;
3501 g_return_if_fail (iter != NULL);
3503 real = gtk_text_iter_make_surreal (iter);
3508 check_invariants (iter);
3510 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3512 g_return_if_fail (byte_on_line <= bytes_in_line);
3514 if (byte_on_line < bytes_in_line)
3515 iter_set_from_byte_offset (real, real->line, byte_on_line);
3517 gtk_text_iter_forward_line (iter);
3519 if (real->segment->type == >k_text_char_type &&
3520 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3521 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3522 "character; this will crash the text buffer. "
3523 "Byte indexes must refer to the start of a character.",
3524 G_STRLOC, byte_on_line);
3526 check_invariants (iter);
3531 * gtk_text_iter_set_visible_line_offset:
3532 * @iter: a #GtkTextIter
3533 * @char_on_line: a character offset
3535 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3536 * characters, i.e. text with a tag making it invisible is not
3537 * counted in the offset.
3540 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3543 gint chars_seen = 0;
3546 g_return_if_fail (iter != NULL);
3550 /* For now we use a ludicrously slow implementation */
3551 while (chars_seen < char_on_line)
3553 if (!_gtk_text_btree_char_is_invisible (&pos))
3556 if (!gtk_text_iter_forward_char (&pos))
3559 if (chars_seen == char_on_line)
3563 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3566 gtk_text_iter_forward_line (iter);
3570 bytes_in_char (GtkTextIter *iter)
3572 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3576 * gtk_text_iter_set_visible_line_index:
3577 * @iter: a #GtkTextIter
3578 * @byte_on_line: a byte index
3580 * Like gtk_text_iter_set_line_index(), but the index is in visible
3581 * bytes, i.e. text with a tag making it invisible is not counted
3585 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3588 gint bytes_seen = 0;
3591 g_return_if_fail (iter != NULL);
3595 /* For now we use a ludicrously slow implementation */
3596 while (bytes_seen < byte_on_line)
3598 if (!_gtk_text_btree_char_is_invisible (&pos))
3599 bytes_seen += bytes_in_char (&pos);
3601 if (!gtk_text_iter_forward_char (&pos))
3604 if (bytes_seen >= byte_on_line)
3608 if (bytes_seen > byte_on_line)
3609 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3610 "character; this will crash the text buffer. "
3611 "Byte indexes must refer to the start of a character.",
3612 G_STRLOC, byte_on_line);
3614 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3617 gtk_text_iter_forward_line (iter);
3621 * gtk_text_iter_set_line:
3622 * @iter: a #GtkTextIter
3623 * @line_number: line number (counted from 0)
3625 * Moves iterator @iter to the start of the line @line_number.
3629 gtk_text_iter_set_line (GtkTextIter *iter,
3634 GtkTextRealIter *real;
3636 g_return_if_fail (iter != NULL);
3638 real = gtk_text_iter_make_surreal (iter);
3643 check_invariants (iter);
3645 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3647 iter_set_from_char_offset (real, line, 0);
3649 /* We might as well cache this, since we know it. */
3650 real->cached_line_number = real_line;
3652 check_invariants (iter);
3656 * gtk_text_iter_set_offset:
3657 * @iter: a #GtkTextIter
3658 * @char_offset: a character number
3660 * Sets @iter to point to @char_offset. @char_offset counts from the start
3661 * of the entire text buffer, starting with 0.
3665 gtk_text_iter_set_offset (GtkTextIter *iter,
3669 GtkTextRealIter *real;
3671 gint real_char_index;
3673 g_return_if_fail (iter != NULL);
3675 real = gtk_text_iter_make_surreal (iter);
3680 check_invariants (iter);
3682 if (real->cached_char_index >= 0 &&
3683 real->cached_char_index == char_offset)
3686 line = _gtk_text_btree_get_line_at_char (real->tree,
3691 iter_set_from_char_offset (real, line, real_char_index - line_start);
3693 /* Go ahead and cache this since we have it. */
3694 real->cached_char_index = real_char_index;
3696 check_invariants (iter);
3700 * gtk_text_iter_forward_to_end:
3701 * @iter: a #GtkTextIter
3703 * Moves @iter forward to the "end iterator," which points one past the last
3704 * valid character in the buffer. gtk_text_iter_get_char() called on the
3705 * end iterator returns 0, which is convenient for writing loops.
3709 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3711 GtkTextBuffer *buffer;
3712 GtkTextRealIter *real;
3714 g_return_if_fail (iter != NULL);
3716 real = gtk_text_iter_make_surreal (iter);
3721 buffer = _gtk_text_btree_get_buffer (real->tree);
3723 gtk_text_buffer_get_end_iter (buffer, iter);
3727 * gtk_text_iter_forward_to_line_end:
3728 * @iter: a #GtkTextIter
3730 * Moves the iterator to point to the paragraph delimiter characters,
3731 * which will be either a newline, a carriage return, a carriage
3732 * return/newline in sequence, or the Unicode paragraph separator
3733 * character. If the iterator is already at the paragraph delimiter
3734 * characters, moves to the paragraph delimiter characters for the
3737 * Return value: %TRUE if we moved and the new location is not the end iterator
3740 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3742 gint current_offset;
3745 g_return_val_if_fail (iter != NULL, FALSE);
3747 current_offset = gtk_text_iter_get_line_offset (iter);
3748 /* FIXME assumption that line ends in a newline; broken */
3749 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3751 if (current_offset < new_offset)
3753 /* Move to end of this line. */
3754 gtk_text_iter_set_line_offset (iter, new_offset);
3759 /* Move to end of next line. */
3760 if (gtk_text_iter_forward_line (iter))
3762 /* We don't want to move past all
3765 if (!gtk_text_iter_ends_line (iter))
3766 gtk_text_iter_forward_to_line_end (iter);
3775 * gtk_text_iter_forward_to_tag_toggle:
3776 * @iter: a #GtkTextIter
3777 * @tag: a #GtkTextTag, or NULL
3779 * Moves forward to the next toggle (on or off) of the
3780 * #GtkTextTag @tag, or to the next toggle of any tag if
3781 * @tag is NULL. If no matching tag toggles are found,
3782 * returns FALSE, otherwise TRUE. Does not return toggles
3783 * located at @iter, only toggles after @iter. Sets @iter to
3784 * the location of the toggle, or to the end of the buffer
3785 * if no toggle is found.
3787 * Return value: whether we found a tag toggle after @iter
3790 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3793 GtkTextLine *next_line;
3794 GtkTextLine *current_line;
3795 GtkTextRealIter *real;
3797 g_return_val_if_fail (iter != NULL, FALSE);
3799 real = gtk_text_iter_make_real (iter);
3804 check_invariants (iter);
3806 current_line = real->line;
3807 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3810 while (_gtk_text_iter_forward_indexable_segment (iter))
3812 /* If we went forward to a line that couldn't contain a toggle
3813 for the tag, then skip forward to a line that could contain
3814 it. This potentially skips huge hunks of the tree, so we
3815 aren't a purely linear search. */
3816 if (real->line != current_line)
3818 if (next_line == NULL)
3820 /* End of search. Set to end of buffer. */
3821 _gtk_text_btree_get_end_iter (real->tree, iter);
3825 if (real->line != next_line)
3826 iter_set_from_byte_offset (real, next_line, 0);
3828 current_line = real->line;
3829 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3834 if (gtk_text_iter_toggles_tag (iter, tag))
3836 /* If there's a toggle here, it isn't indexable so
3837 any_segment can't be the indexable segment. */
3838 g_assert (real->any_segment != real->segment);
3843 /* Check end iterator for tags */
3844 if (gtk_text_iter_toggles_tag (iter, tag))
3846 /* If there's a toggle here, it isn't indexable so
3847 any_segment can't be the indexable segment. */
3848 g_assert (real->any_segment != real->segment);
3852 /* Reached end of buffer */
3857 * gtk_text_iter_backward_to_tag_toggle:
3858 * @iter: a #GtkTextIter
3859 * @tag: a #GtkTextTag, or NULL
3861 * Moves backward to the next toggle (on or off) of the
3862 * #GtkTextTag @tag, or to the next toggle of any tag if
3863 * @tag is NULL. If no matching tag toggles are found,
3864 * returns FALSE, otherwise TRUE. Does not return toggles
3865 * located at @iter, only toggles before @iter. Sets @iter
3866 * to the location of the toggle, or the start of the buffer
3867 * if no toggle is found.
3869 * Return value: whether we found a tag toggle before @iter
3872 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3875 GtkTextLine *prev_line;
3876 GtkTextLine *current_line;
3877 GtkTextRealIter *real;
3879 g_return_val_if_fail (iter != NULL, FALSE);
3881 real = gtk_text_iter_make_real (iter);
3886 check_invariants (iter);
3888 current_line = real->line;
3889 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3893 /* If we're at segment start, go to the previous segment;
3894 * if mid-segment, snap to start of current segment.
3896 if (is_segment_start (real))
3898 if (!_gtk_text_iter_backward_indexable_segment (iter))
3903 ensure_char_offsets (real);
3905 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3911 /* If we went backward to a line that couldn't contain a toggle
3912 * for the tag, then skip backward further to a line that
3913 * could contain it. This potentially skips huge hunks of the
3914 * tree, so we aren't a purely linear search.
3916 if (real->line != current_line)
3918 if (prev_line == NULL)
3920 /* End of search. Set to start of buffer. */
3921 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3925 if (real->line != prev_line)
3927 /* Set to last segment in prev_line (could do this
3930 iter_set_from_byte_offset (real, prev_line, 0);
3932 while (!at_last_indexable_segment (real))
3933 _gtk_text_iter_forward_indexable_segment (iter);
3936 current_line = real->line;
3937 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3942 if (gtk_text_iter_toggles_tag (iter, tag))
3944 /* If there's a toggle here, it isn't indexable so
3945 * any_segment can't be the indexable segment.
3947 g_assert (real->any_segment != real->segment);
3951 while (_gtk_text_iter_backward_indexable_segment (iter));
3953 /* Reached front of buffer */
3958 matches_pred (GtkTextIter *iter,
3959 GtkTextCharPredicate pred,
3964 ch = gtk_text_iter_get_char (iter);
3966 return (*pred) (ch, user_data);
3970 * gtk_text_iter_forward_find_char:
3971 * @iter: a #GtkTextIter
3972 * @pred: a function to be called on each character
3973 * @user_data: user data for @pred
3974 * @limit: search limit, or %NULL for none
3976 * Advances @iter, calling @pred on each character. If
3977 * @pred returns %TRUE, returns %TRUE and stops scanning.
3978 * If @pred never returns %TRUE, @iter is set to @limit if
3979 * @limit is non-%NULL, otherwise to the end iterator.
3981 * Return value: whether a match was found
3984 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3985 GtkTextCharPredicate pred,
3987 const GtkTextIter *limit)
3989 g_return_val_if_fail (iter != NULL, FALSE);
3990 g_return_val_if_fail (pred != NULL, FALSE);
3993 gtk_text_iter_compare (iter, limit) >= 0)
3996 while ((limit == NULL ||
3997 !gtk_text_iter_equal (limit, iter)) &&
3998 gtk_text_iter_forward_char (iter))
4000 if (matches_pred (iter, pred, user_data))
4008 * gtk_text_iter_backward_find_char:
4009 * @iter: a #GtkTextIter
4010 * @pred: function to be called on each character
4011 * @user_data: user data for @pred
4012 * @limit: search limit, or %NULL for none
4014 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4016 * Return value: whether a match was found
4019 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4020 GtkTextCharPredicate pred,
4022 const GtkTextIter *limit)
4024 g_return_val_if_fail (iter != NULL, FALSE);
4025 g_return_val_if_fail (pred != NULL, FALSE);
4028 gtk_text_iter_compare (iter, limit) <= 0)
4031 while ((limit == NULL ||
4032 !gtk_text_iter_equal (limit, iter)) &&
4033 gtk_text_iter_backward_char (iter))
4035 if (matches_pred (iter, pred, user_data))
4043 forward_chars_with_skipping (GtkTextIter *iter,
4045 gboolean skip_invisible,
4046 gboolean skip_nontext)
4051 g_return_if_fail (count >= 0);
4057 gboolean ignored = FALSE;
4060 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4065 _gtk_text_btree_char_is_invisible (iter))
4068 gtk_text_iter_forward_char (iter);
4076 lines_match (const GtkTextIter *start,
4077 const gchar **lines,
4078 gboolean visible_only,
4080 GtkTextIter *match_start,
4081 GtkTextIter *match_end)
4088 if (*lines == NULL || **lines == '\0')
4091 *match_start = *start;
4094 *match_end = *start;
4099 gtk_text_iter_forward_line (&next);
4101 /* No more text in buffer, but *lines is nonempty */
4102 if (gtk_text_iter_equal (start, &next))
4110 line_text = gtk_text_iter_get_visible_slice (start, &next);
4112 line_text = gtk_text_iter_get_slice (start, &next);
4117 line_text = gtk_text_iter_get_visible_text (start, &next);
4119 line_text = gtk_text_iter_get_text (start, &next);
4122 if (match_start) /* if this is the first line we're matching */
4123 found = strstr (line_text, *lines);
4126 /* If it's not the first line, we have to match from the
4127 * start of the line.
4129 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4141 /* Get offset to start of search string */
4142 offset = g_utf8_strlen (line_text, found - line_text);
4146 /* If match start needs to be returned, set it to the
4147 * start of the search string.
4151 *match_start = next;
4153 forward_chars_with_skipping (match_start, offset,
4154 visible_only, !slice);
4157 /* Go to end of search string */
4158 offset += g_utf8_strlen (*lines, -1);
4160 forward_chars_with_skipping (&next, offset,
4161 visible_only, !slice);
4170 /* pass NULL for match_start, since we don't need to find the
4173 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4176 /* strsplit () that retains the delimiter as part of the string. */
4178 strbreakup (const char *string,
4179 const char *delimiter,
4182 GSList *string_list = NULL, *slist;
4183 gchar **str_array, *s;
4186 g_return_val_if_fail (string != NULL, NULL);
4187 g_return_val_if_fail (delimiter != NULL, NULL);
4190 max_tokens = G_MAXINT;
4192 s = strstr (string, delimiter);
4195 guint delimiter_len = strlen (delimiter);
4202 len = s - string + delimiter_len;
4203 new_string = g_new (gchar, len + 1);
4204 strncpy (new_string, string, len);
4205 new_string[len] = 0;
4206 string_list = g_slist_prepend (string_list, new_string);
4208 string = s + delimiter_len;
4209 s = strstr (string, delimiter);
4211 while (--max_tokens && s);
4216 string_list = g_slist_prepend (string_list, g_strdup (string));
4219 str_array = g_new (gchar*, n);
4223 str_array[i--] = NULL;
4224 for (slist = string_list; slist; slist = slist->next)
4225 str_array[i--] = slist->data;
4227 g_slist_free (string_list);
4233 * gtk_text_iter_forward_search:
4234 * @iter: start of search
4235 * @str: a search string
4236 * @visible_only: if %TRUE, search only visible text
4237 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4238 * @match_start: return location for start of match, or %NULL
4239 * @match_end: return location for end of match, or %NULL
4240 * @limit: bound for the search, or %NULL for the end of the buffer
4242 * Searches forward for @str. Any match is returned as the range @match_start,
4243 * @match_end. If you specify @visible_only or @slice, the match may have
4244 * invisible text, pixbufs, or child widgets interspersed in @str.
4246 * Return value: whether a match was found
4249 gtk_text_iter_forward_search (const GtkTextIter *iter,
4251 gboolean visible_only,
4253 GtkTextIter *match_start,
4254 GtkTextIter *match_end,
4255 const GtkTextIter *limit)
4257 gchar **lines = NULL;
4259 gboolean retval = FALSE;
4262 g_return_val_if_fail (iter != NULL, FALSE);
4263 g_return_val_if_fail (str != NULL, FALSE);
4266 gtk_text_iter_compare (iter, limit) >= 0)
4271 /* If we can move one char, return the empty string there */
4274 if (gtk_text_iter_forward_char (&match))
4277 gtk_text_iter_equal (&match, limit))
4281 *match_start = match;
4290 /* locate all lines */
4292 lines = strbreakup (str, "\n", -1);
4298 /* This loop has an inefficient worst-case, where
4299 * gtk_text_iter_get_text () is called repeatedly on
4305 gtk_text_iter_compare (&search, limit) >= 0)
4308 if (lines_match (&search, (const gchar**)lines,
4309 visible_only, slice, &match, &end))
4311 if (limit == NULL ||
4313 gtk_text_iter_compare (&end, limit) < 0))
4318 *match_start = match;
4327 while (gtk_text_iter_forward_line (&search));
4329 g_strfreev ((gchar**)lines);
4335 vectors_equal_ignoring_trailing (gchar **vec1,
4338 /* Ignores trailing chars in vec2's last line */
4347 if (strcmp (*i1, *i2) != 0)
4349 if (*(i2 + 1) == NULL) /* if this is the last line */
4351 gint len1 = strlen (*i1);
4352 gint len2 = strlen (*i2);
4355 strncmp (*i1, *i2, len1) == 0)
4357 /* We matched ignoring the trailing stuff in vec2 */
4382 typedef struct _LinesWindow LinesWindow;
4388 GtkTextIter first_line_start;
4389 GtkTextIter first_line_end;
4391 gboolean visible_only;
4395 lines_window_init (LinesWindow *win,
4396 const GtkTextIter *start)
4399 GtkTextIter line_start;
4400 GtkTextIter line_end;
4402 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4405 if (gtk_text_iter_is_start (start) ||
4406 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4408 /* Already at the end, or not enough lines to match */
4409 win->lines = g_new0 (gchar*, 1);
4414 line_start = *start;
4417 /* Move to start iter to start of line */
4418 gtk_text_iter_set_line_offset (&line_start, 0);
4420 if (gtk_text_iter_equal (&line_start, &line_end))
4422 /* we were already at the start; so go back one line */
4423 gtk_text_iter_backward_line (&line_start);
4426 win->first_line_start = line_start;
4427 win->first_line_end = line_end;
4429 win->lines = g_new0 (gchar*, win->n_lines + 1);
4431 i = win->n_lines - 1;
4438 if (win->visible_only)
4439 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4441 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4445 if (win->visible_only)
4446 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4448 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4451 win->lines[i] = line_text;
4453 line_end = line_start;
4454 gtk_text_iter_backward_line (&line_start);
4461 lines_window_back (LinesWindow *win)
4463 GtkTextIter new_start;
4466 new_start = win->first_line_start;
4468 if (!gtk_text_iter_backward_line (&new_start))
4472 win->first_line_start = new_start;
4473 win->first_line_end = new_start;
4475 gtk_text_iter_forward_line (&win->first_line_end);
4480 if (win->visible_only)
4481 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4482 &win->first_line_end);
4484 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4485 &win->first_line_end);
4489 if (win->visible_only)
4490 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4491 &win->first_line_end);
4493 line_text = gtk_text_iter_get_text (&win->first_line_start,
4494 &win->first_line_end);
4497 /* Move lines to make room for first line. */
4498 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4500 *win->lines = line_text;
4502 /* Free old last line and NULL-terminate */
4503 g_free (win->lines[win->n_lines]);
4504 win->lines[win->n_lines] = NULL;
4510 lines_window_free (LinesWindow *win)
4512 g_strfreev (win->lines);
4516 my_strrstr (const gchar *haystack,
4517 const gchar *needle)
4519 /* FIXME GLib should have a nice implementation in it, this
4523 gint haystack_len = strlen (haystack);
4524 gint needle_len = strlen (needle);
4525 const gchar *needle_end = needle + needle_len;
4526 const gchar *haystack_rend = haystack - 1;
4527 const gchar *needle_rend = needle - 1;
4530 p = haystack + haystack_len;
4531 while (p != haystack)
4533 const gchar *n = needle_end - 1;
4534 const gchar *s = p - 1;
4535 while (s != haystack_rend &&
4543 if (n == needle_rend)
4553 * gtk_text_iter_backward_search:
4554 * @iter: a #GtkTextIter where the search begins
4555 * @str: search string
4556 * @visible_only: if %TRUE search only visible text
4557 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4558 * @match_start: return location for start of match, or %NULL
4559 * @match_end: return location for end of match, or %NULL
4560 * @limit: location of last possible @match_start, or %NULL for start of buffer
4562 * Same as gtk_text_iter_forward_search(), but moves backward.
4564 * Return value: whether a match was found
4567 gtk_text_iter_backward_search (const GtkTextIter *iter,
4569 gboolean visible_only,
4571 GtkTextIter *match_start,
4572 GtkTextIter *match_end,
4573 const GtkTextIter *limit)
4575 gchar **lines = NULL;
4579 gboolean retval = FALSE;
4581 g_return_val_if_fail (iter != NULL, FALSE);
4582 g_return_val_if_fail (str != NULL, FALSE);
4585 gtk_text_iter_compare (limit, iter) > 0)
4590 /* If we can move one char, return the empty string there */
4591 GtkTextIter match = *iter;
4593 if (limit && gtk_text_iter_equal (limit, &match))
4596 if (gtk_text_iter_backward_char (&match))
4599 *match_start = match;
4608 /* locate all lines */
4610 lines = strbreakup (str, "\n", -1);
4620 win.n_lines = n_lines;
4622 win.visible_only = visible_only;
4624 lines_window_init (&win, iter);
4626 if (*win.lines == NULL)
4631 gchar *first_line_match;
4634 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4636 /* We're now before the search limit, abort. */
4640 /* If there are multiple lines, the first line will
4641 * end in '\n', so this will only match at the
4642 * end of the first line, which is correct.
4644 first_line_match = my_strrstr (*win.lines, *lines);
4646 if (first_line_match &&
4647 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4652 GtkTextIter start_tmp;
4654 /* Offset to start of search string */
4655 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4657 next = win.first_line_start;
4659 forward_chars_with_skipping (&start_tmp, offset,
4660 visible_only, !slice);
4663 gtk_text_iter_compare (limit, &start_tmp) > 0)
4664 goto out; /* match was bogus */
4667 *match_start = start_tmp;
4669 /* Go to end of search string */
4673 offset += g_utf8_strlen (*l, -1);
4677 forward_chars_with_skipping (&next, offset,
4678 visible_only, !slice);
4687 while (lines_window_back (&win));
4690 lines_window_free (&win);
4701 * gtk_text_iter_equal:
4702 * @lhs: a #GtkTextIter
4703 * @rhs: another #GtkTextIter
4705 * Tests whether two iterators are equal, using the fastest possible
4706 * mechanism. This function is very fast; you can expect it to perform
4707 * better than e.g. getting the character offset for each iterator and
4708 * comparing the offsets yourself. Also, it's a bit faster than
4709 * gtk_text_iter_compare().
4711 * Return value: %TRUE if the iterators point to the same place in the buffer
4714 gtk_text_iter_equal (const GtkTextIter *lhs,
4715 const GtkTextIter *rhs)
4717 GtkTextRealIter *real_lhs;
4718 GtkTextRealIter *real_rhs;
4720 real_lhs = (GtkTextRealIter*)lhs;
4721 real_rhs = (GtkTextRealIter*)rhs;
4723 check_invariants (lhs);
4724 check_invariants (rhs);
4726 if (real_lhs->line != real_rhs->line)
4728 else if (real_lhs->line_byte_offset >= 0 &&
4729 real_rhs->line_byte_offset >= 0)
4730 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4733 /* the ensure_char_offsets () calls do nothing if the char offsets
4734 are already up-to-date. */
4735 ensure_char_offsets (real_lhs);
4736 ensure_char_offsets (real_rhs);
4737 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4742 * gtk_text_iter_compare:
4743 * @lhs: a #GtkTextIter
4744 * @rhs: another #GtkTextIter
4746 * A qsort()-style function that returns negative if @lhs is less than
4747 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4748 * Ordering is in character offset order, i.e. the first character in the buffer
4749 * is less than the second character in the buffer.
4751 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4754 gtk_text_iter_compare (const GtkTextIter *lhs,
4755 const GtkTextIter *rhs)
4757 GtkTextRealIter *real_lhs;
4758 GtkTextRealIter *real_rhs;
4760 real_lhs = gtk_text_iter_make_surreal (lhs);
4761 real_rhs = gtk_text_iter_make_surreal (rhs);
4763 if (real_lhs == NULL ||
4765 return -1; /* why not */
4767 check_invariants (lhs);
4768 check_invariants (rhs);
4770 if (real_lhs->line == real_rhs->line)
4772 gint left_index, right_index;
4774 if (real_lhs->line_byte_offset >= 0 &&
4775 real_rhs->line_byte_offset >= 0)
4777 left_index = real_lhs->line_byte_offset;
4778 right_index = real_rhs->line_byte_offset;
4782 /* the ensure_char_offsets () calls do nothing if
4783 the offsets are already up-to-date. */
4784 ensure_char_offsets (real_lhs);
4785 ensure_char_offsets (real_rhs);
4786 left_index = real_lhs->line_char_offset;
4787 right_index = real_rhs->line_char_offset;
4790 if (left_index < right_index)
4792 else if (left_index > right_index)
4801 line1 = gtk_text_iter_get_line (lhs);
4802 line2 = gtk_text_iter_get_line (rhs);
4805 else if (line1 > line2)
4813 * gtk_text_iter_in_range:
4814 * @iter: a #GtkTextIter
4815 * @start: start of range
4816 * @end: end of range
4818 * Checks whether @iter falls in the range [@start, @end).
4819 * @start and @end must be in ascending order.
4821 * Return value: %TRUE if @iter is in the range
4824 gtk_text_iter_in_range (const GtkTextIter *iter,
4825 const GtkTextIter *start,
4826 const GtkTextIter *end)
4828 g_return_val_if_fail (iter != NULL, FALSE);
4829 g_return_val_if_fail (start != NULL, FALSE);
4830 g_return_val_if_fail (end != NULL, FALSE);
4831 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4833 return gtk_text_iter_compare (iter, start) >= 0 &&
4834 gtk_text_iter_compare (iter, end) < 0;
4838 * gtk_text_iter_order:
4839 * @first: a #GtkTextIter
4840 * @second: another #GtkTextIter
4842 * Swaps the value of @first and @second if @second comes before
4843 * @first in the buffer. That is, ensures that @first and @second are
4844 * in sequence. Most text buffer functions that take a range call this
4845 * automatically on your behalf, so there's no real reason to call it yourself
4846 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4847 * that expect a pre-sorted range.
4851 gtk_text_iter_order (GtkTextIter *first,
4852 GtkTextIter *second)
4854 g_return_if_fail (first != NULL);
4855 g_return_if_fail (second != NULL);
4857 if (gtk_text_iter_compare (first, second) > 0)
4868 * Init iterators from the BTree
4872 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4876 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4877 gint real_char_index;
4881 g_return_if_fail (iter != NULL);
4882 g_return_if_fail (tree != NULL);
4884 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4885 &line_start, &real_char_index);
4887 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4889 real->cached_char_index = real_char_index;
4891 check_invariants (iter);
4895 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4900 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4904 g_return_if_fail (iter != NULL);
4905 g_return_if_fail (tree != NULL);
4907 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4909 iter_init_from_char_offset (iter, tree, line, char_on_line);
4911 /* We might as well cache this, since we know it. */
4912 real->cached_line_number = real_line;
4914 check_invariants (iter);
4918 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4923 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4927 g_return_if_fail (iter != NULL);
4928 g_return_if_fail (tree != NULL);
4930 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4932 iter_init_from_byte_offset (iter, tree, line, byte_index);
4934 /* We might as well cache this, since we know it. */
4935 real->cached_line_number = real_line;
4937 check_invariants (iter);
4941 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4946 g_return_if_fail (iter != NULL);
4947 g_return_if_fail (tree != NULL);
4948 g_return_if_fail (line != NULL);
4950 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4952 check_invariants (iter);
4956 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4962 g_return_val_if_fail (iter != NULL, FALSE);
4963 g_return_val_if_fail (tree != NULL, FALSE);
4965 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4969 /* Set iter to last in tree */
4970 _gtk_text_btree_get_end_iter (tree, iter);
4971 check_invariants (iter);
4976 iter_init_from_byte_offset (iter, tree, line, 0);
4977 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4978 check_invariants (iter);
4984 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4988 g_return_val_if_fail (iter != NULL, FALSE);
4989 g_return_val_if_fail (tree != NULL, FALSE);
4991 _gtk_text_btree_get_end_iter (tree, iter);
4992 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4993 check_invariants (iter);
4999 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5001 const gchar *mark_name)
5005 g_return_val_if_fail (iter != NULL, FALSE);
5006 g_return_val_if_fail (tree != NULL, FALSE);
5008 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5014 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5015 check_invariants (iter);
5021 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5025 GtkTextLineSegment *seg;
5027 g_return_if_fail (iter != NULL);
5028 g_return_if_fail (tree != NULL);
5029 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5031 seg = mark->segment;
5033 iter_init_from_segment (iter, tree,
5034 seg->body.mark.line, seg);
5035 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5036 check_invariants (iter);
5040 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5042 GtkTextChildAnchor *anchor)
5044 GtkTextLineSegment *seg;
5046 g_return_if_fail (iter != NULL);
5047 g_return_if_fail (tree != NULL);
5048 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5050 seg = anchor->segment;
5052 iter_init_from_segment (iter, tree,
5053 seg->body.child.line, seg);
5054 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5055 check_invariants (iter);
5059 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5062 g_return_if_fail (iter != NULL);
5063 g_return_if_fail (tree != NULL);
5065 _gtk_text_btree_get_iter_at_char (tree,
5067 _gtk_text_btree_char_count (tree));
5068 check_invariants (iter);
5072 _gtk_text_iter_check (const GtkTextIter *iter)
5074 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5075 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5076 GtkTextLineSegment *byte_segment = NULL;
5077 GtkTextLineSegment *byte_any_segment = NULL;
5078 GtkTextLineSegment *char_segment = NULL;
5079 GtkTextLineSegment *char_any_segment = NULL;
5080 gboolean segments_updated;
5082 /* This function checks our class invariants for the Iter class. */
5084 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5086 if (real->chars_changed_stamp !=
5087 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5088 g_error ("iterator check failed: invalid iterator");
5090 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5091 g_error ("iterator check failed: both char and byte offsets are invalid");
5093 segments_updated = (real->segments_changed_stamp ==
5094 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5097 printf ("checking iter, segments %s updated, byte %d char %d\n",
5098 segments_updated ? "are" : "aren't",
5099 real->line_byte_offset,
5100 real->line_char_offset);
5103 if (segments_updated)
5105 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5106 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5108 if (real->segment->char_count == 0)
5109 g_error ("iterator check failed: segment is not indexable.");
5111 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5112 g_error ("segment char offset is not properly up-to-date");
5114 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5115 g_error ("segment byte offset is not properly up-to-date");
5117 if (real->segment_byte_offset >= 0 &&
5118 real->segment_byte_offset >= real->segment->byte_count)
5119 g_error ("segment byte offset is too large.");
5121 if (real->segment_char_offset >= 0 &&
5122 real->segment_char_offset >= real->segment->char_count)
5123 g_error ("segment char offset is too large.");
5126 if (real->line_byte_offset >= 0)
5128 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5129 &byte_segment, &byte_any_segment,
5130 &seg_byte_offset, &line_byte_offset);
5132 if (line_byte_offset != real->line_byte_offset)
5133 g_error ("wrong byte offset was stored in iterator");
5135 if (segments_updated)
5137 if (real->segment != byte_segment)
5138 g_error ("wrong segment was stored in iterator");
5140 if (real->any_segment != byte_any_segment)
5141 g_error ("wrong any_segment was stored in iterator");
5143 if (seg_byte_offset != real->segment_byte_offset)
5144 g_error ("wrong segment byte offset was stored in iterator");
5146 if (byte_segment->type == >k_text_char_type)
5149 p = byte_segment->body.chars + seg_byte_offset;
5151 if (!gtk_text_byte_begins_utf8_char (p))
5152 g_error ("broken iterator byte index pointed into the middle of a character");
5157 if (real->line_char_offset >= 0)
5159 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5160 &char_segment, &char_any_segment,
5161 &seg_char_offset, &line_char_offset);
5163 if (line_char_offset != real->line_char_offset)
5164 g_error ("wrong char offset was stored in iterator");
5166 if (segments_updated)
5168 if (real->segment != char_segment)
5169 g_error ("wrong segment was stored in iterator");
5171 if (real->any_segment != char_any_segment)
5172 g_error ("wrong any_segment was stored in iterator");
5174 if (seg_char_offset != real->segment_char_offset)
5175 g_error ("wrong segment char offset was stored in iterator");
5177 if (char_segment->type == >k_text_char_type)
5180 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5183 /* hmm, not likely to happen eh */
5184 if (!gtk_text_byte_begins_utf8_char (p))
5185 g_error ("broken iterator char offset pointed into the middle of a character");
5190 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5192 if (byte_segment != char_segment)
5193 g_error ("char and byte offsets did not point to the same segment");
5195 if (byte_any_segment != char_any_segment)
5196 g_error ("char and byte offsets did not point to the same any segment");
5198 /* Make sure the segment offsets are equivalent, if it's a char
5200 if (char_segment->type == >k_text_char_type)
5202 gint byte_offset = 0;
5203 gint char_offset = 0;
5204 while (char_offset < seg_char_offset)
5206 const char * start = char_segment->body.chars + byte_offset;
5207 byte_offset += g_utf8_next_char (start) - start;
5211 if (byte_offset != seg_byte_offset)
5212 g_error ("byte offset did not correspond to char offset");
5215 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5217 if (char_offset != seg_char_offset)
5218 g_error ("char offset did not correspond to byte offset");
5220 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5221 g_error ("byte index for iterator does not index the start of a character");
5225 if (real->cached_line_number >= 0)
5229 should_be = _gtk_text_line_get_number (real->line);
5230 if (real->cached_line_number != should_be)
5231 g_error ("wrong line number was cached");
5234 if (real->cached_char_index >= 0)
5236 if (real->line_char_offset >= 0) /* only way we can check it
5237 efficiently, not a real
5242 char_index = _gtk_text_line_char_index (real->line);
5243 char_index += real->line_char_offset;
5245 if (real->cached_char_index != char_index)
5246 g_error ("wrong char index was cached");
5250 if (_gtk_text_line_is_last (real->line, real->tree))
5251 g_error ("Iterator was on last line (past the end iterator)");