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 return _gtk_text_line_is_last (real->line, real->tree);
1539 * gtk_text_iter_is_start:
1540 * @iter: an iterator
1542 * Returns TRUE if @iter is the first iterator in the buffer, that is
1543 * if @iter has a character offset of 0.
1545 * Return value: whether @iter is the first in the buffer
1548 gtk_text_iter_is_start (const GtkTextIter *iter)
1550 return gtk_text_iter_get_offset (iter) == 0;
1554 * gtk_text_iter_get_chars_in_line:
1555 * @iter: an iterator
1557 * Returns the number of characters in the line containing @iter,
1558 * including the paragraph delimiters.
1560 * Return value: number of characters in the line
1563 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1565 GtkTextRealIter *real;
1567 GtkTextLineSegment *seg;
1569 g_return_val_if_fail (iter != NULL, FALSE);
1571 real = gtk_text_iter_make_surreal (iter);
1576 check_invariants (iter);
1578 if (real->line_char_offset >= 0)
1580 /* We can start at the segments we've already found. */
1581 count = real->line_char_offset - real->segment_char_offset;
1582 seg = _gtk_text_iter_get_indexable_segment (iter);
1586 /* count whole line. */
1587 seg = real->line->segments;
1594 count += seg->char_count;
1603 * gtk_text_iter_get_bytes_in_line:
1604 * @iter: an iterator
1606 * Returns the number of bytes in the line containing @iter,
1607 * including the paragraph delimiters.
1609 * Return value: number of bytes in the line
1612 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1614 GtkTextRealIter *real;
1616 GtkTextLineSegment *seg;
1618 g_return_val_if_fail (iter != NULL, FALSE);
1620 real = gtk_text_iter_make_surreal (iter);
1625 check_invariants (iter);
1627 if (real->line_byte_offset >= 0)
1629 /* We can start at the segments we've already found. */
1630 count = real->line_byte_offset - real->segment_byte_offset;
1631 seg = _gtk_text_iter_get_indexable_segment (iter);
1635 /* count whole line. */
1636 seg = real->line->segments;
1642 count += seg->byte_count;
1651 * gtk_text_iter_get_attributes:
1652 * @iter: an iterator
1653 * @values: a #GtkTextAttributes to be filled in
1655 * Computes the effect of any tags applied to this spot in the
1656 * text. The @values parameter should be initialized to the default
1657 * settings you wish to use if no tags are in effect. You'd typically
1658 * obtain the defaults from gtk_text_view_get_default_attributes().
1660 * gtk_text_iter_get_attributes () will modify @values, applying the
1661 * effects of any tags present at @iter. If any tags affected @values,
1662 * the function returns %TRUE.
1664 * Return value: %TRUE if @values was modified
1667 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1668 GtkTextAttributes *values)
1673 /* Get the tags at this spot */
1674 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1676 /* No tags, use default style */
1677 if (tags == NULL || tag_count == 0)
1685 /* Sort tags in ascending order of priority */
1686 _gtk_text_tag_array_sort (tags, tag_count);
1688 _gtk_text_attributes_fill_from_tags (values,
1698 * Increments/decrements
1701 /* The return value of this indicates WHETHER WE MOVED.
1702 * The return value of public functions indicates
1703 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1706 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1708 GtkTextLine *new_line;
1710 new_line = _gtk_text_line_next (real->line);
1712 g_assert (new_line != real->line);
1714 if (new_line != NULL)
1716 real->line = new_line;
1718 real->line_byte_offset = 0;
1719 real->line_char_offset = 0;
1721 real->segment_byte_offset = 0;
1722 real->segment_char_offset = 0;
1724 /* Find first segments in new line */
1725 real->any_segment = real->line->segments;
1726 real->segment = real->any_segment;
1727 while (real->segment->char_count == 0)
1728 real->segment = real->segment->next;
1734 /* There is no way to move forward; we were already
1735 at the "end" index. (the end index is the last
1736 line pointer, segment_byte_offset of 0) */
1738 g_assert (real->line_char_offset == 0 ||
1739 real->line_byte_offset == 0);
1741 /* The only indexable segment allowed on the bogus
1742 line at the end is a single char segment containing
1744 if (real->segments_changed_stamp ==
1745 _gtk_text_btree_get_segments_changed_stamp (real->tree))
1747 g_assert (real->segment->type == >k_text_char_type);
1748 g_assert (real->segment->char_count == 1);
1750 /* We leave real->line as-is */
1757 /* The return value of this indicates WHETHER WE MOVED.
1758 * The return value of public functions indicates
1759 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1762 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1764 GtkTextLine *new_line;
1766 new_line = _gtk_text_line_previous (real->line);
1768 g_assert (new_line != real->line);
1770 if (new_line != NULL)
1772 real->line = new_line;
1774 real->line_byte_offset = 0;
1775 real->line_char_offset = 0;
1777 real->segment_byte_offset = 0;
1778 real->segment_char_offset = 0;
1780 /* Find first segments in new line */
1781 real->any_segment = real->line->segments;
1782 real->segment = real->any_segment;
1783 while (real->segment->char_count == 0)
1784 real->segment = real->segment->next;
1790 /* There is no way to move backward; we were already
1791 at the first line. */
1793 /* We leave real->line as-is */
1795 /* Note that we didn't clamp to the start of the first line. */
1801 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1805 forward_char (GtkTextRealIter *real)
1807 GtkTextIter *iter = (GtkTextIter*)real;
1809 check_invariants ((GtkTextIter*)real);
1811 ensure_char_offsets (real);
1813 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1815 /* Need to move to the next segment; if no next segment,
1816 need to move to next line. */
1817 return _gtk_text_iter_forward_indexable_segment (iter);
1821 /* Just moving within a segment. Keep byte count
1822 up-to-date, if it was already up-to-date. */
1824 g_assert (real->segment->type == >k_text_char_type);
1826 if (real->line_byte_offset >= 0)
1829 const char * start =
1830 real->segment->body.chars + real->segment_byte_offset;
1832 bytes = g_utf8_next_char (start) - start;
1834 real->line_byte_offset += bytes;
1835 real->segment_byte_offset += bytes;
1837 g_assert (real->segment_byte_offset < real->segment->byte_count);
1840 real->line_char_offset += 1;
1841 real->segment_char_offset += 1;
1843 adjust_char_index (real, 1);
1845 g_assert (real->segment_char_offset < real->segment->char_count);
1847 /* We moved into the middle of a segment, so the any_segment
1848 must now be the segment we're in the middle of. */
1849 real->any_segment = real->segment;
1851 check_invariants ((GtkTextIter*)real);
1853 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1861 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1863 /* Need to move to the next segment; if no next segment,
1864 need to move to next line. */
1865 GtkTextLineSegment *seg;
1866 GtkTextLineSegment *any_seg;
1867 GtkTextRealIter *real;
1871 g_return_val_if_fail (iter != NULL, FALSE);
1873 real = gtk_text_iter_make_real (iter);
1878 check_invariants (iter);
1880 if (real->line_char_offset >= 0)
1882 chars_skipped = real->segment->char_count - real->segment_char_offset;
1883 g_assert (chars_skipped > 0);
1888 if (real->line_byte_offset >= 0)
1890 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1891 g_assert (bytes_skipped > 0);
1896 /* Get first segment of any kind */
1897 any_seg = real->segment->next;
1898 /* skip non-indexable segments, if any */
1900 while (seg != NULL && seg->char_count == 0)
1905 real->any_segment = any_seg;
1906 real->segment = seg;
1908 if (real->line_byte_offset >= 0)
1910 g_assert (bytes_skipped > 0);
1911 real->segment_byte_offset = 0;
1912 real->line_byte_offset += bytes_skipped;
1915 if (real->line_char_offset >= 0)
1917 g_assert (chars_skipped > 0);
1918 real->segment_char_offset = 0;
1919 real->line_char_offset += chars_skipped;
1920 adjust_char_index (real, chars_skipped);
1923 check_invariants (iter);
1929 /* End of the line */
1930 if (forward_line_leaving_caches_unmodified (real))
1932 adjust_line_number (real, 1);
1933 if (real->line_char_offset >= 0)
1934 adjust_char_index (real, chars_skipped);
1936 g_assert (real->line_byte_offset == 0);
1937 g_assert (real->line_char_offset == 0);
1938 g_assert (real->segment_byte_offset == 0);
1939 g_assert (real->segment_char_offset == 0);
1940 g_assert (gtk_text_iter_starts_line (iter));
1942 check_invariants (iter);
1944 if (gtk_text_iter_is_end (iter))
1953 check_invariants (iter);
1961 at_last_indexable_segment (GtkTextRealIter *real)
1963 GtkTextLineSegment *seg;
1965 /* Return TRUE if there are no indexable segments after
1969 seg = real->segment->next;
1972 if (seg->char_count > 0)
1979 /* Goes back to the start of the next segment, even if
1980 * we're not at the start of the current segment (always
1981 * ends up on a different segment if it returns TRUE)
1984 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
1986 /* Move to the start of the previous segment; if no previous
1987 * segment, to the last segment in the previous line. This is
1988 * inherently a bit inefficient due to the singly-linked list and
1989 * tree nodes, but we can't afford the RAM for doubly-linked.
1991 GtkTextRealIter *real;
1992 GtkTextLineSegment *seg;
1993 GtkTextLineSegment *any_seg;
1994 GtkTextLineSegment *prev_seg;
1995 GtkTextLineSegment *prev_any_seg;
1999 g_return_val_if_fail (iter != NULL, FALSE);
2001 real = gtk_text_iter_make_real (iter);
2006 check_invariants (iter);
2008 /* Find first segments in line */
2009 any_seg = real->line->segments;
2011 while (seg->char_count == 0)
2014 if (seg == real->segment)
2016 /* Could probably do this case faster by hand-coding the
2020 /* We were already at the start of a line;
2021 * go back to the previous line.
2023 if (gtk_text_iter_backward_line (iter))
2025 /* Go forward to last indexable segment in line. */
2026 while (!at_last_indexable_segment (real))
2027 _gtk_text_iter_forward_indexable_segment (iter);
2029 check_invariants (iter);
2034 return FALSE; /* We were at the start of the first line. */
2037 /* We must be in the middle of a line; so find the indexable
2038 * segment just before our current segment.
2040 g_assert (seg != real->segment);
2041 while (seg != real->segment)
2044 prev_any_seg = any_seg;
2046 any_seg = seg->next;
2048 while (seg->char_count == 0)
2052 g_assert (prev_seg != NULL);
2053 g_assert (prev_any_seg != NULL);
2054 g_assert (prev_seg->char_count > 0);
2056 /* We skipped the entire previous segment, plus any
2057 * chars we were into the current segment.
2059 if (real->segment_byte_offset >= 0)
2060 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2064 if (real->segment_char_offset >= 0)
2065 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2069 real->segment = prev_seg;
2070 real->any_segment = prev_any_seg;
2071 real->segment_byte_offset = 0;
2072 real->segment_char_offset = 0;
2074 if (bytes_skipped >= 0)
2076 if (real->line_byte_offset >= 0)
2078 real->line_byte_offset -= bytes_skipped;
2079 g_assert (real->line_byte_offset >= 0);
2083 real->line_byte_offset = -1;
2085 if (chars_skipped >= 0)
2087 if (real->line_char_offset >= 0)
2089 real->line_char_offset -= chars_skipped;
2090 g_assert (real->line_char_offset >= 0);
2093 if (real->cached_char_index >= 0)
2095 real->cached_char_index -= chars_skipped;
2096 g_assert (real->cached_char_index >= 0);
2101 real->line_char_offset = -1;
2102 real->cached_char_index = -1;
2105 /* line number is unchanged. */
2107 check_invariants (iter);
2113 * gtk_text_iter_forward_char:
2114 * @iter: an iterator
2116 * Moves @iter forward by one character offset. Note that images
2117 * embedded in the buffer occupy 1 character slot, so
2118 * gtk_text_iter_forward_char () may actually move onto an image instead
2119 * of a character, if you have images in your buffer. If @iter is the
2120 * end iterator or one character before it, @iter will now point at
2121 * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
2122 * convenience when writing loops.
2124 * Return value: whether the new position is the end iterator
2127 gtk_text_iter_forward_char (GtkTextIter *iter)
2129 GtkTextRealIter *real;
2131 g_return_val_if_fail (iter != NULL, FALSE);
2133 real = gtk_text_iter_make_real (iter);
2139 check_invariants (iter);
2140 return forward_char (real);
2145 * gtk_text_iter_backward_char:
2146 * @iter: an iterator
2148 * Moves backward by one character offset. Returns TRUE if movement
2149 * was possible; if @iter was the first in the buffer (character
2150 * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
2153 * Return value: whether movement was possible
2156 gtk_text_iter_backward_char (GtkTextIter *iter)
2158 g_return_val_if_fail (iter != NULL, FALSE);
2160 check_invariants (iter);
2162 return gtk_text_iter_backward_chars (iter, 1);
2166 Definitely we should try to linear scan as often as possible for
2167 movement within a single line, because we can't use the BTree to
2168 speed within-line searches up; for movement between lines, we would
2169 like to avoid the linear scan probably.
2171 Instead of using this constant, it might be nice to cache the line
2172 length in the iterator and linear scan if motion is within a single
2175 I guess you'd have to profile the various approaches.
2177 #define MAX_LINEAR_SCAN 150
2181 * gtk_text_iter_forward_chars:
2182 * @iter: an iterator
2183 * @count: number of characters to move, may be negative
2185 * Moves @count characters if possible (if @count would move past the
2186 * start or end of the buffer, moves to the start or end of the
2187 * buffer). The return value indicates whether the new position of
2188 * @iter is different from its original position, and dereferenceable
2189 * (the last iterator in the buffer is not dereferenceable). If @count
2190 * is 0, the function does nothing and returns FALSE.
2192 * Return value: whether @iter moved and is dereferenceable
2195 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2197 GtkTextRealIter *real;
2199 g_return_val_if_fail (iter != NULL, FALSE);
2201 FIX_OVERFLOWS (count);
2203 real = gtk_text_iter_make_real (iter);
2207 else if (count == 0)
2210 return gtk_text_iter_backward_chars (iter, 0 - count);
2211 else if (count < MAX_LINEAR_SCAN)
2213 check_invariants (iter);
2217 if (!forward_char (real))
2222 return forward_char (real);
2226 gint current_char_index;
2227 gint new_char_index;
2229 check_invariants (iter);
2231 current_char_index = gtk_text_iter_get_offset (iter);
2233 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2234 return FALSE; /* can't move forward */
2236 new_char_index = current_char_index + count;
2237 gtk_text_iter_set_offset (iter, new_char_index);
2239 check_invariants (iter);
2241 /* Return FALSE if we're on the non-dereferenceable end
2244 if (gtk_text_iter_is_end (iter))
2252 * gtk_text_iter_backward_chars:
2253 * @iter: an iterator
2254 * @count: number of characters to move
2256 * Moves @count characters backward, if possible (if @count would move
2257 * past the start or end of the buffer, moves to the start or end of
2258 * the buffer). The return value indicates whether the iterator moved
2259 * onto a dereferenceable position; if the iterator didn't move, or
2260 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2261 * the function does nothing and returns FALSE.
2263 * Return value: whether @iter moved and is dereferenceable
2267 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2269 GtkTextRealIter *real;
2271 g_return_val_if_fail (iter != NULL, FALSE);
2273 FIX_OVERFLOWS (count);
2275 real = gtk_text_iter_make_real (iter);
2279 else if (count == 0)
2282 return gtk_text_iter_forward_chars (iter, 0 - count);
2284 ensure_char_offsets (real);
2285 check_invariants (iter);
2287 if (count <= real->segment_char_offset)
2289 /* Optimize the within-segment case */
2290 g_assert (real->segment->char_count > 0);
2291 g_assert (real->segment->type == >k_text_char_type);
2293 real->segment_char_offset -= count;
2294 g_assert (real->segment_char_offset >= 0);
2296 if (real->line_byte_offset >= 0)
2298 gint new_byte_offset;
2301 new_byte_offset = 0;
2303 while (i < real->segment_char_offset)
2305 const char * start = real->segment->body.chars + new_byte_offset;
2306 new_byte_offset += g_utf8_next_char (start) - start;
2311 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2312 real->segment_byte_offset = new_byte_offset;
2315 real->line_char_offset -= count;
2317 adjust_char_index (real, 0 - count);
2319 check_invariants (iter);
2325 /* We need to go back into previous segments. For now,
2326 * just keep this really simple. FIXME
2327 * use backward_indexable_segment.
2329 if (TRUE || count > MAX_LINEAR_SCAN)
2331 gint current_char_index;
2332 gint new_char_index;
2334 current_char_index = gtk_text_iter_get_offset (iter);
2336 if (current_char_index == 0)
2337 return FALSE; /* can't move backward */
2339 new_char_index = current_char_index - count;
2340 if (new_char_index < 0)
2342 gtk_text_iter_set_offset (iter, new_char_index);
2344 check_invariants (iter);
2350 /* FIXME backward_indexable_segment here */
2359 /* These two can't be implemented efficiently (always have to use
2360 * a linear scan, since that's the only way to find all the non-text
2365 * gtk_text_iter_forward_text_chars:
2366 * @iter: a #GtkTextIter
2367 * @count: number of chars to move
2369 * Moves forward by @count text characters (pixbufs, widgets,
2370 * etc. do not count as characters for this). Equivalent to moving
2371 * through the results of gtk_text_iter_get_text (), rather than
2372 * gtk_text_iter_get_slice ().
2374 * Return value: whether @iter moved and is dereferenceable
2377 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2386 * gtk_text_iter_forward_text_chars:
2387 * @iter: a #GtkTextIter
2388 * @count: number of chars to move
2390 * Moves backward by @count text characters (pixbufs, widgets,
2391 * etc. do not count as characters for this). Equivalent to moving
2392 * through the results of gtk_text_iter_get_text (), rather than
2393 * gtk_text_iter_get_slice ().
2395 * Return value: whether @iter moved and is dereferenceable
2398 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2407 * gtk_text_iter_forward_line:
2408 * @iter: an iterator
2410 * Moves @iter to the start of the next line. Returns TRUE if there
2411 * was a next line to move to, and FALSE if @iter was simply moved to
2412 * the end of the buffer and is now not dereferenceable, or if @iter was
2413 * already at the end of the buffer.
2415 * Return value: whether @iter can be dereferenced
2418 gtk_text_iter_forward_line (GtkTextIter *iter)
2420 GtkTextRealIter *real;
2422 g_return_val_if_fail (iter != NULL, FALSE);
2424 real = gtk_text_iter_make_real (iter);
2429 check_invariants (iter);
2431 if (forward_line_leaving_caches_unmodified (real))
2433 invalidate_char_index (real);
2434 adjust_line_number (real, 1);
2436 check_invariants (iter);
2438 if (gtk_text_iter_is_end (iter))
2445 check_invariants (iter);
2451 * gtk_text_iter_backward_line:
2452 * @iter: an iterator
2454 * Moves @iter to the start of the previous line. Returns TRUE if
2455 * @iter could be moved; i.e. if @iter was at character offset 0, this
2456 * function returns FALSE. Therefore if @iter was already on line 0,
2457 * but not at the start of the line, @iter is snapped to the start of
2458 * the line and the function returns TRUE. (Note that this implies that
2459 * in a loop calling this function, the line number may not change on
2460 * every iteration, if your first iteration is on line 0.)
2462 * Return value: whether @iter moved
2465 gtk_text_iter_backward_line (GtkTextIter *iter)
2467 GtkTextLine *new_line;
2468 GtkTextRealIter *real;
2469 gboolean offset_will_change;
2472 g_return_val_if_fail (iter != NULL, FALSE);
2474 real = gtk_text_iter_make_real (iter);
2479 check_invariants (iter);
2481 new_line = _gtk_text_line_previous (real->line);
2483 offset_will_change = FALSE;
2484 if (real->line_char_offset > 0)
2485 offset_will_change = TRUE;
2487 if (new_line != NULL)
2489 real->line = new_line;
2491 adjust_line_number (real, -1);
2495 if (!offset_will_change)
2499 invalidate_char_index (real);
2501 real->line_byte_offset = 0;
2502 real->line_char_offset = 0;
2504 real->segment_byte_offset = 0;
2505 real->segment_char_offset = 0;
2507 /* Find first segment in line */
2508 real->any_segment = real->line->segments;
2509 real->segment = _gtk_text_line_byte_to_segment (real->line,
2512 g_assert (offset == 0);
2514 /* Note that if we are on the first line, we snap to the start of
2515 * the first line and return TRUE, so TRUE means the iterator
2516 * changed, not that the line changed; this is maybe a bit
2517 * weird. I'm not sure there's an obvious right thing to do though.
2520 check_invariants (iter);
2527 * gtk_text_iter_forward_lines:
2528 * @iter: a #GtkTextIter
2529 * @count: number of lines to move forward
2531 * Moves @count lines forward, if possible (if @count would move
2532 * past the start or end of the buffer, moves to the start or end of
2533 * the buffer). The return value indicates whether the iterator moved
2534 * onto a dereferenceable position; if the iterator didn't move, or
2535 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2536 * the function does nothing and returns FALSE. If @count is negative,
2537 * moves backward by 0 - @count lines.
2539 * Return value: whether @iter moved and is dereferenceable
2542 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2544 FIX_OVERFLOWS (count);
2547 return gtk_text_iter_backward_lines (iter, 0 - count);
2548 else if (count == 0)
2550 else if (count == 1)
2552 check_invariants (iter);
2553 return gtk_text_iter_forward_line (iter);
2559 old_line = gtk_text_iter_get_line (iter);
2561 gtk_text_iter_set_line (iter, old_line + count);
2563 check_invariants (iter);
2565 /* return whether it moved, and is dereferenceable. */
2567 (gtk_text_iter_get_line (iter) != old_line) &&
2568 !gtk_text_iter_is_end (iter);
2573 * gtk_text_iter_backward_lines:
2574 * @iter: a #GtkTextIter
2575 * @count: number of lines to move backward
2577 * Moves @count lines backward, if possible (if @count would move
2578 * past the start or end of the buffer, moves to the start or end of
2579 * the buffer). The return value indicates whether the iterator moved
2580 * onto a dereferenceable position; if the iterator didn't move, or
2581 * moved onto the end iterator, then FALSE is returned. If @count is 0,
2582 * the function does nothing and returns FALSE. If @count is negative,
2583 * moves forward by 0 - @count lines.
2585 * Return value: whether @iter moved and is dereferenceable
2588 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2590 FIX_OVERFLOWS (count);
2593 return gtk_text_iter_forward_lines (iter, 0 - count);
2594 else if (count == 0)
2596 else if (count == 1)
2598 return gtk_text_iter_backward_line (iter);
2604 old_line = gtk_text_iter_get_line (iter);
2606 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2608 return (gtk_text_iter_get_line (iter) != old_line);
2612 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2617 gboolean already_moved_initially);
2619 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2627 find_word_end_func (const PangoLogAttr *attrs,
2632 gboolean already_moved_initially)
2634 if (!already_moved_initially)
2637 /* Find end of next word */
2638 while (offset < min_offset + len &&
2639 !attrs[offset].is_word_end)
2642 *found_offset = offset;
2644 return offset < min_offset + len;
2648 is_word_end_func (const PangoLogAttr *attrs,
2653 return attrs[offset].is_word_end;
2657 find_word_start_func (const PangoLogAttr *attrs,
2662 gboolean already_moved_initially)
2664 if (!already_moved_initially)
2667 /* Find start of prev word */
2668 while (offset >= min_offset &&
2669 !attrs[offset].is_word_start)
2672 *found_offset = offset;
2674 return offset >= min_offset;
2678 is_word_start_func (const PangoLogAttr *attrs,
2683 return attrs[offset].is_word_start;
2687 inside_word_func (const PangoLogAttr *attrs,
2692 /* Find next word start or end */
2693 while (offset >= min_offset &&
2694 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2697 return attrs[offset].is_word_start;
2700 /* Sentence funcs */
2703 find_sentence_end_func (const PangoLogAttr *attrs,
2708 gboolean already_moved_initially)
2710 if (!already_moved_initially)
2713 /* Find end of next sentence */
2714 while (offset < min_offset + len &&
2715 !attrs[offset].is_sentence_end)
2718 *found_offset = offset;
2720 return offset < min_offset + len;
2724 is_sentence_end_func (const PangoLogAttr *attrs,
2729 return attrs[offset].is_sentence_end;
2733 find_sentence_start_func (const PangoLogAttr *attrs,
2738 gboolean already_moved_initially)
2740 if (!already_moved_initially)
2743 /* Find start of prev sentence */
2744 while (offset >= min_offset &&
2745 !attrs[offset].is_sentence_start)
2748 *found_offset = offset;
2750 return offset >= min_offset;
2754 is_sentence_start_func (const PangoLogAttr *attrs,
2759 return attrs[offset].is_sentence_start;
2763 inside_sentence_func (const PangoLogAttr *attrs,
2768 /* Find next sentence start or end */
2769 while (offset >= min_offset &&
2770 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2773 return attrs[offset].is_sentence_start;
2777 test_log_attrs (const GtkTextIter *iter,
2778 TestLogAttrFunc func)
2781 const PangoLogAttr *attrs;
2783 gboolean result = FALSE;
2785 g_return_val_if_fail (iter != NULL, FALSE);
2787 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2790 offset = gtk_text_iter_get_line_offset (iter);
2792 g_assert (char_len > 0);
2794 if (offset < char_len)
2795 result = (* func) (attrs, offset, 0, char_len);
2801 find_line_log_attrs (const GtkTextIter *iter,
2802 FindLogAttrFunc func,
2804 gboolean already_moved_initially)
2807 const PangoLogAttr *attrs;
2809 gboolean result = FALSE;
2811 g_return_val_if_fail (iter != NULL, FALSE);
2813 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2816 offset = gtk_text_iter_get_line_offset (iter);
2818 g_assert (char_len > 0);
2820 if (offset < char_len)
2821 result = (* func) (attrs, offset, 0, char_len, found_offset,
2822 already_moved_initially);
2827 /* FIXME this function is very, very gratuitously slow */
2829 find_by_log_attrs (GtkTextIter *iter,
2830 FindLogAttrFunc func,
2832 gboolean already_moved_initially)
2836 gboolean found = FALSE;
2838 g_return_val_if_fail (iter != NULL, FALSE);
2842 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2848 if (gtk_text_iter_forward_line (iter))
2849 return find_by_log_attrs (iter, func, forward,
2856 /* go to end of previous line */
2857 gtk_text_iter_set_line_offset (iter, 0);
2859 if (gtk_text_iter_backward_char (iter))
2860 return find_by_log_attrs (iter, func, forward,
2868 gtk_text_iter_set_line_offset (iter, offset);
2871 !gtk_text_iter_equal (iter, &orig) &&
2872 !gtk_text_iter_is_end (iter);
2877 * gtk_text_iter_forward_word_end:
2878 * @iter: a #GtkTextIter
2880 * Moves forward to the next word end. (If @iter is currently on a
2881 * word end, moves forward to the next one after that.) Word breaks
2882 * are determined by Pango and should be correct for nearly any
2883 * language (if not, the correct fix would be to the Pango word break
2886 * Return value: %TRUE if @iter moved and is not the end iterator
2889 gtk_text_iter_forward_word_end (GtkTextIter *iter)
2891 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
2895 * gtk_text_iter_backward_word_start:
2896 * @iter: a #GtkTextIter
2898 * Moves backward to the next word start. (If @iter is currently on a
2899 * word start, moves backward to the next one after that.) Word breaks
2900 * are determined by Pango and should be correct for nearly any
2901 * language (if not, the correct fix would be to the Pango word break
2904 * Return value: %TRUE if @iter moved and is not the end iterator
2907 gtk_text_iter_backward_word_start (GtkTextIter *iter)
2909 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
2912 /* FIXME a loop around a truly slow function means
2913 * a truly spectacularly slow function.
2917 * gtk_text_iter_forward_word_ends:
2918 * @iter: a #GtkTextIter
2919 * @count: number of times to move
2921 * Calls gtk_text_iter_forward_word_end() up to @count times.
2923 * Return value: %TRUE if @iter moved and is not the end iterator
2926 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
2929 g_return_val_if_fail (iter != NULL, FALSE);
2931 FIX_OVERFLOWS (count);
2937 return gtk_text_iter_backward_word_starts (iter, -count);
2939 if (!gtk_text_iter_forward_word_end (iter))
2945 if (!gtk_text_iter_forward_word_end (iter))
2953 * gtk_text_iter_backward_word_starts
2954 * @iter: a #GtkTextIter
2955 * @count: number of times to move
2957 * Calls gtk_text_iter_backward_word_starts() up to @count times.
2959 * Return value: %TRUE if @iter moved and is not the end iterator
2962 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
2965 g_return_val_if_fail (iter != NULL, FALSE);
2967 FIX_OVERFLOWS (count);
2970 return gtk_text_iter_forward_word_ends (iter, -count);
2972 if (!gtk_text_iter_backward_word_start (iter))
2978 if (!gtk_text_iter_backward_word_start (iter))
2986 * gtk_text_iter_starts_word:
2987 * @iter: a #GtkTextIter
2989 * Determines whether @iter begins a natural-language word. Word
2990 * breaks are determined by Pango and should be correct for nearly any
2991 * language (if not, the correct fix would be to the Pango word break
2994 * Return value: %TRUE if @iter is at the start of a word
2997 gtk_text_iter_starts_word (const GtkTextIter *iter)
2999 return test_log_attrs (iter, is_word_start_func);
3003 * gtk_text_iter_ends_word:
3004 * @iter: a #GtkTextIter
3006 * Determines whether @iter ends a natural-language word. Word breaks
3007 * are determined by Pango and should be correct for nearly any
3008 * language (if not, the correct fix would be to the Pango word break
3011 * Return value: %TRUE if @iter is at the end of a word
3014 gtk_text_iter_ends_word (const GtkTextIter *iter)
3016 return test_log_attrs (iter, is_word_end_func);
3020 * gtk_text_iter_inside_word:
3021 * @iter: a #GtkTextIter
3023 * Determines whether @iter is inside a natural-language word (as
3024 * opposed to say inside some whitespace). Word breaks are determined
3025 * by Pango and should be correct for nearly any language (if not, the
3026 * correct fix would be to the Pango word break algorithms).
3028 * Return value: %TRUE if @iter is inside a word
3031 gtk_text_iter_inside_word (const GtkTextIter *iter)
3033 return test_log_attrs (iter, inside_word_func);
3037 * gtk_text_iter_starts_sentence:
3038 * @iter: a #GtkTextIter
3040 * Determines whether @iter begins a sentence. Sentence boundaries are
3041 * determined by Pango and should be correct for nearly any language
3042 * (if not, the correct fix would be to the Pango text boundary
3045 * Return value: %TRUE if @iter is at the start of a sentence.
3048 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3050 return test_log_attrs (iter, is_sentence_start_func);
3054 * gtk_text_iter_ends_sentence:
3055 * @iter: a #GtkTextIter
3057 * Determines whether @iter ends a sentence. Sentence boundaries are
3058 * determined by Pango and should be correct for nearly any language
3059 * (if not, the correct fix would be to the Pango text boundary
3062 * Return value: %TRUE if @iter is at the end of a sentence.
3065 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3067 return test_log_attrs (iter, is_sentence_end_func);
3071 * gtk_text_iter_inside_sentence:
3072 * @iter: a #GtkTextIter
3074 * Determines whether @iter is inside a sentence (as opposed to in
3075 * between two sentences, e.g. after a period and before the first
3076 * letter of the next sentence). Sentence boundaries are determined
3077 * by Pango and should be correct for nearly any language (if not, the
3078 * correct fix would be to the Pango text boundary algorithms).
3080 * Return value: %TRUE if @iter is inside a sentence.
3083 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3085 return test_log_attrs (iter, inside_sentence_func);
3089 * gtk_text_iter_forward_sentence_end:
3090 * @iter: a #GtkTextIter
3092 * Moves forward to the next sentence end. (If @iter is at the end of
3093 * a sentence, moves to the next end of sentence.) Sentence
3094 * boundaries are determined by Pango and should be correct for nearly
3095 * any language (if not, the correct fix would be to the Pango text
3096 * boundary algorithms).
3098 * Return value: %TRUE if @iter moved and is not the end iterator
3101 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3103 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3107 * gtk_text_iter_backward_sentence_start:
3108 * @iter: a #GtkTextIter
3110 * Moves backward to the next sentence start; if @iter is already at
3111 * the start of a sentence, moves backward to the next one. Sentence
3112 * boundaries are determined by Pango and should be correct for nearly
3113 * any language (if not, the correct fix would be to the Pango text
3114 * boundary algorithms).
3116 * Return value: %TRUE if @iter moved and is not the end iterator
3119 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3121 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3124 /* FIXME a loop around a truly slow function means
3125 * a truly spectacularly slow function.
3128 * gtk_text_iter_forward_sentence_ends:
3129 * @iter: a #GtkTextIter
3130 * @count: number of sentences to move
3132 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3133 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3134 * negative, moves backward instead of forward.
3136 * Return value: %TRUE if @iter moved and is not the end iterator
3139 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3142 g_return_val_if_fail (iter != NULL, FALSE);
3148 return gtk_text_iter_backward_sentence_starts (iter, -count);
3150 if (!gtk_text_iter_forward_sentence_end (iter))
3156 if (!gtk_text_iter_forward_sentence_end (iter))
3164 * gtk_text_iter_backward_sentence_starts:
3165 * @iter: a #GtkTextIter
3166 * @count: number of sentences to move
3168 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3169 * or until it returns %FALSE. If @count is negative, moves forward
3170 * instead of backward.
3172 * Return value: %TRUE if @iter moved and is not the end iterator
3175 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3178 g_return_val_if_fail (iter != NULL, FALSE);
3181 return gtk_text_iter_forward_sentence_ends (iter, -count);
3183 if (!gtk_text_iter_backward_sentence_start (iter))
3189 if (!gtk_text_iter_backward_sentence_start (iter))
3197 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3202 gboolean already_moved_initially)
3204 if (!already_moved_initially)
3207 while (offset < (min_offset + len) &&
3208 !attrs[offset].is_cursor_position)
3211 *found_offset = offset;
3213 return offset < (min_offset + len);
3217 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3222 gboolean already_moved_initially)
3224 if (!already_moved_initially)
3227 while (offset > min_offset &&
3228 !attrs[offset].is_cursor_position)
3231 *found_offset = offset;
3233 return offset >= min_offset;
3237 is_cursor_pos_func (const PangoLogAttr *attrs,
3242 return attrs[offset].is_cursor_position;
3246 * gtk_text_iter_forward_cursor_position:
3247 * @iter: a #GtkTextIter
3249 * Moves @iter forward by a single cursor position. Cursor positions
3250 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3251 * surprisingly, there may not be a cursor position between all
3252 * characters. The most common example for European languages would be
3253 * a carriage return/newline sequence. For some Unicode characters,
3254 * the equivalent of say the letter "a" with an accent mark will be
3255 * represented as two characters, first the letter then a "combining
3256 * mark" that causes the accent to be rendered; so the cursor can't go
3257 * between those two characters. See also the #PangoLogAttr structure and
3258 * pango_break() function.
3260 * Return value: %TRUE if we moved and the new position is dereferenceable
3263 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3265 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3269 * gtk_text_iter_backward_cursor_position:
3270 * @iter: a #GtkTextIter
3272 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3274 * Return value: %TRUE if we moved and the new position is dereferenceable
3277 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3279 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3283 * gtk_text_iter_forward_cursor_positions:
3284 * @iter: a #GtkTextIter
3285 * @count: number of positions to move
3287 * Moves up to @count cursor positions. See
3288 * gtk_text_iter_forward_cursor_position() for details.
3290 * Return value: %TRUE if we moved and the new position is dereferenceable
3293 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3296 g_return_val_if_fail (iter != NULL, FALSE);
3298 FIX_OVERFLOWS (count);
3304 return gtk_text_iter_backward_cursor_positions (iter, -count);
3306 if (!gtk_text_iter_forward_cursor_position (iter))
3312 if (!gtk_text_iter_forward_cursor_position (iter))
3320 * gtk_text_iter_backward_cursor_positions:
3321 * @iter: a #GtkTextIter
3322 * @count: number of positions to move
3324 * Moves up to @count cursor positions. See
3325 * gtk_text_iter_forward_cursor_position() for details.
3327 * Return value: %TRUE if we moved and the new position is dereferenceable
3330 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3333 g_return_val_if_fail (iter != NULL, FALSE);
3335 FIX_OVERFLOWS (count);
3341 return gtk_text_iter_forward_cursor_positions (iter, -count);
3343 if (!gtk_text_iter_backward_cursor_position (iter))
3349 if (!gtk_text_iter_backward_cursor_position (iter))
3357 * gtk_text_iter_is_cursor_position:
3358 * @iter: a #GtkTextIter
3360 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3361 * pango_break() for details on what a cursor position is.
3363 * Return value: %TRUE if the cursor can be placed at @iter
3366 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3368 return test_log_attrs (iter, is_cursor_pos_func);
3372 * gtk_text_iter_set_line_offset:
3373 * @iter: a #GtkTextIter
3374 * @char_on_line: a character offset relative to the start of @iter's current line
3376 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3377 * (not byte) offset. The given character offset must be less than or
3378 * equal to the number of characters in the line; if equal, @iter
3379 * moves to the start of the next line. See
3380 * gtk_text_iter_set_line_index() if you have a byte index rather than
3381 * a character offset.
3385 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3388 GtkTextRealIter *real;
3391 g_return_if_fail (iter != NULL);
3393 real = gtk_text_iter_make_surreal (iter);
3398 check_invariants (iter);
3400 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3402 g_return_if_fail (char_on_line <= chars_in_line);
3404 if (char_on_line < chars_in_line)
3405 iter_set_from_char_offset (real, real->line, char_on_line);
3407 gtk_text_iter_forward_line (iter); /* set to start of next line */
3409 check_invariants (iter);
3413 * gtk_text_iter_set_line_index:
3414 * @iter: a #GtkTextIter
3415 * @byte_on_line: a byte index relative to the start of @iter's current line
3417 * Same as gtk_text_iter_set_line_offset(), but works with a
3418 * <emphasis>byte</emphasis> index. The given byte index must be at
3419 * the start of a character, it can't be in the middle of a UTF-8
3420 * encoded character.
3424 gtk_text_iter_set_line_index (GtkTextIter *iter,
3427 GtkTextRealIter *real;
3430 g_return_if_fail (iter != NULL);
3432 real = gtk_text_iter_make_surreal (iter);
3437 check_invariants (iter);
3439 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3441 g_return_if_fail (byte_on_line <= bytes_in_line);
3443 if (byte_on_line < bytes_in_line)
3444 iter_set_from_byte_offset (real, real->line, byte_on_line);
3446 gtk_text_iter_forward_line (iter);
3448 if (real->segment->type == >k_text_char_type &&
3449 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3450 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3451 "character; this will crash the text buffer. "
3452 "Byte indexes must refer to the start of a character.",
3453 G_STRLOC, byte_on_line);
3455 check_invariants (iter);
3460 * gtk_text_iter_set_visible_line_offset:
3461 * @iter: a #GtkTextIter
3462 * @char_on_line: a character offset
3464 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3465 * characters, i.e. text with a tag making it invisible is not
3466 * counted in the offset.
3469 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3472 gint chars_seen = 0;
3475 g_return_if_fail (iter != NULL);
3479 /* For now we use a ludicrously slow implementation */
3480 while (chars_seen < char_on_line)
3482 if (!_gtk_text_btree_char_is_invisible (&pos))
3485 if (!gtk_text_iter_forward_char (&pos))
3488 if (chars_seen == char_on_line)
3492 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3495 gtk_text_iter_forward_line (iter);
3499 bytes_in_char (GtkTextIter *iter)
3501 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3505 * gtk_text_iter_set_visible_line_index:
3506 * @iter: a #GtkTextIter
3507 * @byte_on_line: a byte index
3509 * Like gtk_text_iter_set_line_index(), but the index is in visible
3510 * bytes, i.e. text with a tag making it invisible is not counted
3514 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3517 gint bytes_seen = 0;
3520 g_return_if_fail (iter != NULL);
3524 /* For now we use a ludicrously slow implementation */
3525 while (bytes_seen < byte_on_line)
3527 if (!_gtk_text_btree_char_is_invisible (&pos))
3528 bytes_seen += bytes_in_char (&pos);
3530 if (!gtk_text_iter_forward_char (&pos))
3533 if (bytes_seen >= byte_on_line)
3537 if (bytes_seen > byte_on_line)
3538 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3539 "character; this will crash the text buffer. "
3540 "Byte indexes must refer to the start of a character.",
3541 G_STRLOC, byte_on_line);
3543 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3546 gtk_text_iter_forward_line (iter);
3550 * gtk_text_iter_set_line:
3551 * @iter: a #GtkTextIter
3552 * @line_number: line number (counted from 0)
3554 * Moves iterator @iter to the start of the line @line_number.
3558 gtk_text_iter_set_line (GtkTextIter *iter,
3563 GtkTextRealIter *real;
3565 g_return_if_fail (iter != NULL);
3567 real = gtk_text_iter_make_surreal (iter);
3572 check_invariants (iter);
3574 line = _gtk_text_btree_get_line (real->tree, line_number, &real_line);
3576 iter_set_from_char_offset (real, line, 0);
3578 /* We might as well cache this, since we know it. */
3579 real->cached_line_number = real_line;
3581 check_invariants (iter);
3585 * gtk_text_iter_set_offset:
3586 * @iter: a #GtkTextIter
3587 * @char_offset: a character number
3589 * Sets @iter to point to @char_offset. @char_offset counts from the start
3590 * of the entire text buffer, starting with 0.
3594 gtk_text_iter_set_offset (GtkTextIter *iter,
3598 GtkTextRealIter *real;
3600 gint real_char_index;
3602 g_return_if_fail (iter != NULL);
3604 real = gtk_text_iter_make_surreal (iter);
3609 check_invariants (iter);
3611 if (real->cached_char_index >= 0 &&
3612 real->cached_char_index == char_offset)
3615 line = _gtk_text_btree_get_line_at_char (real->tree,
3620 iter_set_from_char_offset (real, line, real_char_index - line_start);
3622 /* Go ahead and cache this since we have it. */
3623 real->cached_char_index = real_char_index;
3625 check_invariants (iter);
3629 * gtk_text_iter_forward_to_end:
3630 * @iter: a #GtkTextIter
3632 * Moves @iter forward to the "end iterator," which points one past the last
3633 * valid character in the buffer. gtk_text_iter_get_char() called on the
3634 * end iterator returns 0, which is convenient for writing loops.
3638 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3640 GtkTextBuffer *buffer;
3641 GtkTextRealIter *real;
3643 g_return_if_fail (iter != NULL);
3645 real = gtk_text_iter_make_surreal (iter);
3650 buffer = _gtk_text_btree_get_buffer (real->tree);
3652 gtk_text_buffer_get_end_iter (buffer, iter);
3656 * gtk_text_iter_forward_to_line_end:
3657 * @iter: a #GtkTextIter
3659 * Moves the iterator to point to the paragraph delimiter characters,
3660 * which will be either a newline, a carriage return, a carriage
3661 * return/newline in sequence, or the Unicode paragraph separator
3662 * character. If the iterator is already at the paragraph delimiter
3663 * characters, moves to the paragraph delimiter characters for the
3666 * Return value: %TRUE if we moved and the new location is not the end iterator
3669 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3671 gint current_offset;
3674 g_return_val_if_fail (iter != NULL, FALSE);
3676 current_offset = gtk_text_iter_get_line_offset (iter);
3677 /* FIXME assumption that line ends in a newline; broken */
3678 new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
3680 if (current_offset < new_offset)
3682 /* Move to end of this line. */
3683 gtk_text_iter_set_line_offset (iter, new_offset);
3688 /* Move to end of next line. */
3689 if (gtk_text_iter_forward_line (iter))
3691 /* We don't want to move past all
3694 if (!gtk_text_iter_ends_line (iter))
3695 gtk_text_iter_forward_to_line_end (iter);
3704 * gtk_text_iter_forward_to_tag_toggle:
3705 * @iter: a #GtkTextIter
3706 * @tag: a #GtkTextTag, or NULL
3708 * Moves forward to the next toggle (on or off) of the
3709 * #GtkTextTag @tag, or to the next toggle of any tag if
3710 * @tag is NULL. If no matching tag toggles are found,
3711 * returns FALSE, otherwise TRUE. Does not return toggles
3712 * located at @iter, only toggles after @iter. Sets @iter to
3713 * the location of the toggle, or to the end of the buffer
3714 * if no toggle is found.
3716 * Return value: whether we found a tag toggle after @iter
3719 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3722 GtkTextLine *next_line;
3723 GtkTextLine *current_line;
3724 GtkTextRealIter *real;
3726 g_return_val_if_fail (iter != NULL, FALSE);
3728 real = gtk_text_iter_make_real (iter);
3733 check_invariants (iter);
3735 current_line = real->line;
3736 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3739 while (_gtk_text_iter_forward_indexable_segment (iter))
3741 /* If we went forward to a line that couldn't contain a toggle
3742 for the tag, then skip forward to a line that could contain
3743 it. This potentially skips huge hunks of the tree, so we
3744 aren't a purely linear search. */
3745 if (real->line != current_line)
3747 if (next_line == NULL)
3749 /* End of search. Set to end of buffer. */
3750 _gtk_text_btree_get_end_iter (real->tree, iter);
3754 if (real->line != next_line)
3755 iter_set_from_byte_offset (real, next_line, 0);
3757 current_line = real->line;
3758 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3763 if (gtk_text_iter_toggles_tag (iter, tag))
3765 /* If there's a toggle here, it isn't indexable so
3766 any_segment can't be the indexable segment. */
3767 g_assert (real->any_segment != real->segment);
3772 /* Check end iterator for tags */
3773 if (gtk_text_iter_toggles_tag (iter, tag))
3775 /* If there's a toggle here, it isn't indexable so
3776 any_segment can't be the indexable segment. */
3777 g_assert (real->any_segment != real->segment);
3781 /* Reached end of buffer */
3786 * gtk_text_iter_backward_to_tag_toggle:
3787 * @iter: a #GtkTextIter
3788 * @tag: a #GtkTextTag, or NULL
3790 * Moves backward to the next toggle (on or off) of the
3791 * #GtkTextTag @tag, or to the next toggle of any tag if
3792 * @tag is NULL. If no matching tag toggles are found,
3793 * returns FALSE, otherwise TRUE. Does not return toggles
3794 * located at @iter, only toggles before @iter. Sets @iter
3795 * to the location of the toggle, or the start of the buffer
3796 * if no toggle is found.
3798 * Return value: whether we found a tag toggle before @iter
3801 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3804 GtkTextLine *prev_line;
3805 GtkTextLine *current_line;
3806 GtkTextRealIter *real;
3808 g_return_val_if_fail (iter != NULL, FALSE);
3810 real = gtk_text_iter_make_real (iter);
3815 check_invariants (iter);
3817 current_line = real->line;
3818 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3822 /* If we're at segment start, go to the previous segment;
3823 * if mid-segment, snap to start of current segment.
3825 if (is_segment_start (real))
3827 if (!_gtk_text_iter_backward_indexable_segment (iter))
3832 ensure_char_offsets (real);
3834 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3840 /* If we went backward to a line that couldn't contain a toggle
3841 * for the tag, then skip backward further to a line that
3842 * could contain it. This potentially skips huge hunks of the
3843 * tree, so we aren't a purely linear search.
3845 if (real->line != current_line)
3847 if (prev_line == NULL)
3849 /* End of search. Set to start of buffer. */
3850 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
3854 if (real->line != prev_line)
3856 /* Set to last segment in prev_line (could do this
3859 iter_set_from_byte_offset (real, prev_line, 0);
3861 while (!at_last_indexable_segment (real))
3862 _gtk_text_iter_forward_indexable_segment (iter);
3865 current_line = real->line;
3866 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3871 if (gtk_text_iter_toggles_tag (iter, tag))
3873 /* If there's a toggle here, it isn't indexable so
3874 * any_segment can't be the indexable segment.
3876 g_assert (real->any_segment != real->segment);
3880 while (_gtk_text_iter_backward_indexable_segment (iter));
3882 /* Reached front of buffer */
3887 matches_pred (GtkTextIter *iter,
3888 GtkTextCharPredicate pred,
3893 ch = gtk_text_iter_get_char (iter);
3895 return (*pred) (ch, user_data);
3899 * gtk_text_iter_forward_find_char:
3900 * @iter: a #GtkTextIter
3901 * @pred: a function to be called on each character
3902 * @user_data: user data for @pred
3903 * @limit: search limit, or %NULL for none
3905 * Advances @iter, calling @pred on each character. If
3906 * @pred returns %TRUE, returns %TRUE and stops scanning.
3907 * If @pred never returns %TRUE, @iter is set to @limit if
3908 * @limit is non-%NULL, otherwise to the end iterator.
3910 * Return value: whether a match was found
3913 gtk_text_iter_forward_find_char (GtkTextIter *iter,
3914 GtkTextCharPredicate pred,
3916 const GtkTextIter *limit)
3918 g_return_val_if_fail (iter != NULL, FALSE);
3919 g_return_val_if_fail (pred != NULL, FALSE);
3922 gtk_text_iter_compare (iter, limit) >= 0)
3925 while ((limit == NULL ||
3926 !gtk_text_iter_equal (limit, iter)) &&
3927 gtk_text_iter_forward_char (iter))
3929 if (matches_pred (iter, pred, user_data))
3937 * gtk_text_iter_backward_find_char:
3938 * @iter: a #GtkTextIter
3939 * @pred: function to be called on each character
3940 * @user_data: user data for @pred
3941 * @limit: search limit, or %NULL for none
3943 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
3945 * Return value: whether a match was found
3948 gtk_text_iter_backward_find_char (GtkTextIter *iter,
3949 GtkTextCharPredicate pred,
3951 const GtkTextIter *limit)
3953 g_return_val_if_fail (iter != NULL, FALSE);
3954 g_return_val_if_fail (pred != NULL, FALSE);
3957 gtk_text_iter_compare (iter, limit) <= 0)
3960 while ((limit == NULL ||
3961 !gtk_text_iter_equal (limit, iter)) &&
3962 gtk_text_iter_backward_char (iter))
3964 if (matches_pred (iter, pred, user_data))
3972 forward_chars_with_skipping (GtkTextIter *iter,
3974 gboolean skip_invisible,
3975 gboolean skip_nontext)
3980 g_return_if_fail (count >= 0);
3986 gboolean ignored = FALSE;
3989 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
3994 _gtk_text_btree_char_is_invisible (iter))
3997 gtk_text_iter_forward_char (iter);
4005 lines_match (const GtkTextIter *start,
4006 const gchar **lines,
4007 gboolean visible_only,
4009 GtkTextIter *match_start,
4010 GtkTextIter *match_end)
4017 if (*lines == NULL || **lines == '\0')
4020 *match_start = *start;
4023 *match_end = *start;
4028 gtk_text_iter_forward_line (&next);
4030 /* No more text in buffer, but *lines is nonempty */
4031 if (gtk_text_iter_equal (start, &next))
4039 line_text = gtk_text_iter_get_visible_slice (start, &next);
4041 line_text = gtk_text_iter_get_slice (start, &next);
4046 line_text = gtk_text_iter_get_visible_text (start, &next);
4048 line_text = gtk_text_iter_get_text (start, &next);
4051 if (match_start) /* if this is the first line we're matching */
4052 found = strstr (line_text, *lines);
4055 /* If it's not the first line, we have to match from the
4056 * start of the line.
4058 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4070 /* Get offset to start of search string */
4071 offset = g_utf8_strlen (line_text, found - line_text);
4075 /* If match start needs to be returned, set it to the
4076 * start of the search string.
4080 *match_start = next;
4082 forward_chars_with_skipping (match_start, offset,
4083 visible_only, !slice);
4086 /* Go to end of search string */
4087 offset += g_utf8_strlen (*lines, -1);
4089 forward_chars_with_skipping (&next, offset,
4090 visible_only, !slice);
4099 /* pass NULL for match_start, since we don't need to find the
4102 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4105 /* strsplit () that retains the delimiter as part of the string. */
4107 strbreakup (const char *string,
4108 const char *delimiter,
4111 GSList *string_list = NULL, *slist;
4112 gchar **str_array, *s;
4115 g_return_val_if_fail (string != NULL, NULL);
4116 g_return_val_if_fail (delimiter != NULL, NULL);
4119 max_tokens = G_MAXINT;
4121 s = strstr (string, delimiter);
4124 guint delimiter_len = strlen (delimiter);
4131 len = s - string + delimiter_len;
4132 new_string = g_new (gchar, len + 1);
4133 strncpy (new_string, string, len);
4134 new_string[len] = 0;
4135 string_list = g_slist_prepend (string_list, new_string);
4137 string = s + delimiter_len;
4138 s = strstr (string, delimiter);
4140 while (--max_tokens && s);
4145 string_list = g_slist_prepend (string_list, g_strdup (string));
4148 str_array = g_new (gchar*, n);
4152 str_array[i--] = NULL;
4153 for (slist = string_list; slist; slist = slist->next)
4154 str_array[i--] = slist->data;
4156 g_slist_free (string_list);
4162 * gtk_text_iter_forward_search:
4163 * @iter: start of search
4164 * @str: a search string
4165 * @visible_only: if %TRUE, search only visible text
4166 * @slice: if %TRUE, @str contains 0xFFFC when we want to match widgets, pixbufs
4167 * @match_start: return location for start of match, or %NULL
4168 * @match_end: return location for end of match, or %NULL
4169 * @limit: bound for the search, or %NULL for the end of the buffer
4171 * Searches forward for @str. Any match is returned as the range @match_start,
4172 * @match_end. If you specify @visible_only or @slice, the match may have
4173 * invisible text, pixbufs, or child widgets interspersed in @str.
4175 * Return value: whether a match was found
4178 gtk_text_iter_forward_search (const GtkTextIter *iter,
4180 gboolean visible_only,
4182 GtkTextIter *match_start,
4183 GtkTextIter *match_end,
4184 const GtkTextIter *limit)
4186 gchar **lines = NULL;
4188 gboolean retval = FALSE;
4191 g_return_val_if_fail (iter != NULL, FALSE);
4192 g_return_val_if_fail (str != NULL, FALSE);
4195 gtk_text_iter_compare (iter, limit) >= 0)
4200 /* If we can move one char, return the empty string there */
4203 if (gtk_text_iter_forward_char (&match))
4206 gtk_text_iter_equal (&match, limit))
4210 *match_start = match;
4219 /* locate all lines */
4221 lines = strbreakup (str, "\n", -1);
4227 /* This loop has an inefficient worst-case, where
4228 * gtk_text_iter_get_text () is called repeatedly on
4234 gtk_text_iter_compare (&search, limit) >= 0)
4237 if (lines_match (&search, (const gchar**)lines,
4238 visible_only, slice, &match, &end))
4240 if (limit == NULL ||
4242 gtk_text_iter_compare (&end, limit) < 0))
4247 *match_start = match;
4256 while (gtk_text_iter_forward_line (&search));
4258 g_strfreev ((gchar**)lines);
4264 vectors_equal_ignoring_trailing (gchar **vec1,
4267 /* Ignores trailing chars in vec2's last line */
4276 if (strcmp (*i1, *i2) != 0)
4278 if (*(i2 + 1) == NULL) /* if this is the last line */
4280 gint len1 = strlen (*i1);
4281 gint len2 = strlen (*i2);
4284 strncmp (*i1, *i2, len1) == 0)
4286 /* We matched ignoring the trailing stuff in vec2 */
4311 typedef struct _LinesWindow LinesWindow;
4317 GtkTextIter first_line_start;
4318 GtkTextIter first_line_end;
4320 gboolean visible_only;
4324 lines_window_init (LinesWindow *win,
4325 const GtkTextIter *start)
4328 GtkTextIter line_start;
4329 GtkTextIter line_end;
4331 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4334 if (gtk_text_iter_is_start (start) ||
4335 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4337 /* Already at the end, or not enough lines to match */
4338 win->lines = g_new0 (gchar*, 1);
4343 line_start = *start;
4346 /* Move to start iter to start of line */
4347 gtk_text_iter_set_line_offset (&line_start, 0);
4349 if (gtk_text_iter_equal (&line_start, &line_end))
4351 /* we were already at the start; so go back one line */
4352 gtk_text_iter_backward_line (&line_start);
4355 win->first_line_start = line_start;
4356 win->first_line_end = line_end;
4358 win->lines = g_new0 (gchar*, win->n_lines + 1);
4360 i = win->n_lines - 1;
4367 if (win->visible_only)
4368 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4370 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4374 if (win->visible_only)
4375 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4377 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4380 win->lines[i] = line_text;
4382 line_end = line_start;
4383 gtk_text_iter_backward_line (&line_start);
4390 lines_window_back (LinesWindow *win)
4392 GtkTextIter new_start;
4395 new_start = win->first_line_start;
4397 if (!gtk_text_iter_backward_line (&new_start))
4401 win->first_line_start = new_start;
4402 win->first_line_end = new_start;
4404 gtk_text_iter_forward_line (&win->first_line_end);
4409 if (win->visible_only)
4410 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4411 &win->first_line_end);
4413 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4414 &win->first_line_end);
4418 if (win->visible_only)
4419 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4420 &win->first_line_end);
4422 line_text = gtk_text_iter_get_text (&win->first_line_start,
4423 &win->first_line_end);
4426 /* Move lines to make room for first line. */
4427 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4429 *win->lines = line_text;
4431 /* Free old last line and NULL-terminate */
4432 g_free (win->lines[win->n_lines]);
4433 win->lines[win->n_lines] = NULL;
4439 lines_window_free (LinesWindow *win)
4441 g_strfreev (win->lines);
4445 my_strrstr (const gchar *haystack,
4446 const gchar *needle)
4448 /* FIXME GLib should have a nice implementation in it, this
4452 gint haystack_len = strlen (haystack);
4453 gint needle_len = strlen (needle);
4454 const gchar *needle_end = needle + needle_len;
4455 const gchar *haystack_rend = haystack - 1;
4456 const gchar *needle_rend = needle - 1;
4459 p = haystack + haystack_len;
4460 while (p != haystack)
4462 const gchar *n = needle_end - 1;
4463 const gchar *s = p - 1;
4464 while (s != haystack_rend &&
4472 if (n == needle_rend)
4482 * gtk_text_iter_backward_search:
4483 * @iter: a #GtkTextIter where the search begins
4484 * @str: search string
4485 * @visible_only: if %TRUE search only visible text
4486 * @slice: if %TRUE the search string contains 0xFFFC to match pixbufs, widgets
4487 * @match_start: return location for start of match, or %NULL
4488 * @match_end: return location for end of match, or %NULL
4489 * @limit: location of last possible @match_start, or %NULL for start of buffer
4491 * Same as gtk_text_iter_forward_search(), but moves backward.
4493 * Return value: whether a match was found
4496 gtk_text_iter_backward_search (const GtkTextIter *iter,
4498 gboolean visible_only,
4500 GtkTextIter *match_start,
4501 GtkTextIter *match_end,
4502 const GtkTextIter *limit)
4504 gchar **lines = NULL;
4508 gboolean retval = FALSE;
4510 g_return_val_if_fail (iter != NULL, FALSE);
4511 g_return_val_if_fail (str != NULL, FALSE);
4514 gtk_text_iter_compare (limit, iter) > 0)
4519 /* If we can move one char, return the empty string there */
4520 GtkTextIter match = *iter;
4522 if (limit && gtk_text_iter_equal (limit, &match))
4525 if (gtk_text_iter_backward_char (&match))
4528 *match_start = match;
4537 /* locate all lines */
4539 lines = strbreakup (str, "\n", -1);
4549 win.n_lines = n_lines;
4551 win.visible_only = visible_only;
4553 lines_window_init (&win, iter);
4555 if (*win.lines == NULL)
4560 gchar *first_line_match;
4563 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4565 /* We're now before the search limit, abort. */
4569 /* If there are multiple lines, the first line will
4570 * end in '\n', so this will only match at the
4571 * end of the first line, which is correct.
4573 first_line_match = my_strrstr (*win.lines, *lines);
4575 if (first_line_match &&
4576 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4581 GtkTextIter start_tmp;
4583 /* Offset to start of search string */
4584 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4586 next = win.first_line_start;
4588 forward_chars_with_skipping (&start_tmp, offset,
4589 visible_only, !slice);
4592 gtk_text_iter_compare (limit, &start_tmp) > 0)
4593 goto out; /* match was bogus */
4596 *match_start = start_tmp;
4598 /* Go to end of search string */
4602 offset += g_utf8_strlen (*l, -1);
4606 forward_chars_with_skipping (&next, offset,
4607 visible_only, !slice);
4616 while (lines_window_back (&win));
4619 lines_window_free (&win);
4630 * gtk_text_iter_equal:
4631 * @lhs: a #GtkTextIter
4632 * @rhs: another #GtkTextIter
4634 * Tests whether two iterators are equal, using the fastest possible
4635 * mechanism. This function is very fast; you can expect it to perform
4636 * better than e.g. getting the character offset for each iterator and
4637 * comparing the offsets yourself. Also, it's a bit faster than
4638 * gtk_text_iter_compare().
4640 * Return value: %TRUE if the iterators point to the same place in the buffer
4643 gtk_text_iter_equal (const GtkTextIter *lhs,
4644 const GtkTextIter *rhs)
4646 GtkTextRealIter *real_lhs;
4647 GtkTextRealIter *real_rhs;
4649 real_lhs = (GtkTextRealIter*)lhs;
4650 real_rhs = (GtkTextRealIter*)rhs;
4652 check_invariants (lhs);
4653 check_invariants (rhs);
4655 if (real_lhs->line != real_rhs->line)
4657 else if (real_lhs->line_byte_offset >= 0 &&
4658 real_rhs->line_byte_offset >= 0)
4659 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4662 /* the ensure_char_offsets () calls do nothing if the char offsets
4663 are already up-to-date. */
4664 ensure_char_offsets (real_lhs);
4665 ensure_char_offsets (real_rhs);
4666 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4671 * gtk_text_iter_compare:
4672 * @lhs: a #GtkTextIter
4673 * @rhs: another #GtkTextIter
4675 * A qsort()-style function that returns negative if @lhs is less than
4676 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4677 * Ordering is in character offset order, i.e. the first character in the buffer
4678 * is less than the second character in the buffer.
4680 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4683 gtk_text_iter_compare (const GtkTextIter *lhs,
4684 const GtkTextIter *rhs)
4686 GtkTextRealIter *real_lhs;
4687 GtkTextRealIter *real_rhs;
4689 real_lhs = gtk_text_iter_make_surreal (lhs);
4690 real_rhs = gtk_text_iter_make_surreal (rhs);
4692 if (real_lhs == NULL ||
4694 return -1; /* why not */
4696 check_invariants (lhs);
4697 check_invariants (rhs);
4699 if (real_lhs->line == real_rhs->line)
4701 gint left_index, right_index;
4703 if (real_lhs->line_byte_offset >= 0 &&
4704 real_rhs->line_byte_offset >= 0)
4706 left_index = real_lhs->line_byte_offset;
4707 right_index = real_rhs->line_byte_offset;
4711 /* the ensure_char_offsets () calls do nothing if
4712 the offsets are already up-to-date. */
4713 ensure_char_offsets (real_lhs);
4714 ensure_char_offsets (real_rhs);
4715 left_index = real_lhs->line_char_offset;
4716 right_index = real_rhs->line_char_offset;
4719 if (left_index < right_index)
4721 else if (left_index > right_index)
4730 line1 = gtk_text_iter_get_line (lhs);
4731 line2 = gtk_text_iter_get_line (rhs);
4734 else if (line1 > line2)
4742 * gtk_text_iter_in_range:
4743 * @iter: a #GtkTextIter
4744 * @start: start of range
4745 * @end: end of range
4747 * Checks whether @iter falls in the range [@start, @end).
4748 * @start and @end must be in ascending order.
4750 * Return value: %TRUE if @iter is in the range
4753 gtk_text_iter_in_range (const GtkTextIter *iter,
4754 const GtkTextIter *start,
4755 const GtkTextIter *end)
4757 g_return_val_if_fail (iter != NULL, FALSE);
4758 g_return_val_if_fail (start != NULL, FALSE);
4759 g_return_val_if_fail (end != NULL, FALSE);
4760 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4762 return gtk_text_iter_compare (iter, start) >= 0 &&
4763 gtk_text_iter_compare (iter, end) < 0;
4767 * gtk_text_iter_order:
4768 * @first: a #GtkTextIter
4769 * @second: another #GtkTextIter
4771 * Swaps the value of @first and @second if @second comes before
4772 * @first in the buffer. That is, ensures that @first and @second are
4773 * in sequence. Most text buffer functions that take a range call this
4774 * automatically on your behalf, so there's no real reason to call it yourself
4775 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4776 * that expect a pre-sorted range.
4780 gtk_text_iter_order (GtkTextIter *first,
4781 GtkTextIter *second)
4783 g_return_if_fail (first != NULL);
4784 g_return_if_fail (second != NULL);
4786 if (gtk_text_iter_compare (first, second) > 0)
4797 * Init iterators from the BTree
4801 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4805 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4806 gint real_char_index;
4810 g_return_if_fail (iter != NULL);
4811 g_return_if_fail (tree != NULL);
4813 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4814 &line_start, &real_char_index);
4816 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4818 real->cached_char_index = real_char_index;
4820 check_invariants (iter);
4824 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
4829 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4833 g_return_if_fail (iter != NULL);
4834 g_return_if_fail (tree != NULL);
4836 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4838 iter_init_from_char_offset (iter, tree, line, char_on_line);
4840 /* We might as well cache this, since we know it. */
4841 real->cached_line_number = real_line;
4843 check_invariants (iter);
4847 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
4852 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4856 g_return_if_fail (iter != NULL);
4857 g_return_if_fail (tree != NULL);
4859 line = _gtk_text_btree_get_line (tree, line_number, &real_line);
4861 iter_init_from_byte_offset (iter, tree, line, byte_index);
4863 /* We might as well cache this, since we know it. */
4864 real->cached_line_number = real_line;
4866 check_invariants (iter);
4870 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
4875 g_return_if_fail (iter != NULL);
4876 g_return_if_fail (tree != NULL);
4877 g_return_if_fail (line != NULL);
4879 iter_init_from_byte_offset (iter, tree, line, byte_offset);
4881 check_invariants (iter);
4885 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
4891 g_return_val_if_fail (iter != NULL, FALSE);
4892 g_return_val_if_fail (tree != NULL, FALSE);
4894 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
4898 /* Set iter to last in tree */
4899 _gtk_text_btree_get_end_iter (tree, iter);
4900 check_invariants (iter);
4905 iter_init_from_byte_offset (iter, tree, line, 0);
4906 gtk_text_iter_forward_to_tag_toggle (iter, tag);
4907 check_invariants (iter);
4913 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
4917 g_return_val_if_fail (iter != NULL, FALSE);
4918 g_return_val_if_fail (tree != NULL, FALSE);
4920 _gtk_text_btree_get_end_iter (tree, iter);
4921 gtk_text_iter_backward_to_tag_toggle (iter, tag);
4922 check_invariants (iter);
4928 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
4930 const gchar *mark_name)
4934 g_return_val_if_fail (iter != NULL, FALSE);
4935 g_return_val_if_fail (tree != NULL, FALSE);
4937 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
4943 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
4944 check_invariants (iter);
4950 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
4954 GtkTextLineSegment *seg;
4956 g_return_if_fail (iter != NULL);
4957 g_return_if_fail (tree != NULL);
4958 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
4960 seg = mark->segment;
4962 iter_init_from_segment (iter, tree,
4963 seg->body.mark.line, seg);
4964 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
4965 check_invariants (iter);
4969 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
4971 GtkTextChildAnchor *anchor)
4973 GtkTextLineSegment *seg;
4975 g_return_if_fail (iter != NULL);
4976 g_return_if_fail (tree != NULL);
4977 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
4979 seg = anchor->segment;
4981 iter_init_from_segment (iter, tree,
4982 seg->body.child.line, seg);
4983 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
4984 check_invariants (iter);
4988 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
4991 g_return_if_fail (iter != NULL);
4992 g_return_if_fail (tree != NULL);
4994 _gtk_text_btree_get_iter_at_char (tree,
4996 _gtk_text_btree_char_count (tree));
4997 check_invariants (iter);
5001 _gtk_text_iter_check (const GtkTextIter *iter)
5003 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5004 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5005 GtkTextLineSegment *byte_segment = NULL;
5006 GtkTextLineSegment *byte_any_segment = NULL;
5007 GtkTextLineSegment *char_segment = NULL;
5008 GtkTextLineSegment *char_any_segment = NULL;
5009 gboolean segments_updated;
5011 /* This function checks our class invariants for the Iter class. */
5013 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5015 if (real->chars_changed_stamp !=
5016 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5017 g_error ("iterator check failed: invalid iterator");
5019 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5020 g_error ("iterator check failed: both char and byte offsets are invalid");
5022 segments_updated = (real->segments_changed_stamp ==
5023 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5026 printf ("checking iter, segments %s updated, byte %d char %d\n",
5027 segments_updated ? "are" : "aren't",
5028 real->line_byte_offset,
5029 real->line_char_offset);
5032 if (segments_updated)
5034 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5035 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5037 if (real->segment->char_count == 0)
5038 g_error ("iterator check failed: segment is not indexable.");
5040 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5041 g_error ("segment char offset is not properly up-to-date");
5043 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5044 g_error ("segment byte offset is not properly up-to-date");
5046 if (real->segment_byte_offset >= 0 &&
5047 real->segment_byte_offset >= real->segment->byte_count)
5048 g_error ("segment byte offset is too large.");
5050 if (real->segment_char_offset >= 0 &&
5051 real->segment_char_offset >= real->segment->char_count)
5052 g_error ("segment char offset is too large.");
5055 if (real->line_byte_offset >= 0)
5057 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5058 &byte_segment, &byte_any_segment,
5059 &seg_byte_offset, &line_byte_offset);
5061 if (line_byte_offset != real->line_byte_offset)
5062 g_error ("wrong byte offset was stored in iterator");
5064 if (segments_updated)
5066 if (real->segment != byte_segment)
5067 g_error ("wrong segment was stored in iterator");
5069 if (real->any_segment != byte_any_segment)
5070 g_error ("wrong any_segment was stored in iterator");
5072 if (seg_byte_offset != real->segment_byte_offset)
5073 g_error ("wrong segment byte offset was stored in iterator");
5075 if (byte_segment->type == >k_text_char_type)
5078 p = byte_segment->body.chars + seg_byte_offset;
5080 if (!gtk_text_byte_begins_utf8_char (p))
5081 g_error ("broken iterator byte index pointed into the middle of a character");
5086 if (real->line_char_offset >= 0)
5088 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5089 &char_segment, &char_any_segment,
5090 &seg_char_offset, &line_char_offset);
5092 if (line_char_offset != real->line_char_offset)
5093 g_error ("wrong char offset was stored in iterator");
5095 if (segments_updated)
5097 if (real->segment != char_segment)
5098 g_error ("wrong segment was stored in iterator");
5100 if (real->any_segment != char_any_segment)
5101 g_error ("wrong any_segment was stored in iterator");
5103 if (seg_char_offset != real->segment_char_offset)
5104 g_error ("wrong segment char offset was stored in iterator");
5106 if (char_segment->type == >k_text_char_type)
5109 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5112 /* hmm, not likely to happen eh */
5113 if (!gtk_text_byte_begins_utf8_char (p))
5114 g_error ("broken iterator char offset pointed into the middle of a character");
5119 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5121 if (byte_segment != char_segment)
5122 g_error ("char and byte offsets did not point to the same segment");
5124 if (byte_any_segment != char_any_segment)
5125 g_error ("char and byte offsets did not point to the same any segment");
5127 /* Make sure the segment offsets are equivalent, if it's a char
5129 if (char_segment->type == >k_text_char_type)
5131 gint byte_offset = 0;
5132 gint char_offset = 0;
5133 while (char_offset < seg_char_offset)
5135 const char * start = char_segment->body.chars + byte_offset;
5136 byte_offset += g_utf8_next_char (start) - start;
5140 if (byte_offset != seg_byte_offset)
5141 g_error ("byte offset did not correspond to char offset");
5144 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5146 if (char_offset != seg_char_offset)
5147 g_error ("char offset did not correspond to byte offset");
5149 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5150 g_error ("byte index for iterator does not index the start of a character");
5154 if (real->cached_line_number >= 0)
5158 should_be = _gtk_text_line_get_number (real->line);
5159 if (real->cached_line_number != should_be)
5160 g_error ("wrong line number was cached");
5163 if (real->cached_char_index >= 0)
5165 if (real->line_char_offset >= 0) /* only way we can check it
5166 efficiently, not a real
5171 char_index = _gtk_text_line_char_index (real->line);
5172 char_index += real->line_char_offset;
5174 if (real->cached_char_index != char_index)
5175 g_error ("wrong char index was cached");