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.
2857 * offset may be equal to char_len, since attrs contains an entry
2858 * for one past the end
2861 if (offset <= char_len)
2862 result = (* func) (attrs, offset, 0, char_len);
2868 find_line_log_attrs (const GtkTextIter *iter,
2869 FindLogAttrFunc func,
2871 gboolean already_moved_initially)
2874 const PangoLogAttr *attrs;
2876 gboolean result = FALSE;
2878 g_return_val_if_fail (iter != NULL, FALSE);
2880 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2883 offset = gtk_text_iter_get_line_offset (iter);
2885 /* char_len may be 0 and attrs will be NULL if so, if
2886 * iter is the end iter and the last line is empty
2890 result = (* func) (attrs, offset, 0, char_len, found_offset,
2891 already_moved_initially);
2896 /* FIXME this function is very, very gratuitously slow */
2898 find_by_log_attrs (GtkTextIter *iter,
2899 FindLogAttrFunc func,
2901 gboolean already_moved_initially)
2905 gboolean found = FALSE;
2907 g_return_val_if_fail (iter != NULL, FALSE);
2911 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2917 if (gtk_text_iter_forward_line (iter))
2918 return find_by_log_attrs (iter, func, forward,
2925 /* go to end of previous line. need to check that
2926 * line is > 0 because backward_line snaps to start of
2927 * line 0 if it's on line 0
2929 if (gtk_text_iter_get_line (iter) > 0 &&
2930 gtk_text_iter_backward_line (iter))
2932 if (!gtk_text_iter_ends_line (iter))
2933 gtk_text_iter_forward_to_line_end (iter);
2935 return find_by_log_attrs (iter, func, forward,
2944 gtk_text_iter_set_line_offset (iter, offset);
2947 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2948 !gtk_text_iter_is_end (iter);
2953 * gtk_text_iter_forward_word_end:
2954 * @iter: a #GtkTextIter
2956 * Moves forward to the next word end. (If @iter is currently on a
2957 * word end, moves forward to the next one after that.) Word breaks
2958 * are determined by Pango and should be correct for nearly any
2959 * language (if not, the correct fix would be to the Pango word break
2962 * Return value: %TRUE if @iter moved and is not the end iterator
2965 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2967 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2971 * gtk_text_iter_backward_word_start:
2972 * @iter: a #GtkTextIter
2974 * Moves backward to the next word start. (If @iter is currently on a
2975 * word start, moves backward to the next one after that.) Word breaks
2976 * are determined by Pango and should be correct for nearly any
2977 * language (if not, the correct fix would be to the Pango word break
2980 * Return value: %TRUE if @iter moved and is not the end iterator
2983 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2985 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2988 /* FIXME a loop around a truly slow function means
2989 * a truly spectacularly slow function.
2993 * gtk_text_iter_forward_word_ends:
2994 * @iter: a #GtkTextIter
2995 * @count: number of times to move
2997 * Calls gtk_text_iter_forward_word_end() up to @count times.
2999 * Return value: %TRUE if @iter moved and is not the end iterator
3002 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3005 g_return_val_if_fail (iter != NULL, FALSE);
3007 FIX_OVERFLOWS (count);
3013 return gtk_text_iter_backward_word_starts (iter, -count);
3015 if (!gtk_text_iter_forward_word_end (iter))
3021 if (!gtk_text_iter_forward_word_end (iter))
3029 * gtk_text_iter_backward_word_starts
3030 * @iter: a #GtkTextIter
3031 * @count: number of times to move
3033 * Calls gtk_text_iter_backward_word_starts() up to @count times.
3035 * Return value: %TRUE if @iter moved and is not the end iterator
3038 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3041 g_return_val_if_fail (iter != NULL, FALSE);
3043 FIX_OVERFLOWS (count);
3046 return gtk_text_iter_forward_word_ends (iter, -count);
3048 if (!gtk_text_iter_backward_word_start (iter))
3054 if (!gtk_text_iter_backward_word_start (iter))
3062 * gtk_text_iter_starts_word:
3063 * @iter: a #GtkTextIter
3065 * Determines whether @iter begins a natural-language word. Word
3066 * breaks are determined by Pango and should be correct for nearly any
3067 * language (if not, the correct fix would be to the Pango word break
3070 * Return value: %TRUE if @iter is at the start of a word
3073 gtk_text_iter_starts_word (const GtkTextIter *iter)
3075 return test_log_attrs (iter, is_word_start_func);
3079 * gtk_text_iter_ends_word:
3080 * @iter: a #GtkTextIter
3082 * Determines whether @iter ends a natural-language word. Word breaks
3083 * are determined by Pango and should be correct for nearly any
3084 * language (if not, the correct fix would be to the Pango word break
3087 * Return value: %TRUE if @iter is at the end of a word
3090 gtk_text_iter_ends_word (const GtkTextIter *iter)
3092 return test_log_attrs (iter, is_word_end_func);
3096 * gtk_text_iter_inside_word:
3097 * @iter: a #GtkTextIter
3099 * Determines whether @iter is inside a natural-language word (as
3100 * opposed to say inside some whitespace). Word breaks are determined
3101 * by Pango and should be correct for nearly any language (if not, the
3102 * correct fix would be to the Pango word break algorithms).
3104 * Return value: %TRUE if @iter is inside a word
3107 gtk_text_iter_inside_word (const GtkTextIter *iter)
3109 return test_log_attrs (iter, inside_word_func);
3113 * gtk_text_iter_starts_sentence:
3114 * @iter: a #GtkTextIter
3116 * Determines whether @iter begins a sentence. Sentence boundaries are
3117 * determined by Pango and should be correct for nearly any language
3118 * (if not, the correct fix would be to the Pango text boundary
3121 * Return value: %TRUE if @iter is at the start of a sentence.
3124 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3126 return test_log_attrs (iter, is_sentence_start_func);
3130 * gtk_text_iter_ends_sentence:
3131 * @iter: a #GtkTextIter
3133 * Determines whether @iter ends a sentence. Sentence boundaries are
3134 * determined by Pango and should be correct for nearly any language
3135 * (if not, the correct fix would be to the Pango text boundary
3138 * Return value: %TRUE if @iter is at the end of a sentence.
3141 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3143 return test_log_attrs (iter, is_sentence_end_func);
3147 * gtk_text_iter_inside_sentence:
3148 * @iter: a #GtkTextIter
3150 * Determines whether @iter is inside a sentence (as opposed to in
3151 * between two sentences, e.g. after a period and before the first
3152 * letter of the next sentence). Sentence boundaries are determined
3153 * by Pango and should be correct for nearly any language (if not, the
3154 * correct fix would be to the Pango text boundary algorithms).
3156 * Return value: %TRUE if @iter is inside a sentence.
3159 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3161 return test_log_attrs (iter, inside_sentence_func);
3165 * gtk_text_iter_forward_sentence_end:
3166 * @iter: a #GtkTextIter
3168 * Moves forward to the next sentence end. (If @iter is at the end of
3169 * a sentence, moves to the next end of sentence.) Sentence
3170 * boundaries are determined by Pango and should be correct for nearly
3171 * any language (if not, the correct fix would be to the Pango text
3172 * boundary algorithms).
3174 * Return value: %TRUE if @iter moved and is not the end iterator
3177 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3179 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3183 * gtk_text_iter_backward_sentence_start:
3184 * @iter: a #GtkTextIter
3186 * Moves backward to the next sentence start; if @iter is already at
3187 * the start of a sentence, moves backward to the next one. Sentence
3188 * boundaries are determined by Pango and should be correct for nearly
3189 * any language (if not, the correct fix would be to the Pango text
3190 * boundary algorithms).
3192 * Return value: %TRUE if @iter moved and is not the end iterator
3195 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3197 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3200 /* FIXME a loop around a truly slow function means
3201 * a truly spectacularly slow function.
3204 * gtk_text_iter_forward_sentence_ends:
3205 * @iter: a #GtkTextIter
3206 * @count: number of sentences to move
3208 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3209 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3210 * negative, moves backward instead of forward.
3212 * Return value: %TRUE if @iter moved and is not the end iterator
3215 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3218 g_return_val_if_fail (iter != NULL, FALSE);
3224 return gtk_text_iter_backward_sentence_starts (iter, -count);
3226 if (!gtk_text_iter_forward_sentence_end (iter))
3232 if (!gtk_text_iter_forward_sentence_end (iter))
3240 * gtk_text_iter_backward_sentence_starts:
3241 * @iter: a #GtkTextIter
3242 * @count: number of sentences to move
3244 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3245 * or until it returns %FALSE. If @count is negative, moves forward
3246 * instead of backward.
3248 * Return value: %TRUE if @iter moved and is not the end iterator
3251 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3254 g_return_val_if_fail (iter != NULL, FALSE);
3257 return gtk_text_iter_forward_sentence_ends (iter, -count);
3259 if (!gtk_text_iter_backward_sentence_start (iter))
3265 if (!gtk_text_iter_backward_sentence_start (iter))
3273 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3278 gboolean already_moved_initially)
3280 if (!already_moved_initially)
3283 while (offset < (min_offset + len) &&
3284 !attrs[offset].is_cursor_position)
3287 *found_offset = offset;
3289 return offset < (min_offset + len);
3293 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3298 gboolean already_moved_initially)
3300 if (!already_moved_initially)
3303 while (offset > min_offset &&
3304 !attrs[offset].is_cursor_position)
3307 *found_offset = offset;
3309 return offset >= min_offset;
3313 is_cursor_pos_func (const PangoLogAttr *attrs,
3318 return attrs[offset].is_cursor_position;
3322 * gtk_text_iter_forward_cursor_position:
3323 * @iter: a #GtkTextIter
3325 * Moves @iter forward by a single cursor position. Cursor positions
3326 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3327 * surprisingly, there may not be a cursor position between all
3328 * characters. The most common example for European languages would be
3329 * a carriage return/newline sequence. For some Unicode characters,
3330 * the equivalent of say the letter "a" with an accent mark will be
3331 * represented as two characters, first the letter then a "combining
3332 * mark" that causes the accent to be rendered; so the cursor can't go
3333 * between those two characters. See also the #PangoLogAttr structure and
3334 * pango_break() function.
3336 * Return value: %TRUE if we moved and the new position is dereferenceable
3339 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3341 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3345 * gtk_text_iter_backward_cursor_position:
3346 * @iter: a #GtkTextIter
3348 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3350 * Return value: %TRUE if we moved and the new position is dereferenceable
3353 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3355 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3359 * gtk_text_iter_forward_cursor_positions:
3360 * @iter: a #GtkTextIter
3361 * @count: number of positions to move
3363 * Moves up to @count cursor positions. See
3364 * gtk_text_iter_forward_cursor_position() for details.
3366 * Return value: %TRUE if we moved and the new position is dereferenceable
3369 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3372 g_return_val_if_fail (iter != NULL, FALSE);
3374 FIX_OVERFLOWS (count);
3380 return gtk_text_iter_backward_cursor_positions (iter, -count);
3382 if (!gtk_text_iter_forward_cursor_position (iter))
3388 if (!gtk_text_iter_forward_cursor_position (iter))
3396 * gtk_text_iter_backward_cursor_positions:
3397 * @iter: a #GtkTextIter
3398 * @count: number of positions to move
3400 * Moves up to @count cursor positions. See
3401 * gtk_text_iter_forward_cursor_position() for details.
3403 * Return value: %TRUE if we moved and the new position is dereferenceable
3406 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3409 g_return_val_if_fail (iter != NULL, FALSE);
3411 FIX_OVERFLOWS (count);
3417 return gtk_text_iter_forward_cursor_positions (iter, -count);
3419 if (!gtk_text_iter_backward_cursor_position (iter))
3425 if (!gtk_text_iter_backward_cursor_position (iter))
3433 * gtk_text_iter_is_cursor_position:
3434 * @iter: a #GtkTextIter
3436 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3437 * pango_break() for details on what a cursor position is.
3439 * Return value: %TRUE if the cursor can be placed at @iter
3442 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3444 return test_log_attrs (iter, is_cursor_pos_func);
3448 * gtk_text_iter_set_line_offset:
3449 * @iter: a #GtkTextIter
3450 * @char_on_line: a character offset relative to the start of @iter's current line
3452 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3453 * (not byte) offset. The given character offset must be less than or
3454 * equal to the number of characters in the line; if equal, @iter
3455 * moves to the start of the next line. See
3456 * gtk_text_iter_set_line_index() if you have a byte index rather than
3457 * a character offset.
3461 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3464 GtkTextRealIter *real;
3467 g_return_if_fail (iter != NULL);
3469 real = gtk_text_iter_make_surreal (iter);
3474 check_invariants (iter);
3476 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3478 g_return_if_fail (char_on_line <= chars_in_line);
3480 if (char_on_line < chars_in_line)
3481 iter_set_from_char_offset (real, real->line, char_on_line);
3483 gtk_text_iter_forward_line (iter); /* set to start of next line */
3485 check_invariants (iter);
3489 * gtk_text_iter_set_line_index:
3490 * @iter: a #GtkTextIter
3491 * @byte_on_line: a byte index relative to the start of @iter's current line
3493 * Same as gtk_text_iter_set_line_offset(), but works with a
3494 * <emphasis>byte</emphasis> index. The given byte index must be at
3495 * the start of a character, it can't be in the middle of a UTF-8
3496 * encoded character.
3500 gtk_text_iter_set_line_index (GtkTextIter *iter,
3503 GtkTextRealIter *real;
3506 g_return_if_fail (iter != NULL);
3508 real = gtk_text_iter_make_surreal (iter);
3513 check_invariants (iter);
3515 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3517 g_return_if_fail (byte_on_line <= bytes_in_line);
3519 if (byte_on_line < bytes_in_line)
3520 iter_set_from_byte_offset (real, real->line, byte_on_line);
3522 gtk_text_iter_forward_line (iter);
3524 if (real->segment->type == >k_text_char_type &&
3525 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3526 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3527 "character; this will crash the text buffer. "
3528 "Byte indexes must refer to the start of a character.",
3529 G_STRLOC, byte_on_line);
3531 check_invariants (iter);
3536 * gtk_text_iter_set_visible_line_offset:
3537 * @iter: a #GtkTextIter
3538 * @char_on_line: a character offset
3540 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3541 * characters, i.e. text with a tag making it invisible is not
3542 * counted in the offset.
3545 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3548 gint chars_seen = 0;
3551 g_return_if_fail (iter != NULL);
3555 /* For now we use a ludicrously slow implementation */
3556 while (chars_seen < char_on_line)
3558 if (!_gtk_text_btree_char_is_invisible (&pos))
3561 if (!gtk_text_iter_forward_char (&pos))
3564 if (chars_seen == char_on_line)
3568 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3571 gtk_text_iter_forward_line (iter);
3575 bytes_in_char (GtkTextIter *iter)
3577 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3581 * gtk_text_iter_set_visible_line_index:
3582 * @iter: a #GtkTextIter
3583 * @byte_on_line: a byte index
3585 * Like gtk_text_iter_set_line_index(), but the index is in visible
3586 * bytes, i.e. text with a tag making it invisible is not counted
3590 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3593 gint bytes_seen = 0;
3596 g_return_if_fail (iter != NULL);
3600 /* For now we use a ludicrously slow implementation */
3601 while (bytes_seen < byte_on_line)
3603 if (!_gtk_text_btree_char_is_invisible (&pos))
3604 bytes_seen += bytes_in_char (&pos);
3606 if (!gtk_text_iter_forward_char (&pos))
3609 if (bytes_seen >= byte_on_line)
3613 if (bytes_seen > byte_on_line)
3614 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3615 "character; this will crash the text buffer. "
3616 "Byte indexes must refer to the start of a character.",
3617 G_STRLOC, byte_on_line);
3619 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3622 gtk_text_iter_forward_line (iter);
3626 * gtk_text_iter_set_line:
3627 * @iter: a #GtkTextIter
3628 * @line_number: line number (counted from 0)
3630 * Moves iterator @iter to the start of the line @line_number.
3634 gtk_text_iter_set_line (GtkTextIter *iter,
3639 GtkTextRealIter *real;
3641 g_return_if_fail (iter != NULL);
3643 real = gtk_text_iter_make_surreal (iter);
3648 check_invariants (iter);
3650 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3652 iter_set_from_char_offset (real, line, 0);
3654 /* We might as well cache this, since we know it. */
3655 real->cached_line_number = real_line;
3657 check_invariants (iter);
3661 * gtk_text_iter_set_offset:
3662 * @iter: a #GtkTextIter
3663 * @char_offset: a character number
3665 * Sets @iter to point to @char_offset. @char_offset counts from the start
3666 * of the entire text buffer, starting with 0.
3670 gtk_text_iter_set_offset (GtkTextIter *iter,
3674 GtkTextRealIter *real;
3676 gint real_char_index;
3678 g_return_if_fail (iter != NULL);
3680 real = gtk_text_iter_make_surreal (iter);
3685 check_invariants (iter);
3687 if (real->cached_char_index >= 0 &&
3688 real->cached_char_index == char_offset)
3691 line = _gtk_text_btree_get_line_at_char (real->tree,
3696 iter_set_from_char_offset (real, line, real_char_index - line_start);
3698 /* Go ahead and cache this since we have it. */
3699 real->cached_char_index = real_char_index;
3701 check_invariants (iter);
3705 * gtk_text_iter_forward_to_end:
3706 * @iter: a #GtkTextIter
3708 * Moves @iter forward to the "end iterator," which points one past the last
3709 * valid character in the buffer. gtk_text_iter_get_char() called on the
3710 * end iterator returns 0, which is convenient for writing loops.
3714 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3716 GtkTextBuffer *buffer;
3717 GtkTextRealIter *real;
3719 g_return_if_fail (iter != NULL);
3721 real = gtk_text_iter_make_surreal (iter);
3726 buffer = _gtk_text_btree_get_buffer (real->tree);
3728 gtk_text_buffer_get_end_iter (buffer, iter);
3732 * gtk_text_iter_forward_to_line_end:
3733 * @iter: a #GtkTextIter
3735 * Moves the iterator to point to the paragraph delimiter characters,
3736 * which will be either a newline, a carriage return, a carriage
3737 * return/newline in sequence, or the Unicode paragraph separator
3738 * character. If the iterator is already at the paragraph delimiter
3739 * characters, moves to the paragraph delimiter characters for the
3742 * Return value: %TRUE if we moved and the new location is not the end iterator
3745 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3747 gint current_offset;
3750 g_return_val_if_fail (iter != NULL, FALSE);
3752 current_offset = gtk_text_iter_get_line_offset (iter);
3753 /* FIXME assumption that line ends in a newline; broken */
3754 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3756 if (current_offset < new_offset)
3758 /* Move to end of this line. */
3759 gtk_text_iter_set_line_offset (iter, new_offset);
3764 /* Move to end of next line. */
3765 if (gtk_text_iter_forward_line (iter))
3767 /* We don't want to move past all
3770 if (!gtk_text_iter_ends_line (iter))
3771 gtk_text_iter_forward_to_line_end (iter);
3780 * gtk_text_iter_forward_to_tag_toggle:
3781 * @iter: a #GtkTextIter
3782 * @tag: a #GtkTextTag, or NULL
3784 * Moves forward to the next toggle (on or off) of the
3785 * #GtkTextTag @tag, or to the next toggle of any tag if
3786 * @tag is NULL. If no matching tag toggles are found,
3787 * returns FALSE, otherwise TRUE. Does not return toggles
3788 * located at @iter, only toggles after @iter. Sets @iter to
3789 * the location of the toggle, or to the end of the buffer
3790 * if no toggle is found.
3792 * Return value: whether we found a tag toggle after @iter
3795 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3798 GtkTextLine *next_line;
3799 GtkTextLine *current_line;
3800 GtkTextRealIter *real;
3802 g_return_val_if_fail (iter != NULL, FALSE);
3804 real = gtk_text_iter_make_real (iter);
3809 check_invariants (iter);
3811 current_line = real->line;
3812 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3815 while (_gtk_text_iter_forward_indexable_segment (iter))
3817 /* If we went forward to a line that couldn't contain a toggle
3818 for the tag, then skip forward to a line that could contain
3819 it. This potentially skips huge hunks of the tree, so we
3820 aren't a purely linear search. */
3821 if (real->line != current_line)
3823 if (next_line == NULL)
3825 /* End of search. Set to end of buffer. */
3826 _gtk_text_btree_get_end_iter (real->tree, iter);
3830 if (real->line != next_line)
3831 iter_set_from_byte_offset (real, next_line, 0);
3833 current_line = real->line;
3834 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3839 if (gtk_text_iter_toggles_tag (iter, tag))
3841 /* If there's a toggle here, it isn't indexable so
3842 any_segment can't be the indexable segment. */
3843 g_assert (real->any_segment != real->segment);
3848 /* Check end iterator for tags */
3849 if (gtk_text_iter_toggles_tag (iter, tag))
3851 /* If there's a toggle here, it isn't indexable so
3852 any_segment can't be the indexable segment. */
3853 g_assert (real->any_segment != real->segment);
3857 /* Reached end of buffer */
3862 * gtk_text_iter_backward_to_tag_toggle:
3863 * @iter: a #GtkTextIter
3864 * @tag: a #GtkTextTag, or NULL
3866 * Moves backward to the next toggle (on or off) of the
3867 * #GtkTextTag @tag, or to the next toggle of any tag if
3868 * @tag is NULL. If no matching tag toggles are found,
3869 * returns FALSE, otherwise TRUE. Does not return toggles
3870 * located at @iter, only toggles before @iter. Sets @iter
3871 * to the location of the toggle, or the start of the buffer
3872 * if no toggle is found.
3874 * Return value: whether we found a tag toggle before @iter
3877 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3880 GtkTextLine *prev_line;
3881 GtkTextLine *current_line;
3882 GtkTextRealIter *real;
3884 g_return_val_if_fail (iter != NULL, FALSE);
3886 real = gtk_text_iter_make_real (iter);
3891 check_invariants (iter);
3893 current_line = real->line;
3894 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3898 /* If we're at segment start, go to the previous segment;
3899 * if mid-segment, snap to start of current segment.
3901 if (is_segment_start (real))
3903 if (!_gtk_text_iter_backward_indexable_segment (iter))
3908 ensure_char_offsets (real);
3910 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3916 /* If we went backward to a line that couldn't contain a toggle
3917 * for the tag, then skip backward further to a line that
3918 * could contain it. This potentially skips huge hunks of the
3919 * tree, so we aren't a purely linear search.
3921 if (real->line != current_line)
3923 if (prev_line == NULL)
3925 /* End of search. Set to start of buffer. */
3926 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3930 if (real->line != prev_line)
3932 /* Set to last segment in prev_line (could do this
3935 iter_set_from_byte_offset (real, prev_line, 0);
3937 while (!at_last_indexable_segment (real))
3938 _gtk_text_iter_forward_indexable_segment (iter);
3941 current_line = real->line;
3942 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3947 if (gtk_text_iter_toggles_tag (iter, tag))
3949 /* If there's a toggle here, it isn't indexable so
3950 * any_segment can't be the indexable segment.
3952 g_assert (real->any_segment != real->segment);
3956 while (_gtk_text_iter_backward_indexable_segment (iter));
3958 /* Reached front of buffer */
3963 matches_pred (GtkTextIter *iter,
3964 GtkTextCharPredicate pred,
3969 ch = gtk_text_iter_get_char (iter);
3971 return (*pred) (ch, user_data);
3975 * gtk_text_iter_forward_find_char:
3976 * @iter: a #GtkTextIter
3977 * @pred: a function to be called on each character
3978 * @user_data: user data for @pred
3979 * @limit: search limit, or %NULL for none
3981 * Advances @iter, calling @pred on each character. If
3982 * @pred returns %TRUE, returns %TRUE and stops scanning.
3983 * If @pred never returns %TRUE, @iter is set to @limit if
3984 * @limit is non-%NULL, otherwise to the end iterator.
3986 * Return value: whether a match was found
3989 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3990 GtkTextCharPredicate pred,
3992 const GtkTextIter *limit)
3994 g_return_val_if_fail (iter != NULL, FALSE);
3995 g_return_val_if_fail (pred != NULL, FALSE);
3998 gtk_text_iter_compare (iter, limit) >= 0)
4001 while ((limit == NULL ||
4002 !gtk_text_iter_equal (limit, iter)) &&
4003 gtk_text_iter_forward_char (iter))
4005 if (matches_pred (iter, pred, user_data))
4013 * gtk_text_iter_backward_find_char:
4014 * @iter: a #GtkTextIter
4015 * @pred: function to be called on each character
4016 * @user_data: user data for @pred
4017 * @limit: search limit, or %NULL for none
4019 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4021 * Return value: whether a match was found
4024 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4025 GtkTextCharPredicate pred,
4027 const GtkTextIter *limit)
4029 g_return_val_if_fail (iter != NULL, FALSE);
4030 g_return_val_if_fail (pred != NULL, FALSE);
4033 gtk_text_iter_compare (iter, limit) <= 0)
4036 while ((limit == NULL ||
4037 !gtk_text_iter_equal (limit, iter)) &&
4038 gtk_text_iter_backward_char (iter))
4040 if (matches_pred (iter, pred, user_data))
4048 forward_chars_with_skipping (GtkTextIter *iter,
4050 gboolean skip_invisible,
4051 gboolean skip_nontext)
4056 g_return_if_fail (count >= 0);
4062 gboolean ignored = FALSE;
4065 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4070 _gtk_text_btree_char_is_invisible (iter))
4073 gtk_text_iter_forward_char (iter);
4081 lines_match (const GtkTextIter *start,
4082 const gchar **lines,
4083 gboolean visible_only,
4085 GtkTextIter *match_start,
4086 GtkTextIter *match_end)
4093 if (*lines == NULL || **lines == '\0')
4096 *match_start = *start;
4099 *match_end = *start;
4104 gtk_text_iter_forward_line (&next);
4106 /* No more text in buffer, but *lines is nonempty */
4107 if (gtk_text_iter_equal (start, &next))
4115 line_text = gtk_text_iter_get_visible_slice (start, &next);
4117 line_text = gtk_text_iter_get_slice (start, &next);
4122 line_text = gtk_text_iter_get_visible_text (start, &next);
4124 line_text = gtk_text_iter_get_text (start, &next);
4127 if (match_start) /* if this is the first line we're matching */
4128 found = strstr (line_text, *lines);
4131 /* If it's not the first line, we have to match from the
4132 * start of the line.
4134 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4146 /* Get offset to start of search string */
4147 offset = g_utf8_strlen (line_text, found - line_text);
4151 /* If match start needs to be returned, set it to the
4152 * start of the search string.
4156 *match_start = next;
4158 forward_chars_with_skipping (match_start, offset,
4159 visible_only, !slice);
4162 /* Go to end of search string */
4163 offset += g_utf8_strlen (*lines, -1);
4165 forward_chars_with_skipping (&next, offset,
4166 visible_only, !slice);
4175 /* pass NULL for match_start, since we don't need to find the
4178 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4181 /* strsplit () that retains the delimiter as part of the string. */
4183 strbreakup (const char *string,
4184 const char *delimiter,
4187 GSList *string_list = NULL, *slist;
4188 gchar **str_array, *s;
4191 g_return_val_if_fail (string != NULL, NULL);
4192 g_return_val_if_fail (delimiter != NULL, NULL);
4195 max_tokens = G_MAXINT;
4197 s = strstr (string, delimiter);
4200 guint delimiter_len = strlen (delimiter);
4207 len = s - string + delimiter_len;
4208 new_string = g_new (gchar, len + 1);
4209 strncpy (new_string, string, len);
4210 new_string[len] = 0;
4211 string_list = g_slist_prepend (string_list, new_string);
4213 string = s + delimiter_len;
4214 s = strstr (string, delimiter);
4216 while (--max_tokens && s);
4221 string_list = g_slist_prepend (string_list, g_strdup (string));
4224 str_array = g_new (gchar*, n);
4228 str_array[i--] = NULL;
4229 for (slist = string_list; slist; slist = slist->next)
4230 str_array[i--] = slist->data;
4232 g_slist_free (string_list);
4238 * gtk_text_iter_forward_search:
4239 * @iter: start of search
4240 * @str: a search string
4241 * @visible_only: if %TRUE, search only visible text
4242 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4243 * @match_start: return location for start of match, or %NULL
4244 * @match_end: return location for end of match, or %NULL
4245 * @limit: bound for the search, or %NULL for the end of the buffer
4247 * Searches forward for @str. Any match is returned as the range @match_start,
4248 * @match_end. If you specify @visible_only or @slice, the match may have
4249 * invisible text, pixbufs, or child widgets interspersed in @str.
4251 * Return value: whether a match was found
4254 gtk_text_iter_forward_search (const GtkTextIter *iter,
4256 gboolean visible_only,
4258 GtkTextIter *match_start,
4259 GtkTextIter *match_end,
4260 const GtkTextIter *limit)
4262 gchar **lines = NULL;
4264 gboolean retval = FALSE;
4267 g_return_val_if_fail (iter != NULL, FALSE);
4268 g_return_val_if_fail (str != NULL, FALSE);
4271 gtk_text_iter_compare (iter, limit) >= 0)
4276 /* If we can move one char, return the empty string there */
4279 if (gtk_text_iter_forward_char (&match))
4282 gtk_text_iter_equal (&match, limit))
4286 *match_start = match;
4295 /* locate all lines */
4297 lines = strbreakup (str, "\n", -1);
4303 /* This loop has an inefficient worst-case, where
4304 * gtk_text_iter_get_text () is called repeatedly on
4310 gtk_text_iter_compare (&search, limit) >= 0)
4313 if (lines_match (&search, (const gchar**)lines,
4314 visible_only, slice, &match, &end))
4316 if (limit == NULL ||
4318 gtk_text_iter_compare (&end, limit) < 0))
4323 *match_start = match;
4332 while (gtk_text_iter_forward_line (&search));
4334 g_strfreev ((gchar**)lines);
4340 vectors_equal_ignoring_trailing (gchar **vec1,
4343 /* Ignores trailing chars in vec2's last line */
4352 if (strcmp (*i1, *i2) != 0)
4354 if (*(i2 + 1) == NULL) /* if this is the last line */
4356 gint len1 = strlen (*i1);
4357 gint len2 = strlen (*i2);
4360 strncmp (*i1, *i2, len1) == 0)
4362 /* We matched ignoring the trailing stuff in vec2 */
4387 typedef struct _LinesWindow LinesWindow;
4393 GtkTextIter first_line_start;
4394 GtkTextIter first_line_end;
4396 gboolean visible_only;
4400 lines_window_init (LinesWindow *win,
4401 const GtkTextIter *start)
4404 GtkTextIter line_start;
4405 GtkTextIter line_end;
4407 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4410 if (gtk_text_iter_is_start (start) ||
4411 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4413 /* Already at the end, or not enough lines to match */
4414 win->lines = g_new0 (gchar*, 1);
4419 line_start = *start;
4422 /* Move to start iter to start of line */
4423 gtk_text_iter_set_line_offset (&line_start, 0);
4425 if (gtk_text_iter_equal (&line_start, &line_end))
4427 /* we were already at the start; so go back one line */
4428 gtk_text_iter_backward_line (&line_start);
4431 win->first_line_start = line_start;
4432 win->first_line_end = line_end;
4434 win->lines = g_new0 (gchar*, win->n_lines + 1);
4436 i = win->n_lines - 1;
4443 if (win->visible_only)
4444 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4446 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4450 if (win->visible_only)
4451 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4453 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4456 win->lines[i] = line_text;
4458 line_end = line_start;
4459 gtk_text_iter_backward_line (&line_start);
4466 lines_window_back (LinesWindow *win)
4468 GtkTextIter new_start;
4471 new_start = win->first_line_start;
4473 if (!gtk_text_iter_backward_line (&new_start))
4477 win->first_line_start = new_start;
4478 win->first_line_end = new_start;
4480 gtk_text_iter_forward_line (&win->first_line_end);
4485 if (win->visible_only)
4486 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4487 &win->first_line_end);
4489 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4490 &win->first_line_end);
4494 if (win->visible_only)
4495 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4496 &win->first_line_end);
4498 line_text = gtk_text_iter_get_text (&win->first_line_start,
4499 &win->first_line_end);
4502 /* Move lines to make room for first line. */
4503 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4505 *win->lines = line_text;
4507 /* Free old last line and NULL-terminate */
4508 g_free (win->lines[win->n_lines]);
4509 win->lines[win->n_lines] = NULL;
4515 lines_window_free (LinesWindow *win)
4517 g_strfreev (win->lines);
4521 my_strrstr (const gchar *haystack,
4522 const gchar *needle)
4524 /* FIXME GLib should have a nice implementation in it, this
4528 gint haystack_len = strlen (haystack);
4529 gint needle_len = strlen (needle);
4530 const gchar *needle_end = needle + needle_len;
4531 const gchar *haystack_rend = haystack - 1;
4532 const gchar *needle_rend = needle - 1;
4535 p = haystack + haystack_len;
4536 while (p != haystack)
4538 const gchar *n = needle_end - 1;
4539 const gchar *s = p - 1;
4540 while (s != haystack_rend &&
4548 if (n == needle_rend)
4558 * gtk_text_iter_backward_search:
4559 * @iter: a #GtkTextIter where the search begins
4560 * @str: search string
4561 * @visible_only: if %TRUE search only visible text
4562 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4563 * @match_start: return location for start of match, or %NULL
4564 * @match_end: return location for end of match, or %NULL
4565 * @limit: location of last possible @match_start, or %NULL for start of buffer
4567 * Same as gtk_text_iter_forward_search(), but moves backward.
4569 * Return value: whether a match was found
4572 gtk_text_iter_backward_search (const GtkTextIter *iter,
4574 gboolean visible_only,
4576 GtkTextIter *match_start,
4577 GtkTextIter *match_end,
4578 const GtkTextIter *limit)
4580 gchar **lines = NULL;
4584 gboolean retval = FALSE;
4586 g_return_val_if_fail (iter != NULL, FALSE);
4587 g_return_val_if_fail (str != NULL, FALSE);
4590 gtk_text_iter_compare (limit, iter) > 0)
4595 /* If we can move one char, return the empty string there */
4596 GtkTextIter match = *iter;
4598 if (limit && gtk_text_iter_equal (limit, &match))
4601 if (gtk_text_iter_backward_char (&match))
4604 *match_start = match;
4613 /* locate all lines */
4615 lines = strbreakup (str, "\n", -1);
4625 win.n_lines = n_lines;
4627 win.visible_only = visible_only;
4629 lines_window_init (&win, iter);
4631 if (*win.lines == NULL)
4636 gchar *first_line_match;
4639 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4641 /* We're now before the search limit, abort. */
4645 /* If there are multiple lines, the first line will
4646 * end in '\n', so this will only match at the
4647 * end of the first line, which is correct.
4649 first_line_match = my_strrstr (*win.lines, *lines);
4651 if (first_line_match &&
4652 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4657 GtkTextIter start_tmp;
4659 /* Offset to start of search string */
4660 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4662 next = win.first_line_start;
4664 forward_chars_with_skipping (&start_tmp, offset,
4665 visible_only, !slice);
4668 gtk_text_iter_compare (limit, &start_tmp) > 0)
4669 goto out; /* match was bogus */
4672 *match_start = start_tmp;
4674 /* Go to end of search string */
4678 offset += g_utf8_strlen (*l, -1);
4682 forward_chars_with_skipping (&next, offset,
4683 visible_only, !slice);
4692 while (lines_window_back (&win));
4695 lines_window_free (&win);
4706 * gtk_text_iter_equal:
4707 * @lhs: a #GtkTextIter
4708 * @rhs: another #GtkTextIter
4710 * Tests whether two iterators are equal, using the fastest possible
4711 * mechanism. This function is very fast; you can expect it to perform
4712 * better than e.g. getting the character offset for each iterator and
4713 * comparing the offsets yourself. Also, it's a bit faster than
4714 * gtk_text_iter_compare().
4716 * Return value: %TRUE if the iterators point to the same place in the buffer
4719 gtk_text_iter_equal (const GtkTextIter *lhs,
4720 const GtkTextIter *rhs)
4722 GtkTextRealIter *real_lhs;
4723 GtkTextRealIter *real_rhs;
4725 real_lhs = (GtkTextRealIter*)lhs;
4726 real_rhs = (GtkTextRealIter*)rhs;
4728 check_invariants (lhs);
4729 check_invariants (rhs);
4731 if (real_lhs->line != real_rhs->line)
4733 else if (real_lhs->line_byte_offset >= 0 &&
4734 real_rhs->line_byte_offset >= 0)
4735 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4738 /* the ensure_char_offsets () calls do nothing if the char offsets
4739 are already up-to-date. */
4740 ensure_char_offsets (real_lhs);
4741 ensure_char_offsets (real_rhs);
4742 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4747 * gtk_text_iter_compare:
4748 * @lhs: a #GtkTextIter
4749 * @rhs: another #GtkTextIter
4751 * A qsort()-style function that returns negative if @lhs is less than
4752 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4753 * Ordering is in character offset order, i.e. the first character in the buffer
4754 * is less than the second character in the buffer.
4756 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4759 gtk_text_iter_compare (const GtkTextIter *lhs,
4760 const GtkTextIter *rhs)
4762 GtkTextRealIter *real_lhs;
4763 GtkTextRealIter *real_rhs;
4765 real_lhs = gtk_text_iter_make_surreal (lhs);
4766 real_rhs = gtk_text_iter_make_surreal (rhs);
4768 if (real_lhs == NULL ||
4770 return -1; /* why not */
4772 check_invariants (lhs);
4773 check_invariants (rhs);
4775 if (real_lhs->line == real_rhs->line)
4777 gint left_index, right_index;
4779 if (real_lhs->line_byte_offset >= 0 &&
4780 real_rhs->line_byte_offset >= 0)
4782 left_index = real_lhs->line_byte_offset;
4783 right_index = real_rhs->line_byte_offset;
4787 /* the ensure_char_offsets () calls do nothing if
4788 the offsets are already up-to-date. */
4789 ensure_char_offsets (real_lhs);
4790 ensure_char_offsets (real_rhs);
4791 left_index = real_lhs->line_char_offset;
4792 right_index = real_rhs->line_char_offset;
4795 if (left_index < right_index)
4797 else if (left_index > right_index)
4806 line1 = gtk_text_iter_get_line (lhs);
4807 line2 = gtk_text_iter_get_line (rhs);
4810 else if (line1 > line2)
4818 * gtk_text_iter_in_range:
4819 * @iter: a #GtkTextIter
4820 * @start: start of range
4821 * @end: end of range
4823 * Checks whether @iter falls in the range [@start, @end).
4824 * @start and @end must be in ascending order.
4826 * Return value: %TRUE if @iter is in the range
4829 gtk_text_iter_in_range (const GtkTextIter *iter,
4830 const GtkTextIter *start,
4831 const GtkTextIter *end)
4833 g_return_val_if_fail (iter != NULL, FALSE);
4834 g_return_val_if_fail (start != NULL, FALSE);
4835 g_return_val_if_fail (end != NULL, FALSE);
4836 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4838 return gtk_text_iter_compare (iter, start) >= 0 &&
4839 gtk_text_iter_compare (iter, end) < 0;
4843 * gtk_text_iter_order:
4844 * @first: a #GtkTextIter
4845 * @second: another #GtkTextIter
4847 * Swaps the value of @first and @second if @second comes before
4848 * @first in the buffer. That is, ensures that @first and @second are
4849 * in sequence. Most text buffer functions that take a range call this
4850 * automatically on your behalf, so there's no real reason to call it yourself
4851 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4852 * that expect a pre-sorted range.
4856 gtk_text_iter_order (GtkTextIter *first,
4857 GtkTextIter *second)
4859 g_return_if_fail (first != NULL);
4860 g_return_if_fail (second != NULL);
4862 if (gtk_text_iter_compare (first, second) > 0)
4873 * Init iterators from the BTree
4877 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4881 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4882 gint real_char_index;
4886 g_return_if_fail (iter != NULL);
4887 g_return_if_fail (tree != NULL);
4889 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4890 &line_start, &real_char_index);
4892 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4894 real->cached_char_index = real_char_index;
4896 check_invariants (iter);
4900 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4905 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4909 g_return_if_fail (iter != NULL);
4910 g_return_if_fail (tree != NULL);
4912 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4914 iter_init_from_char_offset (iter, tree, line, char_on_line);
4916 /* We might as well cache this, since we know it. */
4917 real->cached_line_number = real_line;
4919 check_invariants (iter);
4923 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4928 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4932 g_return_if_fail (iter != NULL);
4933 g_return_if_fail (tree != NULL);
4935 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4937 iter_init_from_byte_offset (iter, tree, line, byte_index);
4939 /* We might as well cache this, since we know it. */
4940 real->cached_line_number = real_line;
4942 check_invariants (iter);
4946 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4951 g_return_if_fail (iter != NULL);
4952 g_return_if_fail (tree != NULL);
4953 g_return_if_fail (line != NULL);
4955 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4957 check_invariants (iter);
4961 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4967 g_return_val_if_fail (iter != NULL, FALSE);
4968 g_return_val_if_fail (tree != NULL, FALSE);
4970 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4974 /* Set iter to last in tree */
4975 _gtk_text_btree_get_end_iter (tree, iter);
4976 check_invariants (iter);
4981 iter_init_from_byte_offset (iter, tree, line, 0);
4982 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4983 check_invariants (iter);
4989 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4993 g_return_val_if_fail (iter != NULL, FALSE);
4994 g_return_val_if_fail (tree != NULL, FALSE);
4996 _gtk_text_btree_get_end_iter (tree, iter);
4997 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4998 check_invariants (iter);
5004 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5006 const gchar *mark_name)
5010 g_return_val_if_fail (iter != NULL, FALSE);
5011 g_return_val_if_fail (tree != NULL, FALSE);
5013 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5019 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5020 check_invariants (iter);
5026 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5030 GtkTextLineSegment *seg;
5032 g_return_if_fail (iter != NULL);
5033 g_return_if_fail (tree != NULL);
5034 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5036 seg = mark->segment;
5038 iter_init_from_segment (iter, tree,
5039 seg->body.mark.line, seg);
5040 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5041 check_invariants (iter);
5045 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5047 GtkTextChildAnchor *anchor)
5049 GtkTextLineSegment *seg;
5051 g_return_if_fail (iter != NULL);
5052 g_return_if_fail (tree != NULL);
5053 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5055 seg = anchor->segment;
5057 iter_init_from_segment (iter, tree,
5058 seg->body.child.line, seg);
5059 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5060 check_invariants (iter);
5064 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5067 g_return_if_fail (iter != NULL);
5068 g_return_if_fail (tree != NULL);
5070 _gtk_text_btree_get_iter_at_char (tree,
5072 _gtk_text_btree_char_count (tree));
5073 check_invariants (iter);
5077 _gtk_text_iter_check (const GtkTextIter *iter)
5079 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5080 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5081 GtkTextLineSegment *byte_segment = NULL;
5082 GtkTextLineSegment *byte_any_segment = NULL;
5083 GtkTextLineSegment *char_segment = NULL;
5084 GtkTextLineSegment *char_any_segment = NULL;
5085 gboolean segments_updated;
5087 /* This function checks our class invariants for the Iter class. */
5089 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5091 if (real->chars_changed_stamp !=
5092 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5093 g_error ("iterator check failed: invalid iterator");
5095 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5096 g_error ("iterator check failed: both char and byte offsets are invalid");
5098 segments_updated = (real->segments_changed_stamp ==
5099 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5102 printf ("checking iter, segments %s updated, byte %d char %d\n",
5103 segments_updated ? "are" : "aren't",
5104 real->line_byte_offset,
5105 real->line_char_offset);
5108 if (segments_updated)
5110 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5111 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5113 if (real->segment->char_count == 0)
5114 g_error ("iterator check failed: segment is not indexable.");
5116 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5117 g_error ("segment char offset is not properly up-to-date");
5119 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5120 g_error ("segment byte offset is not properly up-to-date");
5122 if (real->segment_byte_offset >= 0 &&
5123 real->segment_byte_offset >= real->segment->byte_count)
5124 g_error ("segment byte offset is too large.");
5126 if (real->segment_char_offset >= 0 &&
5127 real->segment_char_offset >= real->segment->char_count)
5128 g_error ("segment char offset is too large.");
5131 if (real->line_byte_offset >= 0)
5133 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5134 &byte_segment, &byte_any_segment,
5135 &seg_byte_offset, &line_byte_offset);
5137 if (line_byte_offset != real->line_byte_offset)
5138 g_error ("wrong byte offset was stored in iterator");
5140 if (segments_updated)
5142 if (real->segment != byte_segment)
5143 g_error ("wrong segment was stored in iterator");
5145 if (real->any_segment != byte_any_segment)
5146 g_error ("wrong any_segment was stored in iterator");
5148 if (seg_byte_offset != real->segment_byte_offset)
5149 g_error ("wrong segment byte offset was stored in iterator");
5151 if (byte_segment->type == >k_text_char_type)
5154 p = byte_segment->body.chars + seg_byte_offset;
5156 if (!gtk_text_byte_begins_utf8_char (p))
5157 g_error ("broken iterator byte index pointed into the middle of a character");
5162 if (real->line_char_offset >= 0)
5164 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5165 &char_segment, &char_any_segment,
5166 &seg_char_offset, &line_char_offset);
5168 if (line_char_offset != real->line_char_offset)
5169 g_error ("wrong char offset was stored in iterator");
5171 if (segments_updated)
5173 if (real->segment != char_segment)
5174 g_error ("wrong segment was stored in iterator");
5176 if (real->any_segment != char_any_segment)
5177 g_error ("wrong any_segment was stored in iterator");
5179 if (seg_char_offset != real->segment_char_offset)
5180 g_error ("wrong segment char offset was stored in iterator");
5182 if (char_segment->type == >k_text_char_type)
5185 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5188 /* hmm, not likely to happen eh */
5189 if (!gtk_text_byte_begins_utf8_char (p))
5190 g_error ("broken iterator char offset pointed into the middle of a character");
5195 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5197 if (byte_segment != char_segment)
5198 g_error ("char and byte offsets did not point to the same segment");
5200 if (byte_any_segment != char_any_segment)
5201 g_error ("char and byte offsets did not point to the same any segment");
5203 /* Make sure the segment offsets are equivalent, if it's a char
5205 if (char_segment->type == >k_text_char_type)
5207 gint byte_offset = 0;
5208 gint char_offset = 0;
5209 while (char_offset < seg_char_offset)
5211 const char * start = char_segment->body.chars + byte_offset;
5212 byte_offset += g_utf8_next_char (start) - start;
5216 if (byte_offset != seg_byte_offset)
5217 g_error ("byte offset did not correspond to char offset");
5220 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5222 if (char_offset != seg_char_offset)
5223 g_error ("char offset did not correspond to byte offset");
5225 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5226 g_error ("byte index for iterator does not index the start of a character");
5230 if (real->cached_line_number >= 0)
5234 should_be = _gtk_text_line_get_number (real->line);
5235 if (real->cached_line_number != should_be)
5236 g_error ("wrong line number was cached");
5239 if (real->cached_char_index >= 0)
5241 if (real->line_char_offset >= 0) /* only way we can check it
5242 efficiently, not a real
5247 char_index = _gtk_text_line_char_index (real->line);
5248 char_index += real->line_char_offset;
5250 if (real->cached_char_index != char_index)
5251 g_error ("wrong char index was cached");
5255 if (_gtk_text_line_is_last (real->line, real->tree))
5256 g_error ("Iterator was on last line (past the end iterator)");