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_line_is_last (real->line, real->tree));
2007 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2008 g_assert (gtk_text_iter_is_end (iter));
2010 check_invariants (iter);
2018 at_last_indexable_segment (GtkTextRealIter *real)
2020 GtkTextLineSegment *seg;
2022 /* Return TRUE if there are no indexable segments after
2026 seg = real->segment->next;
2029 if (seg->char_count > 0)
2036 /* Goes back to the start of the next segment, even if
2037 * we're not at the start of the current segment (always
2038 * ends up on a different segment if it returns TRUE)
2041 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2043 /* Move to the start of the previous segment; if no previous
2044 * segment, to the last segment in the previous line. This is
2045 * inherently a bit inefficient due to the singly-linked list and
2046 * tree nodes, but we can't afford the RAM for doubly-linked.
2048 GtkTextRealIter *real;
2049 GtkTextLineSegment *seg;
2050 GtkTextLineSegment *any_seg;
2051 GtkTextLineSegment *prev_seg;
2052 GtkTextLineSegment *prev_any_seg;
2056 g_return_val_if_fail (iter != NULL, FALSE);
2058 real = gtk_text_iter_make_real (iter);
2063 check_invariants (iter);
2065 /* Find first segments in line */
2066 any_seg = real->line->segments;
2068 while (seg->char_count == 0)
2071 if (seg == real->segment)
2073 /* Could probably do this case faster by hand-coding the
2077 /* We were already at the start of a line;
2078 * go back to the previous line.
2080 if (gtk_text_iter_backward_line (iter))
2082 /* Go forward to last indexable segment in line. */
2083 while (!at_last_indexable_segment (real))
2084 _gtk_text_iter_forward_indexable_segment (iter);
2086 check_invariants (iter);
2091 return FALSE; /* We were at the start of the first line. */
2094 /* We must be in the middle of a line; so find the indexable
2095 * segment just before our current segment.
2097 g_assert (seg != real->segment);
2098 while (seg != real->segment)
2101 prev_any_seg = any_seg;
2103 any_seg = seg->next;
2105 while (seg->char_count == 0)
2109 g_assert (prev_seg != NULL);
2110 g_assert (prev_any_seg != NULL);
2111 g_assert (prev_seg->char_count > 0);
2113 /* We skipped the entire previous segment, plus any
2114 * chars we were into the current segment.
2116 if (real->segment_byte_offset >= 0)
2117 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2121 if (real->segment_char_offset >= 0)
2122 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2126 real->segment = prev_seg;
2127 real->any_segment = prev_any_seg;
2128 real->segment_byte_offset = 0;
2129 real->segment_char_offset = 0;
2131 if (bytes_skipped >= 0)
2133 if (real->line_byte_offset >= 0)
2135 real->line_byte_offset -= bytes_skipped;
2136 g_assert (real->line_byte_offset >= 0);
2140 real->line_byte_offset = -1;
2142 if (chars_skipped >= 0)
2144 if (real->line_char_offset >= 0)
2146 real->line_char_offset -= chars_skipped;
2147 g_assert (real->line_char_offset >= 0);
2150 if (real->cached_char_index >= 0)
2152 real->cached_char_index -= chars_skipped;
2153 g_assert (real->cached_char_index >= 0);
2158 real->line_char_offset = -1;
2159 real->cached_char_index = -1;
2162 /* line number is unchanged. */
2164 check_invariants (iter);
2170 * gtk_text_iter_forward_char:
2171 * @iter: an iterator
2173 * Moves @iter forward by one character offset. Note that images
2174 * embedded in the buffer occupy 1 character slot, so
2175 * gtk_text_iter_forward_char () may actually move onto an image instead
2176 * of a character, if you have images in your buffer. If @iter is the
2177 * end iterator or one character before it, @iter will now point at
2178 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2179 * convenience when writing loops.
2181 * Return value: whether the new position is the end iterator
2184 gtk_text_iter_forward_char (GtkTextIter *iter)
2186 GtkTextRealIter *real;
2188 g_return_val_if_fail (iter != NULL, FALSE);
2190 real = gtk_text_iter_make_real (iter);
2196 check_invariants (iter);
2197 return forward_char (real);
2202 * gtk_text_iter_backward_char:
2203 * @iter: an iterator
2205 * Moves backward by one character offset. Returns TRUE if movement
2206 * was possible; if @iter was the first in the buffer (character
2207 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2210 * Return value: whether movement was possible
2213 gtk_text_iter_backward_char (GtkTextIter *iter)
2215 g_return_val_if_fail (iter != NULL, FALSE);
2217 check_invariants (iter);
2219 return gtk_text_iter_backward_chars (iter, 1);
2223 Definitely we should try to linear scan as often as possible for
2224 movement within a single line, because we can't use the BTree to
2225 speed within-line searches up; for movement between lines, we would
2226 like to avoid the linear scan probably.
2228 Instead of using this constant, it might be nice to cache the line
2229 length in the iterator and linear scan if motion is within a single
2232 I guess you'd have to profile the various approaches.
2234 #define MAX_LINEAR_SCAN 150
2238 * gtk_text_iter_forward_chars:
2239 * @iter: an iterator
2240 * @count: number of characters to move, may be negative
2242 * Moves @count characters if possible (if @count would move past the
2243 * start or end of the buffer, moves to the start or end of the
2244 * buffer). The return value indicates whether the new position of
2245 * @iter is different from its original position, and dereferenceable
2246 * (the last iterator in the buffer is not dereferenceable). If @count
2247 * is 0, the function does nothing and returns FALSE.
2249 * Return value: whether @iter moved and is dereferenceable
2252 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2254 GtkTextRealIter *real;
2256 g_return_val_if_fail (iter != NULL, FALSE);
2258 FIX_OVERFLOWS (count);
2260 real = gtk_text_iter_make_real (iter);
2264 else if (count == 0)
2267 return gtk_text_iter_backward_chars (iter, 0 - count);
2268 else if (count < MAX_LINEAR_SCAN)
2270 check_invariants (iter);
2274 if (!forward_char (real))
2279 return forward_char (real);
2283 gint current_char_index;
2284 gint new_char_index;
2286 check_invariants (iter);
2288 current_char_index = gtk_text_iter_get_offset (iter);
2290 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2291 return FALSE; /* can't move forward */
2293 new_char_index = current_char_index + count;
2294 gtk_text_iter_set_offset (iter, new_char_index);
2296 check_invariants (iter);
2298 /* Return FALSE if we're on the non-dereferenceable end
2301 if (gtk_text_iter_is_end (iter))
2309 * gtk_text_iter_backward_chars:
2310 * @iter: an iterator
2311 * @count: number of characters to move
2313 * Moves @count characters backward, if possible (if @count would move
2314 * past the start or end of the buffer, moves to the start or end of
2315 * the buffer). The return value indicates whether the iterator moved
2316 * onto a dereferenceable position; if the iterator didn't move, or
2317 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2318 * the function does nothing and returns FALSE.
2320 * Return value: whether @iter moved and is dereferenceable
2324 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2326 GtkTextRealIter *real;
2328 g_return_val_if_fail (iter != NULL, FALSE);
2330 FIX_OVERFLOWS (count);
2332 real = gtk_text_iter_make_real (iter);
2336 else if (count == 0)
2339 return gtk_text_iter_forward_chars (iter, 0 - count);
2341 ensure_char_offsets (real);
2342 check_invariants (iter);
2344 if (count <= real->segment_char_offset)
2346 /* Optimize the within-segment case */
2347 g_assert (real->segment->char_count > 0);
2348 g_assert (real->segment->type == >k_text_char_type);
2350 real->segment_char_offset -= count;
2351 g_assert (real->segment_char_offset >= 0);
2353 if (real->line_byte_offset >= 0)
2355 gint new_byte_offset;
2358 new_byte_offset = 0;
2360 while (i < real->segment_char_offset)
2362 const char * start = real->segment->body.chars + new_byte_offset;
2363 new_byte_offset += g_utf8_next_char (start) - start;
2368 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2369 real->segment_byte_offset = new_byte_offset;
2372 real->line_char_offset -= count;
2374 adjust_char_index (real, 0 - count);
2376 check_invariants (iter);
2382 /* We need to go back into previous segments. For now,
2383 * just keep this really simple. FIXME
2384 * use backward_indexable_segment.
2386 if (TRUE || count > MAX_LINEAR_SCAN)
2388 gint current_char_index;
2389 gint new_char_index;
2391 current_char_index = gtk_text_iter_get_offset (iter);
2393 if (current_char_index == 0)
2394 return FALSE; /* can't move backward */
2396 new_char_index = current_char_index - count;
2397 if (new_char_index < 0)
2399 gtk_text_iter_set_offset (iter, new_char_index);
2401 check_invariants (iter);
2407 /* FIXME backward_indexable_segment here */
2416 /* These two can't be implemented efficiently (always have to use
2417 * a linear scan, since that's the only way to find all the non-text
2422 * gtk_text_iter_forward_text_chars:
2423 * @iter: a #GtkTextIter
2424 * @count: number of chars to move
2426 * Moves forward by @count text characters (pixbufs, widgets,
2427 * etc. do not count as characters for this). Equivalent to moving
2428 * through the results of gtk_text_iter_get_text (), rather than
2429 * gtk_text_iter_get_slice ().
2431 * Return value: whether @iter moved and is dereferenceable
2434 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2443 * gtk_text_iter_forward_text_chars:
2444 * @iter: a #GtkTextIter
2445 * @count: number of chars to move
2447 * Moves backward by @count text characters (pixbufs, widgets,
2448 * etc. do not count as characters for this). Equivalent to moving
2449 * through the results of gtk_text_iter_get_text (), rather than
2450 * gtk_text_iter_get_slice ().
2452 * Return value: whether @iter moved and is dereferenceable
2455 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2464 * gtk_text_iter_forward_line:
2465 * @iter: an iterator
2467 * Moves @iter to the start of the next line. Returns TRUE if there
2468 * was a next line to move to, and FALSE if @iter was simply moved to
2469 * the end of the buffer and is now not dereferenceable, or if @iter was
2470 * already at the end of the buffer.
2472 * Return value: whether @iter can be dereferenced
2475 gtk_text_iter_forward_line (GtkTextIter *iter)
2477 GtkTextRealIter *real;
2479 g_return_val_if_fail (iter != NULL, FALSE);
2481 real = gtk_text_iter_make_real (iter);
2486 check_invariants (iter);
2488 if (forward_line_leaving_caches_unmodified (real))
2490 invalidate_char_index (real);
2491 adjust_line_number (real, 1);
2493 check_invariants (iter);
2495 if (gtk_text_iter_is_end (iter))
2502 /* On the last line, move to end of it */
2504 if (!gtk_text_iter_is_end (iter))
2505 gtk_text_iter_forward_to_end (iter);
2507 check_invariants (iter);
2513 * gtk_text_iter_backward_line:
2514 * @iter: an iterator
2516 * Moves @iter to the start of the previous line. Returns TRUE if
2517 * @iter could be moved; i.e. if @iter was at character offset 0, this
2518 * function returns FALSE. Therefore if @iter was already on line 0,
2519 * but not at the start of the line, @iter is snapped to the start of
2520 * the line and the function returns TRUE. (Note that this implies that
2521 * in a loop calling this function, the line number may not change on
2522 * every iteration, if your first iteration is on line 0.)
2524 * Return value: whether @iter moved
2527 gtk_text_iter_backward_line (GtkTextIter *iter)
2529 GtkTextLine *new_line;
2530 GtkTextRealIter *real;
2531 gboolean offset_will_change;
2534 g_return_val_if_fail (iter != NULL, FALSE);
2536 real = gtk_text_iter_make_real (iter);
2541 check_invariants (iter);
2543 new_line = _gtk_text_line_previous (real->line);
2545 offset_will_change = FALSE;
2546 if (real->line_char_offset > 0)
2547 offset_will_change = TRUE;
2549 if (new_line != NULL)
2551 real->line = new_line;
2553 adjust_line_number (real, -1);
2557 if (!offset_will_change)
2561 invalidate_char_index (real);
2563 real->line_byte_offset = 0;
2564 real->line_char_offset = 0;
2566 real->segment_byte_offset = 0;
2567 real->segment_char_offset = 0;
2569 /* Find first segment in line */
2570 real->any_segment = real->line->segments;
2571 real->segment = _gtk_text_line_byte_to_segment (real->line,
2574 g_assert (offset == 0);
2576 /* Note that if we are on the first line, we snap to the start of
2577 * the first line and return TRUE, so TRUE means the iterator
2578 * changed, not that the line changed; this is maybe a bit
2579 * weird. I'm not sure there's an obvious right thing to do though.
2582 check_invariants (iter);
2589 * gtk_text_iter_forward_lines:
2590 * @iter: a #GtkTextIter
2591 * @count: number of lines to move forward
2593 * Moves @count lines forward, if possible (if @count would move
2594 * past the start or end of the buffer, moves to the start or end of
2595 * the buffer). The return value indicates whether the iterator moved
2596 * onto a dereferenceable position; if the iterator didn't move, or
2597 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2598 * the function does nothing and returns FALSE. If @count is negative,
2599 * moves backward by 0 - @count lines.
2601 * Return value: whether @iter moved and is dereferenceable
2604 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2606 FIX_OVERFLOWS (count);
2609 return gtk_text_iter_backward_lines (iter, 0 - count);
2610 else if (count == 0)
2612 else if (count == 1)
2614 check_invariants (iter);
2615 return gtk_text_iter_forward_line (iter);
2621 old_line = gtk_text_iter_get_line (iter);
2623 gtk_text_iter_set_line (iter, old_line + count);
2625 check_invariants (iter);
2627 /* return whether it moved, and is dereferenceable. */
2629 (gtk_text_iter_get_line (iter) != old_line) &&
2630 !gtk_text_iter_is_end (iter);
2635 * gtk_text_iter_backward_lines:
2636 * @iter: a #GtkTextIter
2637 * @count: number of lines to move backward
2639 * Moves @count lines backward, if possible (if @count would move
2640 * past the start or end of the buffer, moves to the start or end of
2641 * the buffer). The return value indicates whether the iterator moved
2642 * onto a dereferenceable position; if the iterator didn't move, or
2643 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2644 * the function does nothing and returns FALSE. If @count is negative,
2645 * moves forward by 0 - @count lines.
2647 * Return value: whether @iter moved and is dereferenceable
2650 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2652 FIX_OVERFLOWS (count);
2655 return gtk_text_iter_forward_lines (iter, 0 - count);
2656 else if (count == 0)
2658 else if (count == 1)
2660 return gtk_text_iter_backward_line (iter);
2666 old_line = gtk_text_iter_get_line (iter);
2668 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2670 return (gtk_text_iter_get_line (iter) != old_line);
2674 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2679 gboolean already_moved_initially);
2681 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2689 find_word_end_func (const PangoLogAttr *attrs,
2694 gboolean already_moved_initially)
2696 if (!already_moved_initially)
2699 /* Find end of next word */
2700 while (offset < min_offset + len &&
2701 !attrs[offset].is_word_end)
2704 *found_offset = offset;
2706 return offset < min_offset + len;
2710 is_word_end_func (const PangoLogAttr *attrs,
2715 return attrs[offset].is_word_end;
2719 find_word_start_func (const PangoLogAttr *attrs,
2724 gboolean already_moved_initially)
2726 if (!already_moved_initially)
2729 /* Find start of prev word */
2730 while (offset >= min_offset &&
2731 !attrs[offset].is_word_start)
2734 *found_offset = offset;
2736 return offset >= min_offset;
2740 is_word_start_func (const PangoLogAttr *attrs,
2745 return attrs[offset].is_word_start;
2749 inside_word_func (const PangoLogAttr *attrs,
2754 /* Find next word start or end */
2755 while (offset >= min_offset &&
2756 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2759 return attrs[offset].is_word_start;
2762 /* Sentence funcs */
2765 find_sentence_end_func (const PangoLogAttr *attrs,
2770 gboolean already_moved_initially)
2772 if (!already_moved_initially)
2775 /* Find end of next sentence */
2776 while (offset < min_offset + len &&
2777 !attrs[offset].is_sentence_end)
2780 *found_offset = offset;
2782 return offset < min_offset + len;
2786 is_sentence_end_func (const PangoLogAttr *attrs,
2791 return attrs[offset].is_sentence_end;
2795 find_sentence_start_func (const PangoLogAttr *attrs,
2800 gboolean already_moved_initially)
2802 if (!already_moved_initially)
2805 /* Find start of prev sentence */
2806 while (offset >= min_offset &&
2807 !attrs[offset].is_sentence_start)
2810 *found_offset = offset;
2812 return offset >= min_offset;
2816 is_sentence_start_func (const PangoLogAttr *attrs,
2821 return attrs[offset].is_sentence_start;
2825 inside_sentence_func (const PangoLogAttr *attrs,
2830 /* Find next sentence start or end */
2831 while (offset >= min_offset &&
2832 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2835 return attrs[offset].is_sentence_start;
2839 test_log_attrs (const GtkTextIter *iter,
2840 TestLogAttrFunc func)
2843 const PangoLogAttr *attrs;
2845 gboolean result = FALSE;
2847 g_return_val_if_fail (iter != NULL, FALSE);
2849 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2852 offset = gtk_text_iter_get_line_offset (iter);
2854 /* char_len may be 0 and attrs will be NULL if so, if
2855 * iter is the end iter and the last line is empty
2858 if (offset < char_len)
2859 result = (* func) (attrs, offset, 0, char_len);
2865 find_line_log_attrs (const GtkTextIter *iter,
2866 FindLogAttrFunc func,
2868 gboolean already_moved_initially)
2871 const PangoLogAttr *attrs;
2873 gboolean result = FALSE;
2875 g_return_val_if_fail (iter != NULL, FALSE);
2877 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2880 offset = gtk_text_iter_get_line_offset (iter);
2882 /* char_len may be 0 and attrs will be NULL if so, if
2883 * iter is the end iter and the last line is empty
2887 result = (* func) (attrs, offset, 0, char_len, found_offset,
2888 already_moved_initially);
2893 /* FIXME this function is very, very gratuitously slow */
2895 find_by_log_attrs (GtkTextIter *iter,
2896 FindLogAttrFunc func,
2898 gboolean already_moved_initially)
2902 gboolean found = FALSE;
2904 g_return_val_if_fail (iter != NULL, FALSE);
2908 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2914 if (gtk_text_iter_forward_line (iter))
2915 return find_by_log_attrs (iter, func, forward,
2922 /* go to end of previous line. need to check that
2923 * line is > 0 because backward_line snaps to start of
2924 * line 0 if it's on line 0
2926 if (gtk_text_iter_get_line (iter) > 0 &&
2927 gtk_text_iter_backward_line (iter))
2929 if (!gtk_text_iter_ends_line (iter))
2930 gtk_text_iter_forward_to_line_end (iter);
2932 return find_by_log_attrs (iter, func, forward,
2941 gtk_text_iter_set_line_offset (iter, offset);
2944 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2945 !gtk_text_iter_is_end (iter);
2950 * gtk_text_iter_forward_word_end:
2951 * @iter: a #GtkTextIter
2953 * Moves forward to the next word end. (If @iter is currently on a
2954 * word end, moves forward to the next one after that.) Word breaks
2955 * are determined by Pango and should be correct for nearly any
2956 * language (if not, the correct fix would be to the Pango word break
2959 * Return value: %TRUE if @iter moved and is not the end iterator
2962 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2964 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2968 * gtk_text_iter_backward_word_start:
2969 * @iter: a #GtkTextIter
2971 * Moves backward to the next word start. (If @iter is currently on a
2972 * word start, moves backward to the next one after that.) Word breaks
2973 * are determined by Pango and should be correct for nearly any
2974 * language (if not, the correct fix would be to the Pango word break
2977 * Return value: %TRUE if @iter moved and is not the end iterator
2980 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2982 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2985 /* FIXME a loop around a truly slow function means
2986 * a truly spectacularly slow function.
2990 * gtk_text_iter_forward_word_ends:
2991 * @iter: a #GtkTextIter
2992 * @count: number of times to move
2994 * Calls gtk_text_iter_forward_word_end() up to @count times.
2996 * Return value: %TRUE if @iter moved and is not the end iterator
2999 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3002 g_return_val_if_fail (iter != NULL, FALSE);
3004 FIX_OVERFLOWS (count);
3010 return gtk_text_iter_backward_word_starts (iter, -count);
3012 if (!gtk_text_iter_forward_word_end (iter))
3018 if (!gtk_text_iter_forward_word_end (iter))
3026 * gtk_text_iter_backward_word_starts
3027 * @iter: a #GtkTextIter
3028 * @count: number of times to move
3030 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3032 * Return value: %TRUE if @iter moved and is not the end iterator
3035 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3038 g_return_val_if_fail (iter != NULL, FALSE);
3040 FIX_OVERFLOWS (count);
3043 return gtk_text_iter_forward_word_ends (iter, -count);
3045 if (!gtk_text_iter_backward_word_start (iter))
3051 if (!gtk_text_iter_backward_word_start (iter))
3059 * gtk_text_iter_starts_word:
3060 * @iter: a #GtkTextIter
3062 * Determines whether @iter begins a natural-language word. Word
3063 * breaks are determined by Pango and should be correct for nearly any
3064 * language (if not, the correct fix would be to the Pango word break
3067 * Return value: %TRUE if @iter is at the start of a word
3070 gtk_text_iter_starts_word (const GtkTextIter *iter)
3072 return test_log_attrs (iter, is_word_start_func);
3076 * gtk_text_iter_ends_word:
3077 * @iter: a #GtkTextIter
3079 * Determines whether @iter ends a natural-language word. Word breaks
3080 * are determined by Pango and should be correct for nearly any
3081 * language (if not, the correct fix would be to the Pango word break
3084 * Return value: %TRUE if @iter is at the end of a word
3087 gtk_text_iter_ends_word (const GtkTextIter *iter)
3089 return test_log_attrs (iter, is_word_end_func);
3093 * gtk_text_iter_inside_word:
3094 * @iter: a #GtkTextIter
3096 * Determines whether @iter is inside a natural-language word (as
3097 * opposed to say inside some whitespace). Word breaks are determined
3098 * by Pango and should be correct for nearly any language (if not, the
3099 * correct fix would be to the Pango word break algorithms).
3101 * Return value: %TRUE if @iter is inside a word
3104 gtk_text_iter_inside_word (const GtkTextIter *iter)
3106 return test_log_attrs (iter, inside_word_func);
3110 * gtk_text_iter_starts_sentence:
3111 * @iter: a #GtkTextIter
3113 * Determines whether @iter begins a sentence. Sentence boundaries are
3114 * determined by Pango and should be correct for nearly any language
3115 * (if not, the correct fix would be to the Pango text boundary
3118 * Return value: %TRUE if @iter is at the start of a sentence.
3121 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3123 return test_log_attrs (iter, is_sentence_start_func);
3127 * gtk_text_iter_ends_sentence:
3128 * @iter: a #GtkTextIter
3130 * Determines whether @iter ends a sentence. Sentence boundaries are
3131 * determined by Pango and should be correct for nearly any language
3132 * (if not, the correct fix would be to the Pango text boundary
3135 * Return value: %TRUE if @iter is at the end of a sentence.
3138 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3140 return test_log_attrs (iter, is_sentence_end_func);
3144 * gtk_text_iter_inside_sentence:
3145 * @iter: a #GtkTextIter
3147 * Determines whether @iter is inside a sentence (as opposed to in
3148 * between two sentences, e.g. after a period and before the first
3149 * letter of the next sentence). Sentence boundaries are determined
3150 * by Pango and should be correct for nearly any language (if not, the
3151 * correct fix would be to the Pango text boundary algorithms).
3153 * Return value: %TRUE if @iter is inside a sentence.
3156 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3158 return test_log_attrs (iter, inside_sentence_func);
3162 * gtk_text_iter_forward_sentence_end:
3163 * @iter: a #GtkTextIter
3165 * Moves forward to the next sentence end. (If @iter is at the end of
3166 * a sentence, moves to the next end of sentence.) Sentence
3167 * boundaries are determined by Pango and should be correct for nearly
3168 * any language (if not, the correct fix would be to the Pango text
3169 * boundary algorithms).
3171 * Return value: %TRUE if @iter moved and is not the end iterator
3174 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3176 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3180 * gtk_text_iter_backward_sentence_start:
3181 * @iter: a #GtkTextIter
3183 * Moves backward to the next sentence start; if @iter is already at
3184 * the start of a sentence, moves backward to the next one. Sentence
3185 * boundaries are determined by Pango and should be correct for nearly
3186 * any language (if not, the correct fix would be to the Pango text
3187 * boundary algorithms).
3189 * Return value: %TRUE if @iter moved and is not the end iterator
3192 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3194 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3197 /* FIXME a loop around a truly slow function means
3198 * a truly spectacularly slow function.
3201 * gtk_text_iter_forward_sentence_ends:
3202 * @iter: a #GtkTextIter
3203 * @count: number of sentences to move
3205 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3206 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3207 * negative, moves backward instead of forward.
3209 * Return value: %TRUE if @iter moved and is not the end iterator
3212 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3215 g_return_val_if_fail (iter != NULL, FALSE);
3221 return gtk_text_iter_backward_sentence_starts (iter, -count);
3223 if (!gtk_text_iter_forward_sentence_end (iter))
3229 if (!gtk_text_iter_forward_sentence_end (iter))
3237 * gtk_text_iter_backward_sentence_starts:
3238 * @iter: a #GtkTextIter
3239 * @count: number of sentences to move
3241 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3242 * or until it returns %FALSE. If @count is negative, moves forward
3243 * instead of backward.
3245 * Return value: %TRUE if @iter moved and is not the end iterator
3248 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3251 g_return_val_if_fail (iter != NULL, FALSE);
3254 return gtk_text_iter_forward_sentence_ends (iter, -count);
3256 if (!gtk_text_iter_backward_sentence_start (iter))
3262 if (!gtk_text_iter_backward_sentence_start (iter))
3270 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3275 gboolean already_moved_initially)
3277 if (!already_moved_initially)
3280 while (offset < (min_offset + len) &&
3281 !attrs[offset].is_cursor_position)
3284 *found_offset = offset;
3286 return offset < (min_offset + len);
3290 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3295 gboolean already_moved_initially)
3297 if (!already_moved_initially)
3300 while (offset > min_offset &&
3301 !attrs[offset].is_cursor_position)
3304 *found_offset = offset;
3306 return offset >= min_offset;
3310 is_cursor_pos_func (const PangoLogAttr *attrs,
3315 return attrs[offset].is_cursor_position;
3319 * gtk_text_iter_forward_cursor_position:
3320 * @iter: a #GtkTextIter
3322 * Moves @iter forward by a single cursor position. Cursor positions
3323 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3324 * surprisingly, there may not be a cursor position between all
3325 * characters. The most common example for European languages would be
3326 * a carriage return/newline sequence. For some Unicode characters,
3327 * the equivalent of say the letter "a" with an accent mark will be
3328 * represented as two characters, first the letter then a "combining
3329 * mark" that causes the accent to be rendered; so the cursor can't go
3330 * between those two characters. See also the #PangoLogAttr structure and
3331 * pango_break() function.
3333 * Return value: %TRUE if we moved and the new position is dereferenceable
3336 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3338 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3342 * gtk_text_iter_backward_cursor_position:
3343 * @iter: a #GtkTextIter
3345 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3347 * Return value: %TRUE if we moved and the new position is dereferenceable
3350 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3352 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3356 * gtk_text_iter_forward_cursor_positions:
3357 * @iter: a #GtkTextIter
3358 * @count: number of positions to move
3360 * Moves up to @count cursor positions. See
3361 * gtk_text_iter_forward_cursor_position() for details.
3363 * Return value: %TRUE if we moved and the new position is dereferenceable
3366 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3369 g_return_val_if_fail (iter != NULL, FALSE);
3371 FIX_OVERFLOWS (count);
3377 return gtk_text_iter_backward_cursor_positions (iter, -count);
3379 if (!gtk_text_iter_forward_cursor_position (iter))
3385 if (!gtk_text_iter_forward_cursor_position (iter))
3393 * gtk_text_iter_backward_cursor_positions:
3394 * @iter: a #GtkTextIter
3395 * @count: number of positions to move
3397 * Moves up to @count cursor positions. See
3398 * gtk_text_iter_forward_cursor_position() for details.
3400 * Return value: %TRUE if we moved and the new position is dereferenceable
3403 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3406 g_return_val_if_fail (iter != NULL, FALSE);
3408 FIX_OVERFLOWS (count);
3414 return gtk_text_iter_forward_cursor_positions (iter, -count);
3416 if (!gtk_text_iter_backward_cursor_position (iter))
3422 if (!gtk_text_iter_backward_cursor_position (iter))
3430 * gtk_text_iter_is_cursor_position:
3431 * @iter: a #GtkTextIter
3433 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3434 * pango_break() for details on what a cursor position is.
3436 * Return value: %TRUE if the cursor can be placed at @iter
3439 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3441 return test_log_attrs (iter, is_cursor_pos_func);
3445 * gtk_text_iter_set_line_offset:
3446 * @iter: a #GtkTextIter
3447 * @char_on_line: a character offset relative to the start of @iter's current line
3449 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3450 * (not byte) offset. The given character offset must be less than or
3451 * equal to the number of characters in the line; if equal, @iter
3452 * moves to the start of the next line. See
3453 * gtk_text_iter_set_line_index() if you have a byte index rather than
3454 * a character offset.
3458 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3461 GtkTextRealIter *real;
3464 g_return_if_fail (iter != NULL);
3466 real = gtk_text_iter_make_surreal (iter);
3471 check_invariants (iter);
3473 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3475 g_return_if_fail (char_on_line <= chars_in_line);
3477 if (char_on_line < chars_in_line)
3478 iter_set_from_char_offset (real, real->line, char_on_line);
3480 gtk_text_iter_forward_line (iter); /* set to start of next line */
3482 check_invariants (iter);
3486 * gtk_text_iter_set_line_index:
3487 * @iter: a #GtkTextIter
3488 * @byte_on_line: a byte index relative to the start of @iter's current line
3490 * Same as gtk_text_iter_set_line_offset(), but works with a
3491 * <emphasis>byte</emphasis> index. The given byte index must be at
3492 * the start of a character, it can't be in the middle of a UTF-8
3493 * encoded character.
3497 gtk_text_iter_set_line_index (GtkTextIter *iter,
3500 GtkTextRealIter *real;
3503 g_return_if_fail (iter != NULL);
3505 real = gtk_text_iter_make_surreal (iter);
3510 check_invariants (iter);
3512 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3514 g_return_if_fail (byte_on_line <= bytes_in_line);
3516 if (byte_on_line < bytes_in_line)
3517 iter_set_from_byte_offset (real, real->line, byte_on_line);
3519 gtk_text_iter_forward_line (iter);
3521 if (real->segment->type == >k_text_char_type &&
3522 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3523 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3524 "character; this will crash the text buffer. "
3525 "Byte indexes must refer to the start of a character.",
3526 G_STRLOC, byte_on_line);
3528 check_invariants (iter);
3533 * gtk_text_iter_set_visible_line_offset:
3534 * @iter: a #GtkTextIter
3535 * @char_on_line: a character offset
3537 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3538 * characters, i.e. text with a tag making it invisible is not
3539 * counted in the offset.
3542 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3545 gint chars_seen = 0;
3548 g_return_if_fail (iter != NULL);
3552 /* For now we use a ludicrously slow implementation */
3553 while (chars_seen < char_on_line)
3555 if (!_gtk_text_btree_char_is_invisible (&pos))
3558 if (!gtk_text_iter_forward_char (&pos))
3561 if (chars_seen == char_on_line)
3565 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3568 gtk_text_iter_forward_line (iter);
3572 bytes_in_char (GtkTextIter *iter)
3574 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3578 * gtk_text_iter_set_visible_line_index:
3579 * @iter: a #GtkTextIter
3580 * @byte_on_line: a byte index
3582 * Like gtk_text_iter_set_line_index(), but the index is in visible
3583 * bytes, i.e. text with a tag making it invisible is not counted
3587 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3590 gint bytes_seen = 0;
3593 g_return_if_fail (iter != NULL);
3597 /* For now we use a ludicrously slow implementation */
3598 while (bytes_seen < byte_on_line)
3600 if (!_gtk_text_btree_char_is_invisible (&pos))
3601 bytes_seen += bytes_in_char (&pos);
3603 if (!gtk_text_iter_forward_char (&pos))
3606 if (bytes_seen >= byte_on_line)
3610 if (bytes_seen > byte_on_line)
3611 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3612 "character; this will crash the text buffer. "
3613 "Byte indexes must refer to the start of a character.",
3614 G_STRLOC, byte_on_line);
3616 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3619 gtk_text_iter_forward_line (iter);
3623 * gtk_text_iter_set_line:
3624 * @iter: a #GtkTextIter
3625 * @line_number: line number (counted from 0)
3627 * Moves iterator @iter to the start of the line @line_number.
3631 gtk_text_iter_set_line (GtkTextIter *iter,
3636 GtkTextRealIter *real;
3638 g_return_if_fail (iter != NULL);
3640 real = gtk_text_iter_make_surreal (iter);
3645 check_invariants (iter);
3647 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3649 iter_set_from_char_offset (real, line, 0);
3651 /* We might as well cache this, since we know it. */
3652 real->cached_line_number = real_line;
3654 check_invariants (iter);
3658 * gtk_text_iter_set_offset:
3659 * @iter: a #GtkTextIter
3660 * @char_offset: a character number
3662 * Sets @iter to point to @char_offset. @char_offset counts from the start
3663 * of the entire text buffer, starting with 0.
3667 gtk_text_iter_set_offset (GtkTextIter *iter,
3671 GtkTextRealIter *real;
3673 gint real_char_index;
3675 g_return_if_fail (iter != NULL);
3677 real = gtk_text_iter_make_surreal (iter);
3682 check_invariants (iter);
3684 if (real->cached_char_index >= 0 &&
3685 real->cached_char_index == char_offset)
3688 line = _gtk_text_btree_get_line_at_char (real->tree,
3693 iter_set_from_char_offset (real, line, real_char_index - line_start);
3695 /* Go ahead and cache this since we have it. */
3696 real->cached_char_index = real_char_index;
3698 check_invariants (iter);
3702 * gtk_text_iter_forward_to_end:
3703 * @iter: a #GtkTextIter
3705 * Moves @iter forward to the "end iterator," which points one past the last
3706 * valid character in the buffer. gtk_text_iter_get_char() called on the
3707 * end iterator returns 0, which is convenient for writing loops.
3711 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3713 GtkTextBuffer *buffer;
3714 GtkTextRealIter *real;
3716 g_return_if_fail (iter != NULL);
3718 real = gtk_text_iter_make_surreal (iter);
3723 buffer = _gtk_text_btree_get_buffer (real->tree);
3725 gtk_text_buffer_get_end_iter (buffer, iter);
3729 * gtk_text_iter_forward_to_line_end:
3730 * @iter: a #GtkTextIter
3732 * Moves the iterator to point to the paragraph delimiter characters,
3733 * which will be either a newline, a carriage return, a carriage
3734 * return/newline in sequence, or the Unicode paragraph separator
3735 * character. If the iterator is already at the paragraph delimiter
3736 * characters, moves to the paragraph delimiter characters for the
3739 * Return value: %TRUE if we moved and the new location is not the end iterator
3742 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3744 gint current_offset;
3747 g_return_val_if_fail (iter != NULL, FALSE);
3749 current_offset = gtk_text_iter_get_line_offset (iter);
3750 /* FIXME assumption that line ends in a newline; broken */
3751 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3753 if (current_offset < new_offset)
3755 /* Move to end of this line. */
3756 gtk_text_iter_set_line_offset (iter, new_offset);
3761 /* Move to end of next line. */
3762 if (gtk_text_iter_forward_line (iter))
3764 /* We don't want to move past all
3767 if (!gtk_text_iter_ends_line (iter))
3768 gtk_text_iter_forward_to_line_end (iter);
3777 * gtk_text_iter_forward_to_tag_toggle:
3778 * @iter: a #GtkTextIter
3779 * @tag: a #GtkTextTag, or NULL
3781 * Moves forward to the next toggle (on or off) of the
3782 * #GtkTextTag @tag, or to the next toggle of any tag if
3783 * @tag is NULL. If no matching tag toggles are found,
3784 * returns FALSE, otherwise TRUE. Does not return toggles
3785 * located at @iter, only toggles after @iter. Sets @iter to
3786 * the location of the toggle, or to the end of the buffer
3787 * if no toggle is found.
3789 * Return value: whether we found a tag toggle after @iter
3792 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3795 GtkTextLine *next_line;
3796 GtkTextLine *current_line;
3797 GtkTextRealIter *real;
3799 g_return_val_if_fail (iter != NULL, FALSE);
3801 real = gtk_text_iter_make_real (iter);
3806 check_invariants (iter);
3808 current_line = real->line;
3809 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3812 while (_gtk_text_iter_forward_indexable_segment (iter))
3814 /* If we went forward to a line that couldn't contain a toggle
3815 for the tag, then skip forward to a line that could contain
3816 it. This potentially skips huge hunks of the tree, so we
3817 aren't a purely linear search. */
3818 if (real->line != current_line)
3820 if (next_line == NULL)
3822 /* End of search. Set to end of buffer. */
3823 _gtk_text_btree_get_end_iter (real->tree, iter);
3827 if (real->line != next_line)
3828 iter_set_from_byte_offset (real, next_line, 0);
3830 current_line = real->line;
3831 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3836 if (gtk_text_iter_toggles_tag (iter, tag))
3838 /* If there's a toggle here, it isn't indexable so
3839 any_segment can't be the indexable segment. */
3840 g_assert (real->any_segment != real->segment);
3845 /* Check end iterator for tags */
3846 if (gtk_text_iter_toggles_tag (iter, tag))
3848 /* If there's a toggle here, it isn't indexable so
3849 any_segment can't be the indexable segment. */
3850 g_assert (real->any_segment != real->segment);
3854 /* Reached end of buffer */
3859 * gtk_text_iter_backward_to_tag_toggle:
3860 * @iter: a #GtkTextIter
3861 * @tag: a #GtkTextTag, or NULL
3863 * Moves backward to the next toggle (on or off) of the
3864 * #GtkTextTag @tag, or to the next toggle of any tag if
3865 * @tag is NULL. If no matching tag toggles are found,
3866 * returns FALSE, otherwise TRUE. Does not return toggles
3867 * located at @iter, only toggles before @iter. Sets @iter
3868 * to the location of the toggle, or the start of the buffer
3869 * if no toggle is found.
3871 * Return value: whether we found a tag toggle before @iter
3874 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3877 GtkTextLine *prev_line;
3878 GtkTextLine *current_line;
3879 GtkTextRealIter *real;
3881 g_return_val_if_fail (iter != NULL, FALSE);
3883 real = gtk_text_iter_make_real (iter);
3888 check_invariants (iter);
3890 current_line = real->line;
3891 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3895 /* If we're at segment start, go to the previous segment;
3896 * if mid-segment, snap to start of current segment.
3898 if (is_segment_start (real))
3900 if (!_gtk_text_iter_backward_indexable_segment (iter))
3905 ensure_char_offsets (real);
3907 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3913 /* If we went backward to a line that couldn't contain a toggle
3914 * for the tag, then skip backward further to a line that
3915 * could contain it. This potentially skips huge hunks of the
3916 * tree, so we aren't a purely linear search.
3918 if (real->line != current_line)
3920 if (prev_line == NULL)
3922 /* End of search. Set to start of buffer. */
3923 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3927 if (real->line != prev_line)
3929 /* Set to last segment in prev_line (could do this
3932 iter_set_from_byte_offset (real, prev_line, 0);
3934 while (!at_last_indexable_segment (real))
3935 _gtk_text_iter_forward_indexable_segment (iter);
3938 current_line = real->line;
3939 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3944 if (gtk_text_iter_toggles_tag (iter, tag))
3946 /* If there's a toggle here, it isn't indexable so
3947 * any_segment can't be the indexable segment.
3949 g_assert (real->any_segment != real->segment);
3953 while (_gtk_text_iter_backward_indexable_segment (iter));
3955 /* Reached front of buffer */
3960 matches_pred (GtkTextIter *iter,
3961 GtkTextCharPredicate pred,
3966 ch = gtk_text_iter_get_char (iter);
3968 return (*pred) (ch, user_data);
3972 * gtk_text_iter_forward_find_char:
3973 * @iter: a #GtkTextIter
3974 * @pred: a function to be called on each character
3975 * @user_data: user data for @pred
3976 * @limit: search limit, or %NULL for none
3978 * Advances @iter, calling @pred on each character. If
3979 * @pred returns %TRUE, returns %TRUE and stops scanning.
3980 * If @pred never returns %TRUE, @iter is set to @limit if
3981 * @limit is non-%NULL, otherwise to the end iterator.
3983 * Return value: whether a match was found
3986 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3987 GtkTextCharPredicate pred,
3989 const GtkTextIter *limit)
3991 g_return_val_if_fail (iter != NULL, FALSE);
3992 g_return_val_if_fail (pred != NULL, FALSE);
3995 gtk_text_iter_compare (iter, limit) >= 0)
3998 while ((limit == NULL ||
3999 !gtk_text_iter_equal (limit, iter)) &&
4000 gtk_text_iter_forward_char (iter))
4002 if (matches_pred (iter, pred, user_data))
4010 * gtk_text_iter_backward_find_char:
4011 * @iter: a #GtkTextIter
4012 * @pred: function to be called on each character
4013 * @user_data: user data for @pred
4014 * @limit: search limit, or %NULL for none
4016 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4018 * Return value: whether a match was found
4021 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4022 GtkTextCharPredicate pred,
4024 const GtkTextIter *limit)
4026 g_return_val_if_fail (iter != NULL, FALSE);
4027 g_return_val_if_fail (pred != NULL, FALSE);
4030 gtk_text_iter_compare (iter, limit) <= 0)
4033 while ((limit == NULL ||
4034 !gtk_text_iter_equal (limit, iter)) &&
4035 gtk_text_iter_backward_char (iter))
4037 if (matches_pred (iter, pred, user_data))
4045 forward_chars_with_skipping (GtkTextIter *iter,
4047 gboolean skip_invisible,
4048 gboolean skip_nontext)
4053 g_return_if_fail (count >= 0);
4059 gboolean ignored = FALSE;
4062 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4067 _gtk_text_btree_char_is_invisible (iter))
4070 gtk_text_iter_forward_char (iter);
4078 lines_match (const GtkTextIter *start,
4079 const gchar **lines,
4080 gboolean visible_only,
4082 GtkTextIter *match_start,
4083 GtkTextIter *match_end)
4090 if (*lines == NULL || **lines == '\0')
4093 *match_start = *start;
4096 *match_end = *start;
4101 gtk_text_iter_forward_line (&next);
4103 /* No more text in buffer, but *lines is nonempty */
4104 if (gtk_text_iter_equal (start, &next))
4112 line_text = gtk_text_iter_get_visible_slice (start, &next);
4114 line_text = gtk_text_iter_get_slice (start, &next);
4119 line_text = gtk_text_iter_get_visible_text (start, &next);
4121 line_text = gtk_text_iter_get_text (start, &next);
4124 if (match_start) /* if this is the first line we're matching */
4125 found = strstr (line_text, *lines);
4128 /* If it's not the first line, we have to match from the
4129 * start of the line.
4131 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4143 /* Get offset to start of search string */
4144 offset = g_utf8_strlen (line_text, found - line_text);
4148 /* If match start needs to be returned, set it to the
4149 * start of the search string.
4153 *match_start = next;
4155 forward_chars_with_skipping (match_start, offset,
4156 visible_only, !slice);
4159 /* Go to end of search string */
4160 offset += g_utf8_strlen (*lines, -1);
4162 forward_chars_with_skipping (&next, offset,
4163 visible_only, !slice);
4172 /* pass NULL for match_start, since we don't need to find the
4175 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4178 /* strsplit () that retains the delimiter as part of the string. */
4180 strbreakup (const char *string,
4181 const char *delimiter,
4184 GSList *string_list = NULL, *slist;
4185 gchar **str_array, *s;
4188 g_return_val_if_fail (string != NULL, NULL);
4189 g_return_val_if_fail (delimiter != NULL, NULL);
4192 max_tokens = G_MAXINT;
4194 s = strstr (string, delimiter);
4197 guint delimiter_len = strlen (delimiter);
4204 len = s - string + delimiter_len;
4205 new_string = g_new (gchar, len + 1);
4206 strncpy (new_string, string, len);
4207 new_string[len] = 0;
4208 string_list = g_slist_prepend (string_list, new_string);
4210 string = s + delimiter_len;
4211 s = strstr (string, delimiter);
4213 while (--max_tokens && s);
4218 string_list = g_slist_prepend (string_list, g_strdup (string));
4221 str_array = g_new (gchar*, n);
4225 str_array[i--] = NULL;
4226 for (slist = string_list; slist; slist = slist->next)
4227 str_array[i--] = slist->data;
4229 g_slist_free (string_list);
4235 * gtk_text_iter_forward_search:
4236 * @iter: start of search
4237 * @str: a search string
4238 * @visible_only: if %TRUE, search only visible text
4239 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4240 * @match_start: return location for start of match, or %NULL
4241 * @match_end: return location for end of match, or %NULL
4242 * @limit: bound for the search, or %NULL for the end of the buffer
4244 * Searches forward for @str. Any match is returned as the range @match_start,
4245 * @match_end. If you specify @visible_only or @slice, the match may have
4246 * invisible text, pixbufs, or child widgets interspersed in @str.
4248 * Return value: whether a match was found
4251 gtk_text_iter_forward_search (const GtkTextIter *iter,
4253 gboolean visible_only,
4255 GtkTextIter *match_start,
4256 GtkTextIter *match_end,
4257 const GtkTextIter *limit)
4259 gchar **lines = NULL;
4261 gboolean retval = FALSE;
4264 g_return_val_if_fail (iter != NULL, FALSE);
4265 g_return_val_if_fail (str != NULL, FALSE);
4268 gtk_text_iter_compare (iter, limit) >= 0)
4273 /* If we can move one char, return the empty string there */
4276 if (gtk_text_iter_forward_char (&match))
4279 gtk_text_iter_equal (&match, limit))
4283 *match_start = match;
4292 /* locate all lines */
4294 lines = strbreakup (str, "\n", -1);
4300 /* This loop has an inefficient worst-case, where
4301 * gtk_text_iter_get_text () is called repeatedly on
4307 gtk_text_iter_compare (&search, limit) >= 0)
4310 if (lines_match (&search, (const gchar**)lines,
4311 visible_only, slice, &match, &end))
4313 if (limit == NULL ||
4315 gtk_text_iter_compare (&end, limit) < 0))
4320 *match_start = match;
4329 while (gtk_text_iter_forward_line (&search));
4331 g_strfreev ((gchar**)lines);
4337 vectors_equal_ignoring_trailing (gchar **vec1,
4340 /* Ignores trailing chars in vec2's last line */
4349 if (strcmp (*i1, *i2) != 0)
4351 if (*(i2 + 1) == NULL) /* if this is the last line */
4353 gint len1 = strlen (*i1);
4354 gint len2 = strlen (*i2);
4357 strncmp (*i1, *i2, len1) == 0)
4359 /* We matched ignoring the trailing stuff in vec2 */
4384 typedef struct _LinesWindow LinesWindow;
4390 GtkTextIter first_line_start;
4391 GtkTextIter first_line_end;
4393 gboolean visible_only;
4397 lines_window_init (LinesWindow *win,
4398 const GtkTextIter *start)
4401 GtkTextIter line_start;
4402 GtkTextIter line_end;
4404 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4407 if (gtk_text_iter_is_start (start) ||
4408 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4410 /* Already at the end, or not enough lines to match */
4411 win->lines = g_new0 (gchar*, 1);
4416 line_start = *start;
4419 /* Move to start iter to start of line */
4420 gtk_text_iter_set_line_offset (&line_start, 0);
4422 if (gtk_text_iter_equal (&line_start, &line_end))
4424 /* we were already at the start; so go back one line */
4425 gtk_text_iter_backward_line (&line_start);
4428 win->first_line_start = line_start;
4429 win->first_line_end = line_end;
4431 win->lines = g_new0 (gchar*, win->n_lines + 1);
4433 i = win->n_lines - 1;
4440 if (win->visible_only)
4441 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4443 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4447 if (win->visible_only)
4448 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4450 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4453 win->lines[i] = line_text;
4455 line_end = line_start;
4456 gtk_text_iter_backward_line (&line_start);
4463 lines_window_back (LinesWindow *win)
4465 GtkTextIter new_start;
4468 new_start = win->first_line_start;
4470 if (!gtk_text_iter_backward_line (&new_start))
4474 win->first_line_start = new_start;
4475 win->first_line_end = new_start;
4477 gtk_text_iter_forward_line (&win->first_line_end);
4482 if (win->visible_only)
4483 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4484 &win->first_line_end);
4486 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4487 &win->first_line_end);
4491 if (win->visible_only)
4492 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4493 &win->first_line_end);
4495 line_text = gtk_text_iter_get_text (&win->first_line_start,
4496 &win->first_line_end);
4499 /* Move lines to make room for first line. */
4500 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4502 *win->lines = line_text;
4504 /* Free old last line and NULL-terminate */
4505 g_free (win->lines[win->n_lines]);
4506 win->lines[win->n_lines] = NULL;
4512 lines_window_free (LinesWindow *win)
4514 g_strfreev (win->lines);
4518 my_strrstr (const gchar *haystack,
4519 const gchar *needle)
4521 /* FIXME GLib should have a nice implementation in it, this
4525 gint haystack_len = strlen (haystack);
4526 gint needle_len = strlen (needle);
4527 const gchar *needle_end = needle + needle_len;
4528 const gchar *haystack_rend = haystack - 1;
4529 const gchar *needle_rend = needle - 1;
4532 p = haystack + haystack_len;
4533 while (p != haystack)
4535 const gchar *n = needle_end - 1;
4536 const gchar *s = p - 1;
4537 while (s != haystack_rend &&
4545 if (n == needle_rend)
4555 * gtk_text_iter_backward_search:
4556 * @iter: a #GtkTextIter where the search begins
4557 * @str: search string
4558 * @visible_only: if %TRUE search only visible text
4559 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4560 * @match_start: return location for start of match, or %NULL
4561 * @match_end: return location for end of match, or %NULL
4562 * @limit: location of last possible @match_start, or %NULL for start of buffer
4564 * Same as gtk_text_iter_forward_search(), but moves backward.
4566 * Return value: whether a match was found
4569 gtk_text_iter_backward_search (const GtkTextIter *iter,
4571 gboolean visible_only,
4573 GtkTextIter *match_start,
4574 GtkTextIter *match_end,
4575 const GtkTextIter *limit)
4577 gchar **lines = NULL;
4581 gboolean retval = FALSE;
4583 g_return_val_if_fail (iter != NULL, FALSE);
4584 g_return_val_if_fail (str != NULL, FALSE);
4587 gtk_text_iter_compare (limit, iter) > 0)
4592 /* If we can move one char, return the empty string there */
4593 GtkTextIter match = *iter;
4595 if (limit && gtk_text_iter_equal (limit, &match))
4598 if (gtk_text_iter_backward_char (&match))
4601 *match_start = match;
4610 /* locate all lines */
4612 lines = strbreakup (str, "\n", -1);
4622 win.n_lines = n_lines;
4624 win.visible_only = visible_only;
4626 lines_window_init (&win, iter);
4628 if (*win.lines == NULL)
4633 gchar *first_line_match;
4636 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4638 /* We're now before the search limit, abort. */
4642 /* If there are multiple lines, the first line will
4643 * end in '\n', so this will only match at the
4644 * end of the first line, which is correct.
4646 first_line_match = my_strrstr (*win.lines, *lines);
4648 if (first_line_match &&
4649 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4654 GtkTextIter start_tmp;
4656 /* Offset to start of search string */
4657 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4659 next = win.first_line_start;
4661 forward_chars_with_skipping (&start_tmp, offset,
4662 visible_only, !slice);
4665 gtk_text_iter_compare (limit, &start_tmp) > 0)
4666 goto out; /* match was bogus */
4669 *match_start = start_tmp;
4671 /* Go to end of search string */
4675 offset += g_utf8_strlen (*l, -1);
4679 forward_chars_with_skipping (&next, offset,
4680 visible_only, !slice);
4689 while (lines_window_back (&win));
4692 lines_window_free (&win);
4703 * gtk_text_iter_equal:
4704 * @lhs: a #GtkTextIter
4705 * @rhs: another #GtkTextIter
4707 * Tests whether two iterators are equal, using the fastest possible
4708 * mechanism. This function is very fast; you can expect it to perform
4709 * better than e.g. getting the character offset for each iterator and
4710 * comparing the offsets yourself. Also, it's a bit faster than
4711 * gtk_text_iter_compare().
4713 * Return value: %TRUE if the iterators point to the same place in the buffer
4716 gtk_text_iter_equal (const GtkTextIter *lhs,
4717 const GtkTextIter *rhs)
4719 GtkTextRealIter *real_lhs;
4720 GtkTextRealIter *real_rhs;
4722 real_lhs = (GtkTextRealIter*)lhs;
4723 real_rhs = (GtkTextRealIter*)rhs;
4725 check_invariants (lhs);
4726 check_invariants (rhs);
4728 if (real_lhs->line != real_rhs->line)
4730 else if (real_lhs->line_byte_offset >= 0 &&
4731 real_rhs->line_byte_offset >= 0)
4732 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4735 /* the ensure_char_offsets () calls do nothing if the char offsets
4736 are already up-to-date. */
4737 ensure_char_offsets (real_lhs);
4738 ensure_char_offsets (real_rhs);
4739 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4744 * gtk_text_iter_compare:
4745 * @lhs: a #GtkTextIter
4746 * @rhs: another #GtkTextIter
4748 * A qsort()-style function that returns negative if @lhs is less than
4749 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4750 * Ordering is in character offset order, i.e. the first character in the buffer
4751 * is less than the second character in the buffer.
4753 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4756 gtk_text_iter_compare (const GtkTextIter *lhs,
4757 const GtkTextIter *rhs)
4759 GtkTextRealIter *real_lhs;
4760 GtkTextRealIter *real_rhs;
4762 real_lhs = gtk_text_iter_make_surreal (lhs);
4763 real_rhs = gtk_text_iter_make_surreal (rhs);
4765 if (real_lhs == NULL ||
4767 return -1; /* why not */
4769 check_invariants (lhs);
4770 check_invariants (rhs);
4772 if (real_lhs->line == real_rhs->line)
4774 gint left_index, right_index;
4776 if (real_lhs->line_byte_offset >= 0 &&
4777 real_rhs->line_byte_offset >= 0)
4779 left_index = real_lhs->line_byte_offset;
4780 right_index = real_rhs->line_byte_offset;
4784 /* the ensure_char_offsets () calls do nothing if
4785 the offsets are already up-to-date. */
4786 ensure_char_offsets (real_lhs);
4787 ensure_char_offsets (real_rhs);
4788 left_index = real_lhs->line_char_offset;
4789 right_index = real_rhs->line_char_offset;
4792 if (left_index < right_index)
4794 else if (left_index > right_index)
4803 line1 = gtk_text_iter_get_line (lhs);
4804 line2 = gtk_text_iter_get_line (rhs);
4807 else if (line1 > line2)
4815 * gtk_text_iter_in_range:
4816 * @iter: a #GtkTextIter
4817 * @start: start of range
4818 * @end: end of range
4820 * Checks whether @iter falls in the range [@start, @end).
4821 * @start and @end must be in ascending order.
4823 * Return value: %TRUE if @iter is in the range
4826 gtk_text_iter_in_range (const GtkTextIter *iter,
4827 const GtkTextIter *start,
4828 const GtkTextIter *end)
4830 g_return_val_if_fail (iter != NULL, FALSE);
4831 g_return_val_if_fail (start != NULL, FALSE);
4832 g_return_val_if_fail (end != NULL, FALSE);
4833 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4835 return gtk_text_iter_compare (iter, start) >= 0 &&
4836 gtk_text_iter_compare (iter, end) < 0;
4840 * gtk_text_iter_order:
4841 * @first: a #GtkTextIter
4842 * @second: another #GtkTextIter
4844 * Swaps the value of @first and @second if @second comes before
4845 * @first in the buffer. That is, ensures that @first and @second are
4846 * in sequence. Most text buffer functions that take a range call this
4847 * automatically on your behalf, so there's no real reason to call it yourself
4848 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4849 * that expect a pre-sorted range.
4853 gtk_text_iter_order (GtkTextIter *first,
4854 GtkTextIter *second)
4856 g_return_if_fail (first != NULL);
4857 g_return_if_fail (second != NULL);
4859 if (gtk_text_iter_compare (first, second) > 0)
4870 * Init iterators from the BTree
4874 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4878 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4879 gint real_char_index;
4883 g_return_if_fail (iter != NULL);
4884 g_return_if_fail (tree != NULL);
4886 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4887 &line_start, &real_char_index);
4889 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4891 real->cached_char_index = real_char_index;
4893 check_invariants (iter);
4897 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4902 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4906 g_return_if_fail (iter != NULL);
4907 g_return_if_fail (tree != NULL);
4909 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4911 iter_init_from_char_offset (iter, tree, line, char_on_line);
4913 /* We might as well cache this, since we know it. */
4914 real->cached_line_number = real_line;
4916 check_invariants (iter);
4920 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4925 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4929 g_return_if_fail (iter != NULL);
4930 g_return_if_fail (tree != NULL);
4932 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4934 iter_init_from_byte_offset (iter, tree, line, byte_index);
4936 /* We might as well cache this, since we know it. */
4937 real->cached_line_number = real_line;
4939 check_invariants (iter);
4943 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4948 g_return_if_fail (iter != NULL);
4949 g_return_if_fail (tree != NULL);
4950 g_return_if_fail (line != NULL);
4952 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4954 check_invariants (iter);
4958 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4964 g_return_val_if_fail (iter != NULL, FALSE);
4965 g_return_val_if_fail (tree != NULL, FALSE);
4967 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4971 /* Set iter to last in tree */
4972 _gtk_text_btree_get_end_iter (tree, iter);
4973 check_invariants (iter);
4978 iter_init_from_byte_offset (iter, tree, line, 0);
4979 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4980 check_invariants (iter);
4986 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4990 g_return_val_if_fail (iter != NULL, FALSE);
4991 g_return_val_if_fail (tree != NULL, FALSE);
4993 _gtk_text_btree_get_end_iter (tree, iter);
4994 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4995 check_invariants (iter);
5001 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5003 const gchar *mark_name)
5007 g_return_val_if_fail (iter != NULL, FALSE);
5008 g_return_val_if_fail (tree != NULL, FALSE);
5010 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5016 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5017 check_invariants (iter);
5023 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5027 GtkTextLineSegment *seg;
5029 g_return_if_fail (iter != NULL);
5030 g_return_if_fail (tree != NULL);
5031 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5033 seg = mark->segment;
5035 iter_init_from_segment (iter, tree,
5036 seg->body.mark.line, seg);
5037 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5038 check_invariants (iter);
5042 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5044 GtkTextChildAnchor *anchor)
5046 GtkTextLineSegment *seg;
5048 g_return_if_fail (iter != NULL);
5049 g_return_if_fail (tree != NULL);
5050 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5052 seg = anchor->segment;
5054 iter_init_from_segment (iter, tree,
5055 seg->body.child.line, seg);
5056 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5057 check_invariants (iter);
5061 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5064 g_return_if_fail (iter != NULL);
5065 g_return_if_fail (tree != NULL);
5067 _gtk_text_btree_get_iter_at_char (tree,
5069 _gtk_text_btree_char_count (tree));
5070 check_invariants (iter);
5074 _gtk_text_iter_check (const GtkTextIter *iter)
5076 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5077 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5078 GtkTextLineSegment *byte_segment = NULL;
5079 GtkTextLineSegment *byte_any_segment = NULL;
5080 GtkTextLineSegment *char_segment = NULL;
5081 GtkTextLineSegment *char_any_segment = NULL;
5082 gboolean segments_updated;
5084 /* This function checks our class invariants for the Iter class. */
5086 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5088 if (real->chars_changed_stamp !=
5089 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5090 g_error ("iterator check failed: invalid iterator");
5092 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5093 g_error ("iterator check failed: both char and byte offsets are invalid");
5095 segments_updated = (real->segments_changed_stamp ==
5096 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5099 printf ("checking iter, segments %s updated, byte %d char %d\n",
5100 segments_updated ? "are" : "aren't",
5101 real->line_byte_offset,
5102 real->line_char_offset);
5105 if (segments_updated)
5107 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5108 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5110 if (real->segment->char_count == 0)
5111 g_error ("iterator check failed: segment is not indexable.");
5113 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5114 g_error ("segment char offset is not properly up-to-date");
5116 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5117 g_error ("segment byte offset is not properly up-to-date");
5119 if (real->segment_byte_offset >= 0 &&
5120 real->segment_byte_offset >= real->segment->byte_count)
5121 g_error ("segment byte offset is too large.");
5123 if (real->segment_char_offset >= 0 &&
5124 real->segment_char_offset >= real->segment->char_count)
5125 g_error ("segment char offset is too large.");
5128 if (real->line_byte_offset >= 0)
5130 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5131 &byte_segment, &byte_any_segment,
5132 &seg_byte_offset, &line_byte_offset);
5134 if (line_byte_offset != real->line_byte_offset)
5135 g_error ("wrong byte offset was stored in iterator");
5137 if (segments_updated)
5139 if (real->segment != byte_segment)
5140 g_error ("wrong segment was stored in iterator");
5142 if (real->any_segment != byte_any_segment)
5143 g_error ("wrong any_segment was stored in iterator");
5145 if (seg_byte_offset != real->segment_byte_offset)
5146 g_error ("wrong segment byte offset was stored in iterator");
5148 if (byte_segment->type == >k_text_char_type)
5151 p = byte_segment->body.chars + seg_byte_offset;
5153 if (!gtk_text_byte_begins_utf8_char (p))
5154 g_error ("broken iterator byte index pointed into the middle of a character");
5159 if (real->line_char_offset >= 0)
5161 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5162 &char_segment, &char_any_segment,
5163 &seg_char_offset, &line_char_offset);
5165 if (line_char_offset != real->line_char_offset)
5166 g_error ("wrong char offset was stored in iterator");
5168 if (segments_updated)
5170 if (real->segment != char_segment)
5171 g_error ("wrong segment was stored in iterator");
5173 if (real->any_segment != char_any_segment)
5174 g_error ("wrong any_segment was stored in iterator");
5176 if (seg_char_offset != real->segment_char_offset)
5177 g_error ("wrong segment char offset was stored in iterator");
5179 if (char_segment->type == >k_text_char_type)
5182 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5185 /* hmm, not likely to happen eh */
5186 if (!gtk_text_byte_begins_utf8_char (p))
5187 g_error ("broken iterator char offset pointed into the middle of a character");
5192 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5194 if (byte_segment != char_segment)
5195 g_error ("char and byte offsets did not point to the same segment");
5197 if (byte_any_segment != char_any_segment)
5198 g_error ("char and byte offsets did not point to the same any segment");
5200 /* Make sure the segment offsets are equivalent, if it's a char
5202 if (char_segment->type == >k_text_char_type)
5204 gint byte_offset = 0;
5205 gint char_offset = 0;
5206 while (char_offset < seg_char_offset)
5208 const char * start = char_segment->body.chars + byte_offset;
5209 byte_offset += g_utf8_next_char (start) - start;
5213 if (byte_offset != seg_byte_offset)
5214 g_error ("byte offset did not correspond to char offset");
5217 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5219 if (char_offset != seg_char_offset)
5220 g_error ("char offset did not correspond to byte offset");
5222 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5223 g_error ("byte index for iterator does not index the start of a character");
5227 if (real->cached_line_number >= 0)
5231 should_be = _gtk_text_line_get_number (real->line);
5232 if (real->cached_line_number != should_be)
5233 g_error ("wrong line number was cached");
5236 if (real->cached_char_index >= 0)
5238 if (real->line_char_offset >= 0) /* only way we can check it
5239 efficiently, not a real
5244 char_index = _gtk_text_line_char_index (real->line);
5245 char_index += real->line_char_offset;
5247 if (real->cached_char_index != char_index)
5248 g_error ("wrong char index was cached");
5252 if (_gtk_text_line_is_last (real->line, real->tree))
5253 g_error ("Iterator was on last line (past the end iterator)");