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 @iter is within an editable region of text.
1369 * Non-editable text is "locked" and can't be changed by the user via
1370 * #GtkTextView. This function is simply a convenience wrapper around
1371 * gtk_text_iter_get_attributes (). If no tags applied to this text
1372 * affect editability, @default_setting will be returned.
1374 * Return value: whether @iter is inside an editable range
1377 gtk_text_iter_editable (const GtkTextIter *iter,
1378 gboolean default_setting)
1380 GtkTextAttributes *values;
1383 values = gtk_text_attributes_new ();
1385 values->editable = default_setting;
1387 gtk_text_iter_get_attributes (iter, values);
1389 retval = values->editable;
1391 gtk_text_attributes_unref (values);
1397 * gtk_text_iter_get_language:
1398 * @iter: an iterator
1400 * A convenience wrapper around gtk_text_iter_get_attributes (),
1401 * which returns the language in effect at @iter. If no tags affecting
1402 * language * apply to @iter, the return value is identical to that of
1403 * gtk_get_default_language ().
1405 * Return value: language in effect at @iter
1408 gtk_text_iter_get_language (const GtkTextIter *iter)
1410 GtkTextAttributes *values;
1411 PangoLanguage *retval;
1413 values = gtk_text_attributes_new ();
1415 gtk_text_iter_get_attributes (iter, values);
1417 retval = values->language;
1419 gtk_text_attributes_unref (values);
1425 * gtk_text_iter_starts_line:
1426 * @iter: an iterator
1428 * Returns TRUE if @iter begins a paragraph,
1429 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1430 * However this function is potentially more efficient than
1431 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1432 * the offset, it just has to see whether it's 0.
1434 * Return value: whether @iter begins a line
1437 gtk_text_iter_starts_line (const GtkTextIter *iter)
1439 GtkTextRealIter *real;
1441 g_return_val_if_fail (iter != NULL, FALSE);
1443 real = gtk_text_iter_make_surreal (iter);
1448 check_invariants (iter);
1450 if (real->line_byte_offset >= 0)
1452 return (real->line_byte_offset == 0);
1456 g_assert (real->line_char_offset >= 0);
1457 return (real->line_char_offset == 0);
1462 * gtk_text_iter_ends_line:
1463 * @iter: an iterator
1465 * Returns TRUE if @iter points to the start of the paragraph delimiter
1466 * characters for a line (delimiters will be either a newline, a
1467 * carriage return, a carriage return followed by a newline, or a
1468 * Unicode paragraph separator character). Note that an iterator pointing
1469 * to the \n of a \r\n pair will not be counted as the end of a line,
1470 * the line ends before the \r.
1472 * Return value: whether @iter is at the end of a line
1475 gtk_text_iter_ends_line (const GtkTextIter *iter)
1477 GtkTextRealIter *real;
1480 g_return_val_if_fail (iter != NULL, FALSE);
1482 real = gtk_text_iter_make_real (iter);
1484 check_invariants (iter);
1486 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1487 * Unicode 3.0; update this if that changes.
1489 #define PARAGRAPH_SEPARATOR 0x2029
1491 wc = gtk_text_iter_get_char (iter);
1493 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
1495 else if (wc == '\n')
1497 /* need to determine if a \r precedes the \n, in which case
1498 * we aren't the end of the line
1500 GtkTextIter tmp = *iter;
1501 if (!gtk_text_iter_backward_char (&tmp))
1504 return gtk_text_iter_get_char (&tmp) != '\r';
1511 * gtk_text_iter_is_end:
1512 * @iter: an iterator
1514 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1515 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1516 * the most efficient way to check whether an iterator is the end
1519 * Return value: whether @iter is the end iterator
1522 gtk_text_iter_is_end (const GtkTextIter *iter)
1524 GtkTextRealIter *real;
1526 g_return_val_if_fail (iter != NULL, FALSE);
1528 real = gtk_text_iter_make_surreal (iter);
1533 check_invariants (iter);
1535 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1538 /* Now we need the segments validated */
1539 real = gtk_text_iter_make_real (iter);
1544 return _gtk_text_btree_is_end (real->tree, real->line,
1546 real->segment_byte_offset,
1547 real->segment_char_offset);
1551 * gtk_text_iter_is_start:
1552 * @iter: an iterator
1554 * Returns TRUE if @iter is the first iterator in the buffer, that is
1555 * if @iter has a character offset of 0.
1557 * Return value: whether @iter is the first in the buffer
1560 gtk_text_iter_is_start (const GtkTextIter *iter)
1562 return gtk_text_iter_get_offset (iter) == 0;
1566 * gtk_text_iter_get_chars_in_line:
1567 * @iter: an iterator
1569 * Returns the number of characters in the line containing @iter,
1570 * including the paragraph delimiters.
1572 * Return value: number of characters in the line
1575 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1577 GtkTextRealIter *real;
1579 GtkTextLineSegment *seg;
1581 g_return_val_if_fail (iter != NULL, FALSE);
1583 real = gtk_text_iter_make_surreal (iter);
1588 check_invariants (iter);
1590 if (real->line_char_offset >= 0)
1592 /* We can start at the segments we've already found. */
1593 count = real->line_char_offset - real->segment_char_offset;
1594 seg = _gtk_text_iter_get_indexable_segment (iter);
1598 /* count whole line. */
1599 seg = real->line->segments;
1606 count += seg->char_count;
1615 * gtk_text_iter_get_bytes_in_line:
1616 * @iter: an iterator
1618 * Returns the number of bytes in the line containing @iter,
1619 * including the paragraph delimiters.
1621 * Return value: number of bytes in the line
1624 gtk_text_iter_get_bytes_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_byte_offset >= 0)
1641 /* We can start at the segments we've already found. */
1642 count = real->line_byte_offset - real->segment_byte_offset;
1643 seg = _gtk_text_iter_get_indexable_segment (iter);
1647 /* count whole line. */
1648 seg = real->line->segments;
1654 count += seg->byte_count;
1663 * gtk_text_iter_get_attributes:
1664 * @iter: an iterator
1665 * @values: a #GtkTextAttributes to be filled in
1667 * Computes the effect of any tags applied to this spot in the
1668 * text. The @values parameter should be initialized to the default
1669 * settings you wish to use if no tags are in effect. You'd typically
1670 * obtain the defaults from gtk_text_view_get_default_attributes().
1672 * gtk_text_iter_get_attributes () will modify @values, applying the
1673 * effects of any tags present at @iter. If any tags affected @values,
1674 * the function returns %TRUE.
1676 * Return value: %TRUE if @values was modified
1679 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1680 GtkTextAttributes *values)
1685 /* Get the tags at this spot */
1686 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1688 /* No tags, use default style */
1689 if (tags == NULL || tag_count == 0)
1697 /* Sort tags in ascending order of priority */
1698 _gtk_text_tag_array_sort (tags, tag_count);
1700 _gtk_text_attributes_fill_from_tags (values,
1710 * Increments/decrements
1713 /* The return value of this indicates WHETHER WE MOVED.
1714 * The return value of public functions indicates
1715 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1717 * This function will not change the iterator if
1718 * it's already on the last (end iter) line, i.e. it
1719 * won't move to the end of the last line.
1722 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1724 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1726 GtkTextLine *new_line;
1728 new_line = _gtk_text_line_next (real->line);
1729 g_assert (new_line);
1730 g_assert (new_line != real->line);
1731 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1733 real->line = new_line;
1735 real->line_byte_offset = 0;
1736 real->line_char_offset = 0;
1738 real->segment_byte_offset = 0;
1739 real->segment_char_offset = 0;
1741 /* Find first segments in new line */
1742 real->any_segment = real->line->segments;
1743 real->segment = real->any_segment;
1744 while (real->segment->char_count == 0)
1745 real->segment = real->segment->next;
1751 /* There is no way to move forward a line; we were already at
1752 * the line containing the end iterator.
1753 * However we may not be at the end iterator itself.
1761 /* The return value of this indicates WHETHER WE MOVED.
1762 * The return value of public functions indicates
1763 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1766 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1768 GtkTextLine *new_line;
1770 new_line = _gtk_text_line_previous (real->line);
1772 g_assert (new_line != real->line);
1774 if (new_line != NULL)
1776 real->line = new_line;
1778 real->line_byte_offset = 0;
1779 real->line_char_offset = 0;
1781 real->segment_byte_offset = 0;
1782 real->segment_char_offset = 0;
1784 /* Find first segments in new line */
1785 real->any_segment = real->line->segments;
1786 real->segment = real->any_segment;
1787 while (real->segment->char_count == 0)
1788 real->segment = real->segment->next;
1794 /* There is no way to move backward; we were already
1795 at the first line. */
1797 /* We leave real->line as-is */
1799 /* Note that we didn't clamp to the start of the first line. */
1805 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1809 forward_char (GtkTextRealIter *real)
1811 GtkTextIter *iter = (GtkTextIter*)real;
1813 check_invariants ((GtkTextIter*)real);
1815 ensure_char_offsets (real);
1817 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1819 /* Need to move to the next segment; if no next segment,
1820 need to move to next line. */
1821 return _gtk_text_iter_forward_indexable_segment (iter);
1825 /* Just moving within a segment. Keep byte count
1826 up-to-date, if it was already up-to-date. */
1828 g_assert (real->segment->type == >k_text_char_type);
1830 if (real->line_byte_offset >= 0)
1833 const char * start =
1834 real->segment->body.chars + real->segment_byte_offset;
1836 bytes = g_utf8_next_char (start) - start;
1838 real->line_byte_offset += bytes;
1839 real->segment_byte_offset += bytes;
1841 g_assert (real->segment_byte_offset < real->segment->byte_count);
1844 real->line_char_offset += 1;
1845 real->segment_char_offset += 1;
1847 adjust_char_index (real, 1);
1849 g_assert (real->segment_char_offset < real->segment->char_count);
1851 /* We moved into the middle of a segment, so the any_segment
1852 must now be the segment we're in the middle of. */
1853 real->any_segment = real->segment;
1855 check_invariants ((GtkTextIter*)real);
1857 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1865 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1867 /* Need to move to the next segment; if no next segment,
1868 need to move to next line. */
1869 GtkTextLineSegment *seg;
1870 GtkTextLineSegment *any_seg;
1871 GtkTextRealIter *real;
1875 g_return_val_if_fail (iter != NULL, FALSE);
1877 real = gtk_text_iter_make_real (iter);
1882 check_invariants (iter);
1884 if (real->line_char_offset >= 0)
1886 chars_skipped = real->segment->char_count - real->segment_char_offset;
1887 g_assert (chars_skipped > 0);
1892 if (real->line_byte_offset >= 0)
1894 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1895 g_assert (bytes_skipped > 0);
1900 /* Get first segment of any kind */
1901 any_seg = real->segment->next;
1902 /* skip non-indexable segments, if any */
1904 while (seg != NULL && seg->char_count == 0)
1909 real->any_segment = any_seg;
1910 real->segment = seg;
1912 if (real->line_byte_offset >= 0)
1914 g_assert (bytes_skipped > 0);
1915 real->segment_byte_offset = 0;
1916 real->line_byte_offset += bytes_skipped;
1919 if (real->line_char_offset >= 0)
1921 g_assert (chars_skipped > 0);
1922 real->segment_char_offset = 0;
1923 real->line_char_offset += chars_skipped;
1924 adjust_char_index (real, chars_skipped);
1927 check_invariants (iter);
1933 /* End of the line */
1934 if (forward_line_leaving_caches_unmodified (real))
1936 adjust_line_number (real, 1);
1937 if (real->line_char_offset >= 0)
1938 adjust_char_index (real, chars_skipped);
1940 g_assert (real->line_byte_offset == 0);
1941 g_assert (real->line_char_offset == 0);
1942 g_assert (real->segment_byte_offset == 0);
1943 g_assert (real->segment_char_offset == 0);
1944 g_assert (gtk_text_iter_starts_line (iter));
1946 check_invariants (iter);
1948 if (gtk_text_iter_is_end (iter))
1957 g_assert (gtk_text_iter_is_end (iter));
1959 check_invariants (iter);
1967 at_last_indexable_segment (GtkTextRealIter *real)
1969 GtkTextLineSegment *seg;
1971 /* Return TRUE if there are no indexable segments after
1975 seg = real->segment->next;
1978 if (seg->char_count > 0)
1985 /* Goes back to the start of the next segment, even if
1986 * we're not at the start of the current segment (always
1987 * ends up on a different segment if it returns TRUE)
1990 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1992 /* Move to the start of the previous segment; if no previous
1993 * segment, to the last segment in the previous line. This is
1994 * inherently a bit inefficient due to the singly-linked list and
1995 * tree nodes, but we can't afford the RAM for doubly-linked.
1997 GtkTextRealIter *real;
1998 GtkTextLineSegment *seg;
1999 GtkTextLineSegment *any_seg;
2000 GtkTextLineSegment *prev_seg;
2001 GtkTextLineSegment *prev_any_seg;
2005 g_return_val_if_fail (iter != NULL, FALSE);
2007 real = gtk_text_iter_make_real (iter);
2012 check_invariants (iter);
2014 /* Find first segments in line */
2015 any_seg = real->line->segments;
2017 while (seg->char_count == 0)
2020 if (seg == real->segment)
2022 /* Could probably do this case faster by hand-coding the
2026 /* We were already at the start of a line;
2027 * go back to the previous line.
2029 if (gtk_text_iter_backward_line (iter))
2031 /* Go forward to last indexable segment in line. */
2032 while (!at_last_indexable_segment (real))
2033 _gtk_text_iter_forward_indexable_segment (iter);
2035 check_invariants (iter);
2040 return FALSE; /* We were at the start of the first line. */
2043 /* We must be in the middle of a line; so find the indexable
2044 * segment just before our current segment.
2046 g_assert (seg != real->segment);
2047 while (seg != real->segment)
2050 prev_any_seg = any_seg;
2052 any_seg = seg->next;
2054 while (seg->char_count == 0)
2058 g_assert (prev_seg != NULL);
2059 g_assert (prev_any_seg != NULL);
2060 g_assert (prev_seg->char_count > 0);
2062 /* We skipped the entire previous segment, plus any
2063 * chars we were into the current segment.
2065 if (real->segment_byte_offset >= 0)
2066 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2070 if (real->segment_char_offset >= 0)
2071 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2075 real->segment = prev_seg;
2076 real->any_segment = prev_any_seg;
2077 real->segment_byte_offset = 0;
2078 real->segment_char_offset = 0;
2080 if (bytes_skipped >= 0)
2082 if (real->line_byte_offset >= 0)
2084 real->line_byte_offset -= bytes_skipped;
2085 g_assert (real->line_byte_offset >= 0);
2089 real->line_byte_offset = -1;
2091 if (chars_skipped >= 0)
2093 if (real->line_char_offset >= 0)
2095 real->line_char_offset -= chars_skipped;
2096 g_assert (real->line_char_offset >= 0);
2099 if (real->cached_char_index >= 0)
2101 real->cached_char_index -= chars_skipped;
2102 g_assert (real->cached_char_index >= 0);
2107 real->line_char_offset = -1;
2108 real->cached_char_index = -1;
2111 /* line number is unchanged. */
2113 check_invariants (iter);
2119 * gtk_text_iter_forward_char:
2120 * @iter: an iterator
2122 * Moves @iter forward by one character offset. Note that images
2123 * embedded in the buffer occupy 1 character slot, so
2124 * gtk_text_iter_forward_char () may actually move onto an image instead
2125 * of a character, if you have images in your buffer. If @iter is the
2126 * end iterator or one character before it, @iter will now point at
2127 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2128 * convenience when writing loops.
2130 * Return value: whether the new position is the end iterator
2133 gtk_text_iter_forward_char (GtkTextIter *iter)
2135 GtkTextRealIter *real;
2137 g_return_val_if_fail (iter != NULL, FALSE);
2139 real = gtk_text_iter_make_real (iter);
2145 check_invariants (iter);
2146 return forward_char (real);
2151 * gtk_text_iter_backward_char:
2152 * @iter: an iterator
2154 * Moves backward by one character offset. Returns TRUE if movement
2155 * was possible; if @iter was the first in the buffer (character
2156 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2159 * Return value: whether movement was possible
2162 gtk_text_iter_backward_char (GtkTextIter *iter)
2164 g_return_val_if_fail (iter != NULL, FALSE);
2166 check_invariants (iter);
2168 return gtk_text_iter_backward_chars (iter, 1);
2172 Definitely we should try to linear scan as often as possible for
2173 movement within a single line, because we can't use the BTree to
2174 speed within-line searches up; for movement between lines, we would
2175 like to avoid the linear scan probably.
2177 Instead of using this constant, it might be nice to cache the line
2178 length in the iterator and linear scan if motion is within a single
2181 I guess you'd have to profile the various approaches.
2183 #define MAX_LINEAR_SCAN 150
2187 * gtk_text_iter_forward_chars:
2188 * @iter: an iterator
2189 * @count: number of characters to move, may be negative
2191 * Moves @count characters if possible (if @count would move past the
2192 * start or end of the buffer, moves to the start or end of the
2193 * buffer). The return value indicates whether the new position of
2194 * @iter is different from its original position, and dereferenceable
2195 * (the last iterator in the buffer is not dereferenceable). If @count
2196 * is 0, the function does nothing and returns FALSE.
2198 * Return value: whether @iter moved and is dereferenceable
2201 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2203 GtkTextRealIter *real;
2205 g_return_val_if_fail (iter != NULL, FALSE);
2207 FIX_OVERFLOWS (count);
2209 real = gtk_text_iter_make_real (iter);
2213 else if (count == 0)
2216 return gtk_text_iter_backward_chars (iter, 0 - count);
2217 else if (count < MAX_LINEAR_SCAN)
2219 check_invariants (iter);
2223 if (!forward_char (real))
2228 return forward_char (real);
2232 gint current_char_index;
2233 gint new_char_index;
2235 check_invariants (iter);
2237 current_char_index = gtk_text_iter_get_offset (iter);
2239 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2240 return FALSE; /* can't move forward */
2242 new_char_index = current_char_index + count;
2243 gtk_text_iter_set_offset (iter, new_char_index);
2245 check_invariants (iter);
2247 /* Return FALSE if we're on the non-dereferenceable end
2250 if (gtk_text_iter_is_end (iter))
2258 * gtk_text_iter_backward_chars:
2259 * @iter: an iterator
2260 * @count: number of characters to move
2262 * Moves @count characters backward, if possible (if @count would move
2263 * past the start or end of the buffer, moves to the start or end of
2264 * the buffer). The return value indicates whether the iterator moved
2265 * onto a dereferenceable position; if the iterator didn't move, or
2266 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2267 * the function does nothing and returns FALSE.
2269 * Return value: whether @iter moved and is dereferenceable
2273 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2275 GtkTextRealIter *real;
2277 g_return_val_if_fail (iter != NULL, FALSE);
2279 FIX_OVERFLOWS (count);
2281 real = gtk_text_iter_make_real (iter);
2285 else if (count == 0)
2288 return gtk_text_iter_forward_chars (iter, 0 - count);
2290 ensure_char_offsets (real);
2291 check_invariants (iter);
2293 if (count <= real->segment_char_offset)
2295 /* Optimize the within-segment case */
2296 g_assert (real->segment->char_count > 0);
2297 g_assert (real->segment->type == >k_text_char_type);
2299 real->segment_char_offset -= count;
2300 g_assert (real->segment_char_offset >= 0);
2302 if (real->line_byte_offset >= 0)
2304 gint new_byte_offset;
2307 new_byte_offset = 0;
2309 while (i < real->segment_char_offset)
2311 const char * start = real->segment->body.chars + new_byte_offset;
2312 new_byte_offset += g_utf8_next_char (start) - start;
2317 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2318 real->segment_byte_offset = new_byte_offset;
2321 real->line_char_offset -= count;
2323 adjust_char_index (real, 0 - count);
2325 check_invariants (iter);
2331 /* We need to go back into previous segments. For now,
2332 * just keep this really simple. FIXME
2333 * use backward_indexable_segment.
2335 if (TRUE || count > MAX_LINEAR_SCAN)
2337 gint current_char_index;
2338 gint new_char_index;
2340 current_char_index = gtk_text_iter_get_offset (iter);
2342 if (current_char_index == 0)
2343 return FALSE; /* can't move backward */
2345 new_char_index = current_char_index - count;
2346 if (new_char_index < 0)
2348 gtk_text_iter_set_offset (iter, new_char_index);
2350 check_invariants (iter);
2356 /* FIXME backward_indexable_segment here */
2365 /* These two can't be implemented efficiently (always have to use
2366 * a linear scan, since that's the only way to find all the non-text
2371 * gtk_text_iter_forward_text_chars:
2372 * @iter: a #GtkTextIter
2373 * @count: number of chars to move
2375 * Moves forward by @count text characters (pixbufs, widgets,
2376 * etc. do not count as characters for this). Equivalent to moving
2377 * through the results of gtk_text_iter_get_text (), rather than
2378 * gtk_text_iter_get_slice ().
2380 * Return value: whether @iter moved and is dereferenceable
2383 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2392 * gtk_text_iter_forward_text_chars:
2393 * @iter: a #GtkTextIter
2394 * @count: number of chars to move
2396 * Moves backward by @count text characters (pixbufs, widgets,
2397 * etc. do not count as characters for this). Equivalent to moving
2398 * through the results of gtk_text_iter_get_text (), rather than
2399 * gtk_text_iter_get_slice ().
2401 * Return value: whether @iter moved and is dereferenceable
2404 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2413 * gtk_text_iter_forward_line:
2414 * @iter: an iterator
2416 * Moves @iter to the start of the next line. Returns TRUE if there
2417 * was a next line to move to, and FALSE if @iter was simply moved to
2418 * the end of the buffer and is now not dereferenceable, or if @iter was
2419 * already at the end of the buffer.
2421 * Return value: whether @iter can be dereferenced
2424 gtk_text_iter_forward_line (GtkTextIter *iter)
2426 GtkTextRealIter *real;
2428 g_return_val_if_fail (iter != NULL, FALSE);
2430 real = gtk_text_iter_make_real (iter);
2435 check_invariants (iter);
2437 if (forward_line_leaving_caches_unmodified (real))
2439 invalidate_char_index (real);
2440 adjust_line_number (real, 1);
2442 check_invariants (iter);
2444 if (gtk_text_iter_is_end (iter))
2451 /* On the last line, move to end of it */
2453 if (!gtk_text_iter_is_end (iter))
2454 gtk_text_iter_forward_to_end (iter);
2456 check_invariants (iter);
2462 * gtk_text_iter_backward_line:
2463 * @iter: an iterator
2465 * Moves @iter to the start of the previous line. Returns TRUE if
2466 * @iter could be moved; i.e. if @iter was at character offset 0, this
2467 * function returns FALSE. Therefore if @iter was already on line 0,
2468 * but not at the start of the line, @iter is snapped to the start of
2469 * the line and the function returns TRUE. (Note that this implies that
2470 * in a loop calling this function, the line number may not change on
2471 * every iteration, if your first iteration is on line 0.)
2473 * Return value: whether @iter moved
2476 gtk_text_iter_backward_line (GtkTextIter *iter)
2478 GtkTextLine *new_line;
2479 GtkTextRealIter *real;
2480 gboolean offset_will_change;
2483 g_return_val_if_fail (iter != NULL, FALSE);
2485 real = gtk_text_iter_make_real (iter);
2490 check_invariants (iter);
2492 new_line = _gtk_text_line_previous (real->line);
2494 offset_will_change = FALSE;
2495 if (real->line_char_offset > 0)
2496 offset_will_change = TRUE;
2498 if (new_line != NULL)
2500 real->line = new_line;
2502 adjust_line_number (real, -1);
2506 if (!offset_will_change)
2510 invalidate_char_index (real);
2512 real->line_byte_offset = 0;
2513 real->line_char_offset = 0;
2515 real->segment_byte_offset = 0;
2516 real->segment_char_offset = 0;
2518 /* Find first segment in line */
2519 real->any_segment = real->line->segments;
2520 real->segment = _gtk_text_line_byte_to_segment (real->line,
2523 g_assert (offset == 0);
2525 /* Note that if we are on the first line, we snap to the start of
2526 * the first line and return TRUE, so TRUE means the iterator
2527 * changed, not that the line changed; this is maybe a bit
2528 * weird. I'm not sure there's an obvious right thing to do though.
2531 check_invariants (iter);
2538 * gtk_text_iter_forward_lines:
2539 * @iter: a #GtkTextIter
2540 * @count: number of lines to move forward
2542 * Moves @count lines forward, if possible (if @count would move
2543 * past the start or end of the buffer, moves to the start or end of
2544 * the buffer). The return value indicates whether the iterator moved
2545 * onto a dereferenceable position; if the iterator didn't move, or
2546 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2547 * the function does nothing and returns FALSE. If @count is negative,
2548 * moves backward by 0 - @count lines.
2550 * Return value: whether @iter moved and is dereferenceable
2553 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2555 FIX_OVERFLOWS (count);
2558 return gtk_text_iter_backward_lines (iter, 0 - count);
2559 else if (count == 0)
2561 else if (count == 1)
2563 check_invariants (iter);
2564 return gtk_text_iter_forward_line (iter);
2570 old_line = gtk_text_iter_get_line (iter);
2572 gtk_text_iter_set_line (iter, old_line + count);
2574 check_invariants (iter);
2576 /* return whether it moved, and is dereferenceable. */
2578 (gtk_text_iter_get_line (iter) != old_line) &&
2579 !gtk_text_iter_is_end (iter);
2584 * gtk_text_iter_backward_lines:
2585 * @iter: a #GtkTextIter
2586 * @count: number of lines to move backward
2588 * Moves @count lines backward, if possible (if @count would move
2589 * past the start or end of the buffer, moves to the start or end of
2590 * the buffer). The return value indicates whether the iterator moved
2591 * onto a dereferenceable position; if the iterator didn't move, or
2592 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2593 * the function does nothing and returns FALSE. If @count is negative,
2594 * moves forward by 0 - @count lines.
2596 * Return value: whether @iter moved and is dereferenceable
2599 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2601 FIX_OVERFLOWS (count);
2604 return gtk_text_iter_forward_lines (iter, 0 - count);
2605 else if (count == 0)
2607 else if (count == 1)
2609 return gtk_text_iter_backward_line (iter);
2615 old_line = gtk_text_iter_get_line (iter);
2617 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2619 return (gtk_text_iter_get_line (iter) != old_line);
2623 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2628 gboolean already_moved_initially);
2630 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2638 find_word_end_func (const PangoLogAttr *attrs,
2643 gboolean already_moved_initially)
2645 if (!already_moved_initially)
2648 /* Find end of next word */
2649 while (offset < min_offset + len &&
2650 !attrs[offset].is_word_end)
2653 *found_offset = offset;
2655 return offset < min_offset + len;
2659 is_word_end_func (const PangoLogAttr *attrs,
2664 return attrs[offset].is_word_end;
2668 find_word_start_func (const PangoLogAttr *attrs,
2673 gboolean already_moved_initially)
2675 if (!already_moved_initially)
2678 /* Find start of prev word */
2679 while (offset >= min_offset &&
2680 !attrs[offset].is_word_start)
2683 *found_offset = offset;
2685 return offset >= min_offset;
2689 is_word_start_func (const PangoLogAttr *attrs,
2694 return attrs[offset].is_word_start;
2698 inside_word_func (const PangoLogAttr *attrs,
2703 /* Find next word start or end */
2704 while (offset >= min_offset &&
2705 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2708 return attrs[offset].is_word_start;
2711 /* Sentence funcs */
2714 find_sentence_end_func (const PangoLogAttr *attrs,
2719 gboolean already_moved_initially)
2721 if (!already_moved_initially)
2724 /* Find end of next sentence */
2725 while (offset < min_offset + len &&
2726 !attrs[offset].is_sentence_end)
2729 *found_offset = offset;
2731 return offset < min_offset + len;
2735 is_sentence_end_func (const PangoLogAttr *attrs,
2740 return attrs[offset].is_sentence_end;
2744 find_sentence_start_func (const PangoLogAttr *attrs,
2749 gboolean already_moved_initially)
2751 if (!already_moved_initially)
2754 /* Find start of prev sentence */
2755 while (offset >= min_offset &&
2756 !attrs[offset].is_sentence_start)
2759 *found_offset = offset;
2761 return offset >= min_offset;
2765 is_sentence_start_func (const PangoLogAttr *attrs,
2770 return attrs[offset].is_sentence_start;
2774 inside_sentence_func (const PangoLogAttr *attrs,
2779 /* Find next sentence start or end */
2780 while (offset >= min_offset &&
2781 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2784 return attrs[offset].is_sentence_start;
2788 test_log_attrs (const GtkTextIter *iter,
2789 TestLogAttrFunc func)
2792 const PangoLogAttr *attrs;
2794 gboolean result = FALSE;
2796 g_return_val_if_fail (iter != NULL, FALSE);
2798 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2801 offset = gtk_text_iter_get_line_offset (iter);
2803 /* char_len may be 0 and attrs will be NULL if so, if
2804 * iter is the end iter and the last line is empty
2807 if (offset < char_len)
2808 result = (* func) (attrs, offset, 0, char_len);
2814 find_line_log_attrs (const GtkTextIter *iter,
2815 FindLogAttrFunc func,
2817 gboolean already_moved_initially)
2820 const PangoLogAttr *attrs;
2822 gboolean result = FALSE;
2824 g_return_val_if_fail (iter != NULL, FALSE);
2826 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2829 offset = gtk_text_iter_get_line_offset (iter);
2831 /* char_len may be 0 and attrs will be NULL if so, if
2832 * iter is the end iter and the last line is empty
2835 if (offset < char_len)
2836 result = (* func) (attrs, offset, 0, char_len, found_offset,
2837 already_moved_initially);
2842 /* FIXME this function is very, very gratuitously slow */
2844 find_by_log_attrs (GtkTextIter *iter,
2845 FindLogAttrFunc func,
2847 gboolean already_moved_initially)
2851 gboolean found = FALSE;
2853 g_return_val_if_fail (iter != NULL, FALSE);
2857 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2863 if (gtk_text_iter_forward_line (iter))
2864 return find_by_log_attrs (iter, func, forward,
2871 /* go to end of previous line */
2872 gtk_text_iter_set_line_offset (iter, 0);
2874 if (gtk_text_iter_backward_char (iter))
2875 return find_by_log_attrs (iter, func, forward,
2883 gtk_text_iter_set_line_offset (iter, offset);
2886 !gtk_text_iter_equal (iter, &orig) &&
2887 !gtk_text_iter_is_end (iter);
2892 * gtk_text_iter_forward_word_end:
2893 * @iter: a #GtkTextIter
2895 * Moves forward to the next word end. (If @iter is currently on a
2896 * word end, moves forward to the next one after that.) Word breaks
2897 * are determined by Pango and should be correct for nearly any
2898 * language (if not, the correct fix would be to the Pango word break
2901 * Return value: %TRUE if @iter moved and is not the end iterator
2904 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2906 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2910 * gtk_text_iter_backward_word_start:
2911 * @iter: a #GtkTextIter
2913 * Moves backward to the next word start. (If @iter is currently on a
2914 * word start, moves backward to the next one after that.) Word breaks
2915 * are determined by Pango and should be correct for nearly any
2916 * language (if not, the correct fix would be to the Pango word break
2919 * Return value: %TRUE if @iter moved and is not the end iterator
2922 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2924 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2927 /* FIXME a loop around a truly slow function means
2928 * a truly spectacularly slow function.
2932 * gtk_text_iter_forward_word_ends:
2933 * @iter: a #GtkTextIter
2934 * @count: number of times to move
2936 * Calls gtk_text_iter_forward_word_end() up to @count times.
2938 * Return value: %TRUE if @iter moved and is not the end iterator
2941 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2944 g_return_val_if_fail (iter != NULL, FALSE);
2946 FIX_OVERFLOWS (count);
2952 return gtk_text_iter_backward_word_starts (iter, -count);
2954 if (!gtk_text_iter_forward_word_end (iter))
2960 if (!gtk_text_iter_forward_word_end (iter))
2968 * gtk_text_iter_backward_word_starts
2969 * @iter: a #GtkTextIter
2970 * @count: number of times to move
2972 * Calls gtk_text_iter_backward_word_starts() up to @count times.
2974 * Return value: %TRUE if @iter moved and is not the end iterator
2977 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2980 g_return_val_if_fail (iter != NULL, FALSE);
2982 FIX_OVERFLOWS (count);
2985 return gtk_text_iter_forward_word_ends (iter, -count);
2987 if (!gtk_text_iter_backward_word_start (iter))
2993 if (!gtk_text_iter_backward_word_start (iter))
3001 * gtk_text_iter_starts_word:
3002 * @iter: a #GtkTextIter
3004 * Determines whether @iter begins a natural-language word. Word
3005 * breaks are determined by Pango and should be correct for nearly any
3006 * language (if not, the correct fix would be to the Pango word break
3009 * Return value: %TRUE if @iter is at the start of a word
3012 gtk_text_iter_starts_word (const GtkTextIter *iter)
3014 return test_log_attrs (iter, is_word_start_func);
3018 * gtk_text_iter_ends_word:
3019 * @iter: a #GtkTextIter
3021 * Determines whether @iter ends a natural-language word. Word breaks
3022 * are determined by Pango and should be correct for nearly any
3023 * language (if not, the correct fix would be to the Pango word break
3026 * Return value: %TRUE if @iter is at the end of a word
3029 gtk_text_iter_ends_word (const GtkTextIter *iter)
3031 return test_log_attrs (iter, is_word_end_func);
3035 * gtk_text_iter_inside_word:
3036 * @iter: a #GtkTextIter
3038 * Determines whether @iter is inside a natural-language word (as
3039 * opposed to say inside some whitespace). Word breaks are determined
3040 * by Pango and should be correct for nearly any language (if not, the
3041 * correct fix would be to the Pango word break algorithms).
3043 * Return value: %TRUE if @iter is inside a word
3046 gtk_text_iter_inside_word (const GtkTextIter *iter)
3048 return test_log_attrs (iter, inside_word_func);
3052 * gtk_text_iter_starts_sentence:
3053 * @iter: a #GtkTextIter
3055 * Determines whether @iter begins a sentence. Sentence boundaries are
3056 * determined by Pango and should be correct for nearly any language
3057 * (if not, the correct fix would be to the Pango text boundary
3060 * Return value: %TRUE if @iter is at the start of a sentence.
3063 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3065 return test_log_attrs (iter, is_sentence_start_func);
3069 * gtk_text_iter_ends_sentence:
3070 * @iter: a #GtkTextIter
3072 * Determines whether @iter ends a sentence. Sentence boundaries are
3073 * determined by Pango and should be correct for nearly any language
3074 * (if not, the correct fix would be to the Pango text boundary
3077 * Return value: %TRUE if @iter is at the end of a sentence.
3080 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3082 return test_log_attrs (iter, is_sentence_end_func);
3086 * gtk_text_iter_inside_sentence:
3087 * @iter: a #GtkTextIter
3089 * Determines whether @iter is inside a sentence (as opposed to in
3090 * between two sentences, e.g. after a period and before the first
3091 * letter of the next sentence). Sentence boundaries are determined
3092 * by Pango and should be correct for nearly any language (if not, the
3093 * correct fix would be to the Pango text boundary algorithms).
3095 * Return value: %TRUE if @iter is inside a sentence.
3098 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3100 return test_log_attrs (iter, inside_sentence_func);
3104 * gtk_text_iter_forward_sentence_end:
3105 * @iter: a #GtkTextIter
3107 * Moves forward to the next sentence end. (If @iter is at the end of
3108 * a sentence, moves to the next end of sentence.) Sentence
3109 * boundaries are determined by Pango and should be correct for nearly
3110 * any language (if not, the correct fix would be to the Pango text
3111 * boundary algorithms).
3113 * Return value: %TRUE if @iter moved and is not the end iterator
3116 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3118 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3122 * gtk_text_iter_backward_sentence_start:
3123 * @iter: a #GtkTextIter
3125 * Moves backward to the next sentence start; if @iter is already at
3126 * the start of a sentence, moves backward to the next one. Sentence
3127 * boundaries are determined by Pango and should be correct for nearly
3128 * any language (if not, the correct fix would be to the Pango text
3129 * boundary algorithms).
3131 * Return value: %TRUE if @iter moved and is not the end iterator
3134 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3136 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3139 /* FIXME a loop around a truly slow function means
3140 * a truly spectacularly slow function.
3143 * gtk_text_iter_forward_sentence_ends:
3144 * @iter: a #GtkTextIter
3145 * @count: number of sentences to move
3147 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3148 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3149 * negative, moves backward instead of forward.
3151 * Return value: %TRUE if @iter moved and is not the end iterator
3154 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3157 g_return_val_if_fail (iter != NULL, FALSE);
3163 return gtk_text_iter_backward_sentence_starts (iter, -count);
3165 if (!gtk_text_iter_forward_sentence_end (iter))
3171 if (!gtk_text_iter_forward_sentence_end (iter))
3179 * gtk_text_iter_backward_sentence_starts:
3180 * @iter: a #GtkTextIter
3181 * @count: number of sentences to move
3183 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3184 * or until it returns %FALSE. If @count is negative, moves forward
3185 * instead of backward.
3187 * Return value: %TRUE if @iter moved and is not the end iterator
3190 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3193 g_return_val_if_fail (iter != NULL, FALSE);
3196 return gtk_text_iter_forward_sentence_ends (iter, -count);
3198 if (!gtk_text_iter_backward_sentence_start (iter))
3204 if (!gtk_text_iter_backward_sentence_start (iter))
3212 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3217 gboolean already_moved_initially)
3219 if (!already_moved_initially)
3222 while (offset < (min_offset + len) &&
3223 !attrs[offset].is_cursor_position)
3226 *found_offset = offset;
3228 return offset < (min_offset + len);
3232 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3237 gboolean already_moved_initially)
3239 if (!already_moved_initially)
3242 while (offset > min_offset &&
3243 !attrs[offset].is_cursor_position)
3246 *found_offset = offset;
3248 return offset >= min_offset;
3252 is_cursor_pos_func (const PangoLogAttr *attrs,
3257 return attrs[offset].is_cursor_position;
3261 * gtk_text_iter_forward_cursor_position:
3262 * @iter: a #GtkTextIter
3264 * Moves @iter forward by a single cursor position. Cursor positions
3265 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3266 * surprisingly, there may not be a cursor position between all
3267 * characters. The most common example for European languages would be
3268 * a carriage return/newline sequence. For some Unicode characters,
3269 * the equivalent of say the letter "a" with an accent mark will be
3270 * represented as two characters, first the letter then a "combining
3271 * mark" that causes the accent to be rendered; so the cursor can't go
3272 * between those two characters. See also the #PangoLogAttr structure and
3273 * pango_break() function.
3275 * Return value: %TRUE if we moved and the new position is dereferenceable
3278 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3280 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3284 * gtk_text_iter_backward_cursor_position:
3285 * @iter: a #GtkTextIter
3287 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3289 * Return value: %TRUE if we moved and the new position is dereferenceable
3292 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3294 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3298 * gtk_text_iter_forward_cursor_positions:
3299 * @iter: a #GtkTextIter
3300 * @count: number of positions to move
3302 * Moves up to @count cursor positions. See
3303 * gtk_text_iter_forward_cursor_position() for details.
3305 * Return value: %TRUE if we moved and the new position is dereferenceable
3308 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3311 g_return_val_if_fail (iter != NULL, FALSE);
3313 FIX_OVERFLOWS (count);
3319 return gtk_text_iter_backward_cursor_positions (iter, -count);
3321 if (!gtk_text_iter_forward_cursor_position (iter))
3327 if (!gtk_text_iter_forward_cursor_position (iter))
3335 * gtk_text_iter_backward_cursor_positions:
3336 * @iter: a #GtkTextIter
3337 * @count: number of positions to move
3339 * Moves up to @count cursor positions. See
3340 * gtk_text_iter_forward_cursor_position() for details.
3342 * Return value: %TRUE if we moved and the new position is dereferenceable
3345 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3348 g_return_val_if_fail (iter != NULL, FALSE);
3350 FIX_OVERFLOWS (count);
3356 return gtk_text_iter_forward_cursor_positions (iter, -count);
3358 if (!gtk_text_iter_backward_cursor_position (iter))
3364 if (!gtk_text_iter_backward_cursor_position (iter))
3372 * gtk_text_iter_is_cursor_position:
3373 * @iter: a #GtkTextIter
3375 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3376 * pango_break() for details on what a cursor position is.
3378 * Return value: %TRUE if the cursor can be placed at @iter
3381 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3383 return test_log_attrs (iter, is_cursor_pos_func);
3387 * gtk_text_iter_set_line_offset:
3388 * @iter: a #GtkTextIter
3389 * @char_on_line: a character offset relative to the start of @iter's current line
3391 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3392 * (not byte) offset. The given character offset must be less than or
3393 * equal to the number of characters in the line; if equal, @iter
3394 * moves to the start of the next line. See
3395 * gtk_text_iter_set_line_index() if you have a byte index rather than
3396 * a character offset.
3400 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3403 GtkTextRealIter *real;
3406 g_return_if_fail (iter != NULL);
3408 real = gtk_text_iter_make_surreal (iter);
3413 check_invariants (iter);
3415 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3417 g_return_if_fail (char_on_line <= chars_in_line);
3419 if (char_on_line < chars_in_line)
3420 iter_set_from_char_offset (real, real->line, char_on_line);
3422 gtk_text_iter_forward_line (iter); /* set to start of next line */
3424 check_invariants (iter);
3428 * gtk_text_iter_set_line_index:
3429 * @iter: a #GtkTextIter
3430 * @byte_on_line: a byte index relative to the start of @iter's current line
3432 * Same as gtk_text_iter_set_line_offset(), but works with a
3433 * <emphasis>byte</emphasis> index. The given byte index must be at
3434 * the start of a character, it can't be in the middle of a UTF-8
3435 * encoded character.
3439 gtk_text_iter_set_line_index (GtkTextIter *iter,
3442 GtkTextRealIter *real;
3445 g_return_if_fail (iter != NULL);
3447 real = gtk_text_iter_make_surreal (iter);
3452 check_invariants (iter);
3454 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3456 g_return_if_fail (byte_on_line <= bytes_in_line);
3458 if (byte_on_line < bytes_in_line)
3459 iter_set_from_byte_offset (real, real->line, byte_on_line);
3461 gtk_text_iter_forward_line (iter);
3463 if (real->segment->type == >k_text_char_type &&
3464 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3465 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3466 "character; this will crash the text buffer. "
3467 "Byte indexes must refer to the start of a character.",
3468 G_STRLOC, byte_on_line);
3470 check_invariants (iter);
3475 * gtk_text_iter_set_visible_line_offset:
3476 * @iter: a #GtkTextIter
3477 * @char_on_line: a character offset
3479 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3480 * characters, i.e. text with a tag making it invisible is not
3481 * counted in the offset.
3484 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3487 gint chars_seen = 0;
3490 g_return_if_fail (iter != NULL);
3494 /* For now we use a ludicrously slow implementation */
3495 while (chars_seen < char_on_line)
3497 if (!_gtk_text_btree_char_is_invisible (&pos))
3500 if (!gtk_text_iter_forward_char (&pos))
3503 if (chars_seen == char_on_line)
3507 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3510 gtk_text_iter_forward_line (iter);
3514 bytes_in_char (GtkTextIter *iter)
3516 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3520 * gtk_text_iter_set_visible_line_index:
3521 * @iter: a #GtkTextIter
3522 * @byte_on_line: a byte index
3524 * Like gtk_text_iter_set_line_index(), but the index is in visible
3525 * bytes, i.e. text with a tag making it invisible is not counted
3529 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3532 gint bytes_seen = 0;
3535 g_return_if_fail (iter != NULL);
3539 /* For now we use a ludicrously slow implementation */
3540 while (bytes_seen < byte_on_line)
3542 if (!_gtk_text_btree_char_is_invisible (&pos))
3543 bytes_seen += bytes_in_char (&pos);
3545 if (!gtk_text_iter_forward_char (&pos))
3548 if (bytes_seen >= byte_on_line)
3552 if (bytes_seen > byte_on_line)
3553 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3554 "character; this will crash the text buffer. "
3555 "Byte indexes must refer to the start of a character.",
3556 G_STRLOC, byte_on_line);
3558 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3561 gtk_text_iter_forward_line (iter);
3565 * gtk_text_iter_set_line:
3566 * @iter: a #GtkTextIter
3567 * @line_number: line number (counted from 0)
3569 * Moves iterator @iter to the start of the line @line_number.
3573 gtk_text_iter_set_line (GtkTextIter *iter,
3578 GtkTextRealIter *real;
3580 g_return_if_fail (iter != NULL);
3582 real = gtk_text_iter_make_surreal (iter);
3587 check_invariants (iter);
3589 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3591 iter_set_from_char_offset (real, line, 0);
3593 /* We might as well cache this, since we know it. */
3594 real->cached_line_number = real_line;
3596 check_invariants (iter);
3600 * gtk_text_iter_set_offset:
3601 * @iter: a #GtkTextIter
3602 * @char_offset: a character number
3604 * Sets @iter to point to @char_offset. @char_offset counts from the start
3605 * of the entire text buffer, starting with 0.
3609 gtk_text_iter_set_offset (GtkTextIter *iter,
3613 GtkTextRealIter *real;
3615 gint real_char_index;
3617 g_return_if_fail (iter != NULL);
3619 real = gtk_text_iter_make_surreal (iter);
3624 check_invariants (iter);
3626 if (real->cached_char_index >= 0 &&
3627 real->cached_char_index == char_offset)
3630 line = _gtk_text_btree_get_line_at_char (real->tree,
3635 iter_set_from_char_offset (real, line, real_char_index - line_start);
3637 /* Go ahead and cache this since we have it. */
3638 real->cached_char_index = real_char_index;
3640 check_invariants (iter);
3644 * gtk_text_iter_forward_to_end:
3645 * @iter: a #GtkTextIter
3647 * Moves @iter forward to the "end iterator," which points one past the last
3648 * valid character in the buffer. gtk_text_iter_get_char() called on the
3649 * end iterator returns 0, which is convenient for writing loops.
3653 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3655 GtkTextBuffer *buffer;
3656 GtkTextRealIter *real;
3658 g_return_if_fail (iter != NULL);
3660 real = gtk_text_iter_make_surreal (iter);
3665 buffer = _gtk_text_btree_get_buffer (real->tree);
3667 gtk_text_buffer_get_end_iter (buffer, iter);
3671 * gtk_text_iter_forward_to_line_end:
3672 * @iter: a #GtkTextIter
3674 * Moves the iterator to point to the paragraph delimiter characters,
3675 * which will be either a newline, a carriage return, a carriage
3676 * return/newline in sequence, or the Unicode paragraph separator
3677 * character. If the iterator is already at the paragraph delimiter
3678 * characters, moves to the paragraph delimiter characters for the
3681 * Return value: %TRUE if we moved and the new location is not the end iterator
3684 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3686 gint current_offset;
3689 g_return_val_if_fail (iter != NULL, FALSE);
3691 current_offset = gtk_text_iter_get_line_offset (iter);
3692 /* FIXME assumption that line ends in a newline; broken */
3693 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3695 if (current_offset < new_offset)
3697 /* Move to end of this line. */
3698 gtk_text_iter_set_line_offset (iter, new_offset);
3703 /* Move to end of next line. */
3704 if (gtk_text_iter_forward_line (iter))
3706 /* We don't want to move past all
3709 if (!gtk_text_iter_ends_line (iter))
3710 gtk_text_iter_forward_to_line_end (iter);
3719 * gtk_text_iter_forward_to_tag_toggle:
3720 * @iter: a #GtkTextIter
3721 * @tag: a #GtkTextTag, or NULL
3723 * Moves forward to the next toggle (on or off) of the
3724 * #GtkTextTag @tag, or to the next toggle of any tag if
3725 * @tag is NULL. If no matching tag toggles are found,
3726 * returns FALSE, otherwise TRUE. Does not return toggles
3727 * located at @iter, only toggles after @iter. Sets @iter to
3728 * the location of the toggle, or to the end of the buffer
3729 * if no toggle is found.
3731 * Return value: whether we found a tag toggle after @iter
3734 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3737 GtkTextLine *next_line;
3738 GtkTextLine *current_line;
3739 GtkTextRealIter *real;
3741 g_return_val_if_fail (iter != NULL, FALSE);
3743 real = gtk_text_iter_make_real (iter);
3748 check_invariants (iter);
3750 current_line = real->line;
3751 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3754 while (_gtk_text_iter_forward_indexable_segment (iter))
3756 /* If we went forward to a line that couldn't contain a toggle
3757 for the tag, then skip forward to a line that could contain
3758 it. This potentially skips huge hunks of the tree, so we
3759 aren't a purely linear search. */
3760 if (real->line != current_line)
3762 if (next_line == NULL)
3764 /* End of search. Set to end of buffer. */
3765 _gtk_text_btree_get_end_iter (real->tree, iter);
3769 if (real->line != next_line)
3770 iter_set_from_byte_offset (real, next_line, 0);
3772 current_line = real->line;
3773 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3778 if (gtk_text_iter_toggles_tag (iter, tag))
3780 /* If there's a toggle here, it isn't indexable so
3781 any_segment can't be the indexable segment. */
3782 g_assert (real->any_segment != real->segment);
3787 /* Check end iterator for tags */
3788 if (gtk_text_iter_toggles_tag (iter, tag))
3790 /* If there's a toggle here, it isn't indexable so
3791 any_segment can't be the indexable segment. */
3792 g_assert (real->any_segment != real->segment);
3796 /* Reached end of buffer */
3801 * gtk_text_iter_backward_to_tag_toggle:
3802 * @iter: a #GtkTextIter
3803 * @tag: a #GtkTextTag, or NULL
3805 * Moves backward to the next toggle (on or off) of the
3806 * #GtkTextTag @tag, or to the next toggle of any tag if
3807 * @tag is NULL. If no matching tag toggles are found,
3808 * returns FALSE, otherwise TRUE. Does not return toggles
3809 * located at @iter, only toggles before @iter. Sets @iter
3810 * to the location of the toggle, or the start of the buffer
3811 * if no toggle is found.
3813 * Return value: whether we found a tag toggle before @iter
3816 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3819 GtkTextLine *prev_line;
3820 GtkTextLine *current_line;
3821 GtkTextRealIter *real;
3823 g_return_val_if_fail (iter != NULL, FALSE);
3825 real = gtk_text_iter_make_real (iter);
3830 check_invariants (iter);
3832 current_line = real->line;
3833 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3837 /* If we're at segment start, go to the previous segment;
3838 * if mid-segment, snap to start of current segment.
3840 if (is_segment_start (real))
3842 if (!_gtk_text_iter_backward_indexable_segment (iter))
3847 ensure_char_offsets (real);
3849 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3855 /* If we went backward to a line that couldn't contain a toggle
3856 * for the tag, then skip backward further to a line that
3857 * could contain it. This potentially skips huge hunks of the
3858 * tree, so we aren't a purely linear search.
3860 if (real->line != current_line)
3862 if (prev_line == NULL)
3864 /* End of search. Set to start of buffer. */
3865 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3869 if (real->line != prev_line)
3871 /* Set to last segment in prev_line (could do this
3874 iter_set_from_byte_offset (real, prev_line, 0);
3876 while (!at_last_indexable_segment (real))
3877 _gtk_text_iter_forward_indexable_segment (iter);
3880 current_line = real->line;
3881 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3886 if (gtk_text_iter_toggles_tag (iter, tag))
3888 /* If there's a toggle here, it isn't indexable so
3889 * any_segment can't be the indexable segment.
3891 g_assert (real->any_segment != real->segment);
3895 while (_gtk_text_iter_backward_indexable_segment (iter));
3897 /* Reached front of buffer */
3902 matches_pred (GtkTextIter *iter,
3903 GtkTextCharPredicate pred,
3908 ch = gtk_text_iter_get_char (iter);
3910 return (*pred) (ch, user_data);
3914 * gtk_text_iter_forward_find_char:
3915 * @iter: a #GtkTextIter
3916 * @pred: a function to be called on each character
3917 * @user_data: user data for @pred
3918 * @limit: search limit, or %NULL for none
3920 * Advances @iter, calling @pred on each character. If
3921 * @pred returns %TRUE, returns %TRUE and stops scanning.
3922 * If @pred never returns %TRUE, @iter is set to @limit if
3923 * @limit is non-%NULL, otherwise to the end iterator.
3925 * Return value: whether a match was found
3928 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3929 GtkTextCharPredicate pred,
3931 const GtkTextIter *limit)
3933 g_return_val_if_fail (iter != NULL, FALSE);
3934 g_return_val_if_fail (pred != NULL, FALSE);
3937 gtk_text_iter_compare (iter, limit) >= 0)
3940 while ((limit == NULL ||
3941 !gtk_text_iter_equal (limit, iter)) &&
3942 gtk_text_iter_forward_char (iter))
3944 if (matches_pred (iter, pred, user_data))
3952 * gtk_text_iter_backward_find_char:
3953 * @iter: a #GtkTextIter
3954 * @pred: function to be called on each character
3955 * @user_data: user data for @pred
3956 * @limit: search limit, or %NULL for none
3958 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
3960 * Return value: whether a match was found
3963 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3964 GtkTextCharPredicate pred,
3966 const GtkTextIter *limit)
3968 g_return_val_if_fail (iter != NULL, FALSE);
3969 g_return_val_if_fail (pred != NULL, FALSE);
3972 gtk_text_iter_compare (iter, limit) <= 0)
3975 while ((limit == NULL ||
3976 !gtk_text_iter_equal (limit, iter)) &&
3977 gtk_text_iter_backward_char (iter))
3979 if (matches_pred (iter, pred, user_data))
3987 forward_chars_with_skipping (GtkTextIter *iter,
3989 gboolean skip_invisible,
3990 gboolean skip_nontext)
3995 g_return_if_fail (count >= 0);
4001 gboolean ignored = FALSE;
4004 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4009 _gtk_text_btree_char_is_invisible (iter))
4012 gtk_text_iter_forward_char (iter);
4020 lines_match (const GtkTextIter *start,
4021 const gchar **lines,
4022 gboolean visible_only,
4024 GtkTextIter *match_start,
4025 GtkTextIter *match_end)
4032 if (*lines == NULL || **lines == '\0')
4035 *match_start = *start;
4038 *match_end = *start;
4043 gtk_text_iter_forward_line (&next);
4045 /* No more text in buffer, but *lines is nonempty */
4046 if (gtk_text_iter_equal (start, &next))
4054 line_text = gtk_text_iter_get_visible_slice (start, &next);
4056 line_text = gtk_text_iter_get_slice (start, &next);
4061 line_text = gtk_text_iter_get_visible_text (start, &next);
4063 line_text = gtk_text_iter_get_text (start, &next);
4066 if (match_start) /* if this is the first line we're matching */
4067 found = strstr (line_text, *lines);
4070 /* If it's not the first line, we have to match from the
4071 * start of the line.
4073 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4085 /* Get offset to start of search string */
4086 offset = g_utf8_strlen (line_text, found - line_text);
4090 /* If match start needs to be returned, set it to the
4091 * start of the search string.
4095 *match_start = next;
4097 forward_chars_with_skipping (match_start, offset,
4098 visible_only, !slice);
4101 /* Go to end of search string */
4102 offset += g_utf8_strlen (*lines, -1);
4104 forward_chars_with_skipping (&next, offset,
4105 visible_only, !slice);
4114 /* pass NULL for match_start, since we don't need to find the
4117 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4120 /* strsplit () that retains the delimiter as part of the string. */
4122 strbreakup (const char *string,
4123 const char *delimiter,
4126 GSList *string_list = NULL, *slist;
4127 gchar **str_array, *s;
4130 g_return_val_if_fail (string != NULL, NULL);
4131 g_return_val_if_fail (delimiter != NULL, NULL);
4134 max_tokens = G_MAXINT;
4136 s = strstr (string, delimiter);
4139 guint delimiter_len = strlen (delimiter);
4146 len = s - string + delimiter_len;
4147 new_string = g_new (gchar, len + 1);
4148 strncpy (new_string, string, len);
4149 new_string[len] = 0;
4150 string_list = g_slist_prepend (string_list, new_string);
4152 string = s + delimiter_len;
4153 s = strstr (string, delimiter);
4155 while (--max_tokens && s);
4160 string_list = g_slist_prepend (string_list, g_strdup (string));
4163 str_array = g_new (gchar*, n);
4167 str_array[i--] = NULL;
4168 for (slist = string_list; slist; slist = slist->next)
4169 str_array[i--] = slist->data;
4171 g_slist_free (string_list);
4177 * gtk_text_iter_forward_search:
4178 * @iter: start of search
4179 * @str: a search string
4180 * @visible_only: if %TRUE, search only visible text
4181 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4182 * @match_start: return location for start of match, or %NULL
4183 * @match_end: return location for end of match, or %NULL
4184 * @limit: bound for the search, or %NULL for the end of the buffer
4186 * Searches forward for @str. Any match is returned as the range @match_start,
4187 * @match_end. If you specify @visible_only or @slice, the match may have
4188 * invisible text, pixbufs, or child widgets interspersed in @str.
4190 * Return value: whether a match was found
4193 gtk_text_iter_forward_search (const GtkTextIter *iter,
4195 gboolean visible_only,
4197 GtkTextIter *match_start,
4198 GtkTextIter *match_end,
4199 const GtkTextIter *limit)
4201 gchar **lines = NULL;
4203 gboolean retval = FALSE;
4206 g_return_val_if_fail (iter != NULL, FALSE);
4207 g_return_val_if_fail (str != NULL, FALSE);
4210 gtk_text_iter_compare (iter, limit) >= 0)
4215 /* If we can move one char, return the empty string there */
4218 if (gtk_text_iter_forward_char (&match))
4221 gtk_text_iter_equal (&match, limit))
4225 *match_start = match;
4234 /* locate all lines */
4236 lines = strbreakup (str, "\n", -1);
4242 /* This loop has an inefficient worst-case, where
4243 * gtk_text_iter_get_text () is called repeatedly on
4249 gtk_text_iter_compare (&search, limit) >= 0)
4252 if (lines_match (&search, (const gchar**)lines,
4253 visible_only, slice, &match, &end))
4255 if (limit == NULL ||
4257 gtk_text_iter_compare (&end, limit) < 0))
4262 *match_start = match;
4271 while (gtk_text_iter_forward_line (&search));
4273 g_strfreev ((gchar**)lines);
4279 vectors_equal_ignoring_trailing (gchar **vec1,
4282 /* Ignores trailing chars in vec2's last line */
4291 if (strcmp (*i1, *i2) != 0)
4293 if (*(i2 + 1) == NULL) /* if this is the last line */
4295 gint len1 = strlen (*i1);
4296 gint len2 = strlen (*i2);
4299 strncmp (*i1, *i2, len1) == 0)
4301 /* We matched ignoring the trailing stuff in vec2 */
4326 typedef struct _LinesWindow LinesWindow;
4332 GtkTextIter first_line_start;
4333 GtkTextIter first_line_end;
4335 gboolean visible_only;
4339 lines_window_init (LinesWindow *win,
4340 const GtkTextIter *start)
4343 GtkTextIter line_start;
4344 GtkTextIter line_end;
4346 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4349 if (gtk_text_iter_is_start (start) ||
4350 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4352 /* Already at the end, or not enough lines to match */
4353 win->lines = g_new0 (gchar*, 1);
4358 line_start = *start;
4361 /* Move to start iter to start of line */
4362 gtk_text_iter_set_line_offset (&line_start, 0);
4364 if (gtk_text_iter_equal (&line_start, &line_end))
4366 /* we were already at the start; so go back one line */
4367 gtk_text_iter_backward_line (&line_start);
4370 win->first_line_start = line_start;
4371 win->first_line_end = line_end;
4373 win->lines = g_new0 (gchar*, win->n_lines + 1);
4375 i = win->n_lines - 1;
4382 if (win->visible_only)
4383 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4385 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4389 if (win->visible_only)
4390 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4392 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4395 win->lines[i] = line_text;
4397 line_end = line_start;
4398 gtk_text_iter_backward_line (&line_start);
4405 lines_window_back (LinesWindow *win)
4407 GtkTextIter new_start;
4410 new_start = win->first_line_start;
4412 if (!gtk_text_iter_backward_line (&new_start))
4416 win->first_line_start = new_start;
4417 win->first_line_end = new_start;
4419 gtk_text_iter_forward_line (&win->first_line_end);
4424 if (win->visible_only)
4425 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4426 &win->first_line_end);
4428 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4429 &win->first_line_end);
4433 if (win->visible_only)
4434 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4435 &win->first_line_end);
4437 line_text = gtk_text_iter_get_text (&win->first_line_start,
4438 &win->first_line_end);
4441 /* Move lines to make room for first line. */
4442 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4444 *win->lines = line_text;
4446 /* Free old last line and NULL-terminate */
4447 g_free (win->lines[win->n_lines]);
4448 win->lines[win->n_lines] = NULL;
4454 lines_window_free (LinesWindow *win)
4456 g_strfreev (win->lines);
4460 my_strrstr (const gchar *haystack,
4461 const gchar *needle)
4463 /* FIXME GLib should have a nice implementation in it, this
4467 gint haystack_len = strlen (haystack);
4468 gint needle_len = strlen (needle);
4469 const gchar *needle_end = needle + needle_len;
4470 const gchar *haystack_rend = haystack - 1;
4471 const gchar *needle_rend = needle - 1;
4474 p = haystack + haystack_len;
4475 while (p != haystack)
4477 const gchar *n = needle_end - 1;
4478 const gchar *s = p - 1;
4479 while (s != haystack_rend &&
4487 if (n == needle_rend)
4497 * gtk_text_iter_backward_search:
4498 * @iter: a #GtkTextIter where the search begins
4499 * @str: search string
4500 * @visible_only: if %TRUE search only visible text
4501 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4502 * @match_start: return location for start of match, or %NULL
4503 * @match_end: return location for end of match, or %NULL
4504 * @limit: location of last possible @match_start, or %NULL for start of buffer
4506 * Same as gtk_text_iter_forward_search(), but moves backward.
4508 * Return value: whether a match was found
4511 gtk_text_iter_backward_search (const GtkTextIter *iter,
4513 gboolean visible_only,
4515 GtkTextIter *match_start,
4516 GtkTextIter *match_end,
4517 const GtkTextIter *limit)
4519 gchar **lines = NULL;
4523 gboolean retval = FALSE;
4525 g_return_val_if_fail (iter != NULL, FALSE);
4526 g_return_val_if_fail (str != NULL, FALSE);
4529 gtk_text_iter_compare (limit, iter) > 0)
4534 /* If we can move one char, return the empty string there */
4535 GtkTextIter match = *iter;
4537 if (limit && gtk_text_iter_equal (limit, &match))
4540 if (gtk_text_iter_backward_char (&match))
4543 *match_start = match;
4552 /* locate all lines */
4554 lines = strbreakup (str, "\n", -1);
4564 win.n_lines = n_lines;
4566 win.visible_only = visible_only;
4568 lines_window_init (&win, iter);
4570 if (*win.lines == NULL)
4575 gchar *first_line_match;
4578 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4580 /* We're now before the search limit, abort. */
4584 /* If there are multiple lines, the first line will
4585 * end in '\n', so this will only match at the
4586 * end of the first line, which is correct.
4588 first_line_match = my_strrstr (*win.lines, *lines);
4590 if (first_line_match &&
4591 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4596 GtkTextIter start_tmp;
4598 /* Offset to start of search string */
4599 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4601 next = win.first_line_start;
4603 forward_chars_with_skipping (&start_tmp, offset,
4604 visible_only, !slice);
4607 gtk_text_iter_compare (limit, &start_tmp) > 0)
4608 goto out; /* match was bogus */
4611 *match_start = start_tmp;
4613 /* Go to end of search string */
4617 offset += g_utf8_strlen (*l, -1);
4621 forward_chars_with_skipping (&next, offset,
4622 visible_only, !slice);
4631 while (lines_window_back (&win));
4634 lines_window_free (&win);
4645 * gtk_text_iter_equal:
4646 * @lhs: a #GtkTextIter
4647 * @rhs: another #GtkTextIter
4649 * Tests whether two iterators are equal, using the fastest possible
4650 * mechanism. This function is very fast; you can expect it to perform
4651 * better than e.g. getting the character offset for each iterator and
4652 * comparing the offsets yourself. Also, it's a bit faster than
4653 * gtk_text_iter_compare().
4655 * Return value: %TRUE if the iterators point to the same place in the buffer
4658 gtk_text_iter_equal (const GtkTextIter *lhs,
4659 const GtkTextIter *rhs)
4661 GtkTextRealIter *real_lhs;
4662 GtkTextRealIter *real_rhs;
4664 real_lhs = (GtkTextRealIter*)lhs;
4665 real_rhs = (GtkTextRealIter*)rhs;
4667 check_invariants (lhs);
4668 check_invariants (rhs);
4670 if (real_lhs->line != real_rhs->line)
4672 else if (real_lhs->line_byte_offset >= 0 &&
4673 real_rhs->line_byte_offset >= 0)
4674 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4677 /* the ensure_char_offsets () calls do nothing if the char offsets
4678 are already up-to-date. */
4679 ensure_char_offsets (real_lhs);
4680 ensure_char_offsets (real_rhs);
4681 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4686 * gtk_text_iter_compare:
4687 * @lhs: a #GtkTextIter
4688 * @rhs: another #GtkTextIter
4690 * A qsort()-style function that returns negative if @lhs is less than
4691 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4692 * Ordering is in character offset order, i.e. the first character in the buffer
4693 * is less than the second character in the buffer.
4695 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4698 gtk_text_iter_compare (const GtkTextIter *lhs,
4699 const GtkTextIter *rhs)
4701 GtkTextRealIter *real_lhs;
4702 GtkTextRealIter *real_rhs;
4704 real_lhs = gtk_text_iter_make_surreal (lhs);
4705 real_rhs = gtk_text_iter_make_surreal (rhs);
4707 if (real_lhs == NULL ||
4709 return -1; /* why not */
4711 check_invariants (lhs);
4712 check_invariants (rhs);
4714 if (real_lhs->line == real_rhs->line)
4716 gint left_index, right_index;
4718 if (real_lhs->line_byte_offset >= 0 &&
4719 real_rhs->line_byte_offset >= 0)
4721 left_index = real_lhs->line_byte_offset;
4722 right_index = real_rhs->line_byte_offset;
4726 /* the ensure_char_offsets () calls do nothing if
4727 the offsets are already up-to-date. */
4728 ensure_char_offsets (real_lhs);
4729 ensure_char_offsets (real_rhs);
4730 left_index = real_lhs->line_char_offset;
4731 right_index = real_rhs->line_char_offset;
4734 if (left_index < right_index)
4736 else if (left_index > right_index)
4745 line1 = gtk_text_iter_get_line (lhs);
4746 line2 = gtk_text_iter_get_line (rhs);
4749 else if (line1 > line2)
4757 * gtk_text_iter_in_range:
4758 * @iter: a #GtkTextIter
4759 * @start: start of range
4760 * @end: end of range
4762 * Checks whether @iter falls in the range [@start, @end).
4763 * @start and @end must be in ascending order.
4765 * Return value: %TRUE if @iter is in the range
4768 gtk_text_iter_in_range (const GtkTextIter *iter,
4769 const GtkTextIter *start,
4770 const GtkTextIter *end)
4772 g_return_val_if_fail (iter != NULL, FALSE);
4773 g_return_val_if_fail (start != NULL, FALSE);
4774 g_return_val_if_fail (end != NULL, FALSE);
4775 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4777 return gtk_text_iter_compare (iter, start) >= 0 &&
4778 gtk_text_iter_compare (iter, end) < 0;
4782 * gtk_text_iter_order:
4783 * @first: a #GtkTextIter
4784 * @second: another #GtkTextIter
4786 * Swaps the value of @first and @second if @second comes before
4787 * @first in the buffer. That is, ensures that @first and @second are
4788 * in sequence. Most text buffer functions that take a range call this
4789 * automatically on your behalf, so there's no real reason to call it yourself
4790 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4791 * that expect a pre-sorted range.
4795 gtk_text_iter_order (GtkTextIter *first,
4796 GtkTextIter *second)
4798 g_return_if_fail (first != NULL);
4799 g_return_if_fail (second != NULL);
4801 if (gtk_text_iter_compare (first, second) > 0)
4812 * Init iterators from the BTree
4816 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4820 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4821 gint real_char_index;
4825 g_return_if_fail (iter != NULL);
4826 g_return_if_fail (tree != NULL);
4828 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4829 &line_start, &real_char_index);
4831 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4833 real->cached_char_index = real_char_index;
4835 check_invariants (iter);
4839 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4844 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4848 g_return_if_fail (iter != NULL);
4849 g_return_if_fail (tree != NULL);
4851 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4853 iter_init_from_char_offset (iter, tree, line, char_on_line);
4855 /* We might as well cache this, since we know it. */
4856 real->cached_line_number = real_line;
4858 check_invariants (iter);
4862 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4867 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4871 g_return_if_fail (iter != NULL);
4872 g_return_if_fail (tree != NULL);
4874 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4876 iter_init_from_byte_offset (iter, tree, line, byte_index);
4878 /* We might as well cache this, since we know it. */
4879 real->cached_line_number = real_line;
4881 check_invariants (iter);
4885 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4890 g_return_if_fail (iter != NULL);
4891 g_return_if_fail (tree != NULL);
4892 g_return_if_fail (line != NULL);
4894 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4896 check_invariants (iter);
4900 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4906 g_return_val_if_fail (iter != NULL, FALSE);
4907 g_return_val_if_fail (tree != NULL, FALSE);
4909 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4913 /* Set iter to last in tree */
4914 _gtk_text_btree_get_end_iter (tree, iter);
4915 check_invariants (iter);
4920 iter_init_from_byte_offset (iter, tree, line, 0);
4921 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4922 check_invariants (iter);
4928 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4932 g_return_val_if_fail (iter != NULL, FALSE);
4933 g_return_val_if_fail (tree != NULL, FALSE);
4935 _gtk_text_btree_get_end_iter (tree, iter);
4936 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4937 check_invariants (iter);
4943 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4945 const gchar *mark_name)
4949 g_return_val_if_fail (iter != NULL, FALSE);
4950 g_return_val_if_fail (tree != NULL, FALSE);
4952 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4958 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4959 check_invariants (iter);
4965 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4969 GtkTextLineSegment *seg;
4971 g_return_if_fail (iter != NULL);
4972 g_return_if_fail (tree != NULL);
4973 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4975 seg = mark->segment;
4977 iter_init_from_segment (iter, tree,
4978 seg->body.mark.line, seg);
4979 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4980 check_invariants (iter);
4984 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4986 GtkTextChildAnchor *anchor)
4988 GtkTextLineSegment *seg;
4990 g_return_if_fail (iter != NULL);
4991 g_return_if_fail (tree != NULL);
4992 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4994 seg = anchor->segment;
4996 iter_init_from_segment (iter, tree,
4997 seg->body.child.line, seg);
4998 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4999 check_invariants (iter);
5003 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5006 g_return_if_fail (iter != NULL);
5007 g_return_if_fail (tree != NULL);
5009 _gtk_text_btree_get_iter_at_char (tree,
5011 _gtk_text_btree_char_count (tree));
5012 check_invariants (iter);
5016 _gtk_text_iter_check (const GtkTextIter *iter)
5018 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5019 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5020 GtkTextLineSegment *byte_segment = NULL;
5021 GtkTextLineSegment *byte_any_segment = NULL;
5022 GtkTextLineSegment *char_segment = NULL;
5023 GtkTextLineSegment *char_any_segment = NULL;
5024 gboolean segments_updated;
5026 /* This function checks our class invariants for the Iter class. */
5028 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5030 if (real->chars_changed_stamp !=
5031 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5032 g_error ("iterator check failed: invalid iterator");
5034 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5035 g_error ("iterator check failed: both char and byte offsets are invalid");
5037 segments_updated = (real->segments_changed_stamp ==
5038 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5041 printf ("checking iter, segments %s updated, byte %d char %d\n",
5042 segments_updated ? "are" : "aren't",
5043 real->line_byte_offset,
5044 real->line_char_offset);
5047 if (segments_updated)
5049 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5050 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5052 if (real->segment->char_count == 0)
5053 g_error ("iterator check failed: segment is not indexable.");
5055 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5056 g_error ("segment char offset is not properly up-to-date");
5058 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5059 g_error ("segment byte offset is not properly up-to-date");
5061 if (real->segment_byte_offset >= 0 &&
5062 real->segment_byte_offset >= real->segment->byte_count)
5063 g_error ("segment byte offset is too large.");
5065 if (real->segment_char_offset >= 0 &&
5066 real->segment_char_offset >= real->segment->char_count)
5067 g_error ("segment char offset is too large.");
5070 if (real->line_byte_offset >= 0)
5072 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5073 &byte_segment, &byte_any_segment,
5074 &seg_byte_offset, &line_byte_offset);
5076 if (line_byte_offset != real->line_byte_offset)
5077 g_error ("wrong byte offset was stored in iterator");
5079 if (segments_updated)
5081 if (real->segment != byte_segment)
5082 g_error ("wrong segment was stored in iterator");
5084 if (real->any_segment != byte_any_segment)
5085 g_error ("wrong any_segment was stored in iterator");
5087 if (seg_byte_offset != real->segment_byte_offset)
5088 g_error ("wrong segment byte offset was stored in iterator");
5090 if (byte_segment->type == >k_text_char_type)
5093 p = byte_segment->body.chars + seg_byte_offset;
5095 if (!gtk_text_byte_begins_utf8_char (p))
5096 g_error ("broken iterator byte index pointed into the middle of a character");
5101 if (real->line_char_offset >= 0)
5103 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5104 &char_segment, &char_any_segment,
5105 &seg_char_offset, &line_char_offset);
5107 if (line_char_offset != real->line_char_offset)
5108 g_error ("wrong char offset was stored in iterator");
5110 if (segments_updated)
5112 if (real->segment != char_segment)
5113 g_error ("wrong segment was stored in iterator");
5115 if (real->any_segment != char_any_segment)
5116 g_error ("wrong any_segment was stored in iterator");
5118 if (seg_char_offset != real->segment_char_offset)
5119 g_error ("wrong segment char offset was stored in iterator");
5121 if (char_segment->type == >k_text_char_type)
5124 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5127 /* hmm, not likely to happen eh */
5128 if (!gtk_text_byte_begins_utf8_char (p))
5129 g_error ("broken iterator char offset pointed into the middle of a character");
5134 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5136 if (byte_segment != char_segment)
5137 g_error ("char and byte offsets did not point to the same segment");
5139 if (byte_any_segment != char_any_segment)
5140 g_error ("char and byte offsets did not point to the same any segment");
5142 /* Make sure the segment offsets are equivalent, if it's a char
5144 if (char_segment->type == >k_text_char_type)
5146 gint byte_offset = 0;
5147 gint char_offset = 0;
5148 while (char_offset < seg_char_offset)
5150 const char * start = char_segment->body.chars + byte_offset;
5151 byte_offset += g_utf8_next_char (start) - start;
5155 if (byte_offset != seg_byte_offset)
5156 g_error ("byte offset did not correspond to char offset");
5159 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5161 if (char_offset != seg_char_offset)
5162 g_error ("char offset did not correspond to byte offset");
5164 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5165 g_error ("byte index for iterator does not index the start of a character");
5169 if (real->cached_line_number >= 0)
5173 should_be = _gtk_text_line_get_number (real->line);
5174 if (real->cached_line_number != should_be)
5175 g_error ("wrong line number was cached");
5178 if (real->cached_char_index >= 0)
5180 if (real->line_char_offset >= 0) /* only way we can check it
5181 efficiently, not a real
5186 char_index = _gtk_text_line_char_index (real->line);
5187 char_index += real->line_char_offset;
5189 if (real->cached_char_index != char_index)
5190 g_error ("wrong char index was cached");
5194 if (_gtk_text_line_is_last (real->line, real->tree))
5195 g_error ("Iterator was on last line (past the end iterator)");