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 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include "gtktextiter.h"
29 #include "gtktextbtree.h"
30 #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;
73 /* These "set" functions should not assume any fields
74 other than the char stamp and the tree are valid.
77 iter_set_common (GtkTextRealIter *iter,
80 /* Update segments stamp */
81 iter->segments_changed_stamp =
82 _gtk_text_btree_get_segments_changed_stamp (iter->tree);
86 iter->line_byte_offset = -1;
87 iter->line_char_offset = -1;
88 iter->segment_byte_offset = -1;
89 iter->segment_char_offset = -1;
90 iter->cached_char_index = -1;
91 iter->cached_line_number = -1;
95 iter_set_from_byte_offset (GtkTextRealIter *iter,
99 iter_set_common (iter, line);
101 if (!_gtk_text_line_byte_locate (iter->line,
105 &iter->segment_byte_offset,
106 &iter->line_byte_offset))
107 g_error ("Byte index %d is off the end of the line",
112 iter_set_from_char_offset (GtkTextRealIter *iter,
116 iter_set_common (iter, line);
118 if (!_gtk_text_line_char_locate (iter->line,
122 &iter->segment_char_offset,
123 &iter->line_char_offset))
124 g_error ("Char offset %d is off the end of the line",
129 iter_set_from_segment (GtkTextRealIter *iter,
131 GtkTextLineSegment *segment)
133 GtkTextLineSegment *seg;
136 /* This could theoretically be optimized by computing all the iter
137 fields in this same loop, but I'm skipping it for now. */
139 seg = line->segments;
140 while (seg != segment)
142 byte_offset += seg->byte_count;
146 iter_set_from_byte_offset (iter, line, byte_offset);
149 /* This function ensures that the segment-dependent information is
150 truly computed lazily; often we don't need to do the full make_real
151 work. This ensures the btree and line are valid, but doesn't
152 update the segments. */
153 static GtkTextRealIter*
154 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
156 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
158 if (iter->chars_changed_stamp !=
159 _gtk_text_btree_get_chars_changed_stamp (iter->tree))
161 g_warning ("Invalid text buffer iterator: either the iterator "
162 "is uninitialized, or the characters/pixbufs/widgets "
163 "in the buffer have been modified since the iterator "
164 "was created.\nYou must use marks, character numbers, "
165 "or line numbers to preserve a position across buffer "
166 "modifications.\nYou can apply tags and insert marks "
167 "without invalidating your iterators,\n"
168 "but any mutation that affects 'indexable' buffer contents "
169 "(contents that can be referred to by character offset)\n"
170 "will invalidate all outstanding iterators");
174 /* We don't update the segments information since we are becoming
175 only surreal. However we do invalidate the segments information
176 if appropriate, to be sure we segfault if we try to use it and we
177 should have used make_real. */
179 if (iter->segments_changed_stamp !=
180 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
182 iter->segment = NULL;
183 iter->any_segment = NULL;
184 /* set to segfault-causing values. */
185 iter->segment_byte_offset = -10000;
186 iter->segment_char_offset = -10000;
192 static GtkTextRealIter*
193 gtk_text_iter_make_real (const GtkTextIter *_iter)
195 GtkTextRealIter *iter;
197 iter = gtk_text_iter_make_surreal (_iter);
199 if (iter->segments_changed_stamp !=
200 _gtk_text_btree_get_segments_changed_stamp (iter->tree))
202 if (iter->line_byte_offset >= 0)
204 iter_set_from_byte_offset (iter,
206 iter->line_byte_offset);
210 g_assert (iter->line_char_offset >= 0);
212 iter_set_from_char_offset (iter,
214 iter->line_char_offset);
218 g_assert (iter->segment != NULL);
219 g_assert (iter->any_segment != NULL);
220 g_assert (iter->segment->char_count > 0);
225 static GtkTextRealIter*
226 iter_init_common (GtkTextIter *_iter,
229 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
231 g_return_val_if_fail (iter != NULL, NULL);
232 g_return_val_if_fail (tree != NULL, NULL);
236 iter->chars_changed_stamp =
237 _gtk_text_btree_get_chars_changed_stamp (iter->tree);
242 static GtkTextRealIter*
243 iter_init_from_segment (GtkTextIter *iter,
246 GtkTextLineSegment *segment)
248 GtkTextRealIter *real;
250 g_return_val_if_fail (line != NULL, NULL);
252 real = iter_init_common (iter, tree);
254 iter_set_from_segment (real, line, segment);
259 static GtkTextRealIter*
260 iter_init_from_byte_offset (GtkTextIter *iter,
263 gint line_byte_offset)
265 GtkTextRealIter *real;
267 g_return_val_if_fail (line != NULL, NULL);
269 real = iter_init_common (iter, tree);
271 iter_set_from_byte_offset (real, line, line_byte_offset);
273 if (real->segment->type == >k_text_char_type &&
274 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
275 g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
276 "character; this will crash the text buffer. "
277 "Byte indexes must refer to the start of a character.",
283 static GtkTextRealIter*
284 iter_init_from_char_offset (GtkTextIter *iter,
287 gint line_char_offset)
289 GtkTextRealIter *real;
291 g_return_val_if_fail (line != NULL, NULL);
293 real = iter_init_common (iter, tree);
295 iter_set_from_char_offset (real, line, line_char_offset);
301 invalidate_segment (GtkTextRealIter *iter)
303 iter->segments_changed_stamp -= 1;
307 invalidate_char_index (GtkTextRealIter *iter)
309 iter->cached_char_index = -1;
313 invalidate_line_number (GtkTextRealIter *iter)
315 iter->cached_line_number = -1;
319 adjust_char_index (GtkTextRealIter *iter, gint count)
321 if (iter->cached_char_index >= 0)
322 iter->cached_char_index += count;
326 adjust_line_number (GtkTextRealIter *iter, gint count)
328 if (iter->cached_line_number >= 0)
329 iter->cached_line_number += count;
333 adjust_char_offsets (GtkTextRealIter *iter, gint count)
335 if (iter->line_char_offset >= 0)
337 iter->line_char_offset += count;
338 g_assert (iter->segment_char_offset >= 0);
339 iter->segment_char_offset += count;
344 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
346 if (iter->line_byte_offset >= 0)
348 iter->line_byte_offset += count;
349 g_assert (iter->segment_byte_offset >= 0);
350 iter->segment_byte_offset += count;
355 ensure_char_offsets (GtkTextRealIter *iter)
357 if (iter->line_char_offset < 0)
359 g_assert (iter->line_byte_offset >= 0);
361 _gtk_text_line_byte_to_char_offsets (iter->line,
362 iter->line_byte_offset,
363 &iter->line_char_offset,
364 &iter->segment_char_offset);
369 ensure_byte_offsets (GtkTextRealIter *iter)
371 if (iter->line_byte_offset < 0)
373 g_assert (iter->line_char_offset >= 0);
375 _gtk_text_line_char_to_byte_offsets (iter->line,
376 iter->line_char_offset,
377 &iter->line_byte_offset,
378 &iter->segment_byte_offset);
382 static inline gboolean
383 is_segment_start (GtkTextRealIter *real)
385 return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
390 check_invariants (const GtkTextIter *iter)
392 if (gtk_debug_flags & GTK_DEBUG_TEXT)
393 _gtk_text_iter_check (iter);
396 #define check_invariants (x)
400 * gtk_text_iter_get_buffer:
403 * Returns the #GtkTextBuffer this iterator is associated with.
405 * Return value: the buffer
408 gtk_text_iter_get_buffer (const GtkTextIter *iter)
410 GtkTextRealIter *real;
412 g_return_val_if_fail (iter != NULL, NULL);
414 real = gtk_text_iter_make_surreal (iter);
419 check_invariants (iter);
421 return _gtk_text_btree_get_buffer (real->tree);
425 * gtk_text_iter_copy:
428 * Creates a dynamically-allocated copy of an iterator. This function
429 * is not useful in applications, because iterators can be copied with a
430 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
431 * function is used by language bindings.
433 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
436 gtk_text_iter_copy (const GtkTextIter *iter)
438 GtkTextIter *new_iter;
440 g_return_val_if_fail (iter != NULL, NULL);
442 new_iter = g_new (GtkTextIter, 1);
450 * gtk_text_iter_free:
451 * @iter: a dynamically-allocated iterator
453 * Free an iterator allocated on the heap. This function
454 * is intended for use in language bindings, and is not
455 * especially useful for applications, because iterators can
456 * simply be allocated on the stack.
459 gtk_text_iter_free (GtkTextIter *iter)
461 g_return_if_fail (iter != NULL);
467 gtk_text_iter_get_type (void)
469 static GType our_type = 0;
472 our_type = g_boxed_type_register_static ("GtkTypeTextIter",
473 (GBoxedCopyFunc) gtk_text_iter_copy,
474 (GBoxedFreeFunc) gtk_text_iter_free);
480 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
482 GtkTextRealIter *real;
484 g_return_val_if_fail (iter != NULL, 0);
486 real = gtk_text_iter_make_real (iter);
491 check_invariants (iter);
493 g_assert (real->segment != NULL);
495 return real->segment;
499 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
501 GtkTextRealIter *real;
503 g_return_val_if_fail (iter != NULL, 0);
505 real = gtk_text_iter_make_real (iter);
510 check_invariants (iter);
512 g_assert (real->any_segment != NULL);
514 return real->any_segment;
518 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
520 GtkTextRealIter *real;
522 g_return_val_if_fail (iter != NULL, 0);
524 real = gtk_text_iter_make_real (iter);
529 ensure_byte_offsets (real);
531 check_invariants (iter);
533 return real->segment_byte_offset;
537 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
539 GtkTextRealIter *real;
541 g_return_val_if_fail (iter != NULL, 0);
543 real = gtk_text_iter_make_real (iter);
548 ensure_char_offsets (real);
550 check_invariants (iter);
552 return real->segment_char_offset;
555 /* This function does not require a still-valid
558 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
560 const GtkTextRealIter *real;
562 g_return_val_if_fail (iter != NULL, 0);
564 real = (const GtkTextRealIter*)iter;
569 /* This function does not require a still-valid
572 _gtk_text_iter_get_btree (const GtkTextIter *iter)
574 const GtkTextRealIter *real;
576 g_return_val_if_fail (iter != NULL, 0);
578 real = (const GtkTextRealIter*)iter;
588 * gtk_text_iter_get_offset:
591 * Returns the character offset of an iterator.
592 * Each character in a #GtkTextBuffer has an offset,
593 * starting with 0 for the first character in the buffer.
594 * Use gtk_text_buffer_get_iter_at_offset () to convert an
595 * offset back into an iterator.
597 * Return value: a character offset
600 gtk_text_iter_get_offset (const GtkTextIter *iter)
602 GtkTextRealIter *real;
604 g_return_val_if_fail (iter != NULL, 0);
606 real = gtk_text_iter_make_surreal (iter);
611 check_invariants (iter);
613 if (real->cached_char_index < 0)
615 ensure_char_offsets (real);
617 real->cached_char_index =
618 _gtk_text_line_char_index (real->line);
619 real->cached_char_index += real->line_char_offset;
622 check_invariants (iter);
624 return real->cached_char_index;
628 * gtk_text_iter_get_line:
631 * Returns the line number containing the iterator. Lines in
632 * a #GtkTextBuffer are numbered beginning with 0 for the first
633 * line in the buffer.
635 * Return value: a line number
638 gtk_text_iter_get_line (const GtkTextIter *iter)
640 GtkTextRealIter *real;
642 g_return_val_if_fail (iter != NULL, 0);
644 real = gtk_text_iter_make_surreal (iter);
649 if (real->cached_line_number < 0)
650 real->cached_line_number =
651 _gtk_text_line_get_number (real->line);
653 check_invariants (iter);
655 return real->cached_line_number;
659 * gtk_text_iter_get_line_offset:
662 * Returns the character offset of the iterator,
663 * counting from the start of a newline-terminated line.
664 * The first character on the line has offset 0.
666 * Return value: offset from start of line
669 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
671 GtkTextRealIter *real;
673 g_return_val_if_fail (iter != NULL, 0);
675 real = gtk_text_iter_make_surreal (iter);
680 ensure_char_offsets (real);
682 check_invariants (iter);
684 return real->line_char_offset;
688 * gtk_text_iter_get_line_index:
691 * Returns the byte index of the iterator, counting
692 * from the start of a newline-terminated line.
693 * Remember that #GtkTextBuffer encodes text in
694 * UTF-8, and that characters can require a variable
695 * number of bytes to represent.
697 * Return value: distance from start of line, in bytes
700 gtk_text_iter_get_line_index (const GtkTextIter *iter)
702 GtkTextRealIter *real;
704 g_return_val_if_fail (iter != NULL, 0);
706 real = gtk_text_iter_make_surreal (iter);
711 ensure_byte_offsets (real);
713 check_invariants (iter);
715 return real->line_byte_offset;
719 * gtk_text_iter_get_visible_line_offset:
720 * @iter: a #GtkTextIter
722 * Returns the offset in characters from the start of the
723 * line to the given @iter, not counting characters that
724 * are invisible due to tags with the "invisible" flag
727 * Return value: offset in visible characters from the start of the line
730 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
732 GtkTextRealIter *real;
734 GtkTextLineSegment *seg;
737 g_return_val_if_fail (iter != NULL, 0);
739 real = gtk_text_iter_make_real (iter);
744 ensure_char_offsets (real);
746 check_invariants (iter);
748 vis_offset = real->line_char_offset;
750 g_assert (vis_offset >= 0);
752 _gtk_text_btree_get_iter_at_line (real->tree,
757 seg = _gtk_text_iter_get_indexable_segment (&pos);
759 while (seg != real->segment)
761 /* This is a pretty expensive call, making the
762 * whole function pretty lame; we could keep track
763 * of current invisibility state by looking at toggle
764 * segments as we loop, and then call this function
765 * only once per line, in order to speed up the loop
768 if (_gtk_text_btree_char_is_invisible (&pos))
769 vis_offset -= seg->char_count;
771 _gtk_text_iter_forward_indexable_segment (&pos);
773 seg = _gtk_text_iter_get_indexable_segment (&pos);
776 if (_gtk_text_btree_char_is_invisible (&pos))
777 vis_offset -= real->segment_char_offset;
784 * gtk_text_iter_get_visible_line_index:
785 * @iter: a #GtkTextIter
787 * Returns the number of bytes from the start of the
788 * line to the given @iter, not counting bytes that
789 * are invisible due to tags with the "invisible" flag
792 * Return value: byte index of @iter with respect to the start of the line
795 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
797 GtkTextRealIter *real;
799 GtkTextLineSegment *seg;
802 g_return_val_if_fail (iter != NULL, 0);
804 real = gtk_text_iter_make_real (iter);
809 ensure_byte_offsets (real);
811 check_invariants (iter);
813 vis_offset = real->line_byte_offset;
815 g_assert (vis_offset >= 0);
817 _gtk_text_btree_get_iter_at_line (real->tree,
822 seg = _gtk_text_iter_get_indexable_segment (&pos);
824 while (seg != real->segment)
826 /* This is a pretty expensive call, making the
827 * whole function pretty lame; we could keep track
828 * of current invisibility state by looking at toggle
829 * segments as we loop, and then call this function
830 * only once per line, in order to speed up the loop
833 if (_gtk_text_btree_char_is_invisible (&pos))
834 vis_offset -= seg->byte_count;
836 _gtk_text_iter_forward_indexable_segment (&pos);
838 seg = _gtk_text_iter_get_indexable_segment (&pos);
841 if (_gtk_text_btree_char_is_invisible (&pos))
842 vis_offset -= real->segment_byte_offset;
852 * gtk_text_iter_get_char:
855 * Returns the Unicode character at this iterator. (Equivalent to
856 * operator* on a C++ iterator.) If the iterator points at a
857 * non-character element, such as an image embedded in the buffer, the
858 * Unicode "unknown" character 0xFFFC is returned. If invoked on
859 * the end iterator, zero is returned; zero is not a valid Unicode character.
860 * So you can write a loop which ends when gtk_text_iter_get_char ()
863 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
866 gtk_text_iter_get_char (const GtkTextIter *iter)
868 GtkTextRealIter *real;
870 g_return_val_if_fail (iter != NULL, 0);
872 real = gtk_text_iter_make_real (iter);
877 check_invariants (iter);
879 if (gtk_text_iter_is_end (iter))
881 else if (real->segment->type == >k_text_char_type)
883 ensure_byte_offsets (real);
885 return g_utf8_get_char (real->segment->body.chars +
886 real->segment_byte_offset);
890 /* Unicode "unknown character" 0xFFFC */
891 return GTK_TEXT_UNKNOWN_CHAR;
896 * gtk_text_iter_get_slice:
897 * @start: iterator at start of a range
898 * @end: iterator at end of a range
900 * Returns the text in the given range. A "slice" is an array of
901 * characters encoded in UTF-8 format, including the Unicode "unknown"
902 * character 0xFFFC for iterable non-character elements in the buffer,
903 * such as images. Because images are encoded in the slice, byte and
904 * character offsets in the returned array will correspond to byte
905 * offsets in the text buffer. Note that 0xFFFC can occur in normal
906 * text as well, so it is not a reliable indicator that a pixbuf or
907 * widget is in the buffer.
909 * Return value: slice of text from the buffer
912 gtk_text_iter_get_slice (const GtkTextIter *start,
913 const GtkTextIter *end)
915 g_return_val_if_fail (start != NULL, NULL);
916 g_return_val_if_fail (end != NULL, NULL);
918 check_invariants (start);
919 check_invariants (end);
921 return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
925 * gtk_text_iter_get_text:
926 * @start: iterator at start of a range
927 * @end: iterator at end of a range
929 * Returns <emphasis>text</emphasis> in the given range. If the range
930 * contains non-text elements such as images, the character and byte
931 * offsets in the returned string will not correspond to character and
932 * byte offsets in the buffer. If you want offsets to correspond, see
933 * gtk_text_iter_get_slice ().
935 * Return value: array of characters from the buffer
938 gtk_text_iter_get_text (const GtkTextIter *start,
939 const GtkTextIter *end)
941 g_return_val_if_fail (start != NULL, NULL);
942 g_return_val_if_fail (end != NULL, NULL);
944 check_invariants (start);
945 check_invariants (end);
947 return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
951 * gtk_text_iter_get_visible_slice:
952 * @start: iterator at start of range
953 * @end: iterator at end of range
955 * Like gtk_text_iter_get_slice (), but invisible text is not included.
956 * Invisible text is usually invisible because a #GtkTextTag with the
957 * "invisible" attribute turned on has been applied to it.
959 * Return value: slice of text from the buffer
962 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
963 const GtkTextIter *end)
965 g_return_val_if_fail (start != NULL, NULL);
966 g_return_val_if_fail (end != NULL, NULL);
968 check_invariants (start);
969 check_invariants (end);
971 return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
975 * gtk_text_iter_get_visible_text:
976 * @start: iterator at start of range
977 * @end: iterator at end of range
979 * Like gtk_text_iter_get_text (), but invisible text is not included.
980 * Invisible text is usually invisible because a #GtkTextTag with the
981 * "invisible" attribute turned on has been applied to it.
983 * Return value: string containing visible text in the range
986 gtk_text_iter_get_visible_text (const GtkTextIter *start,
987 const GtkTextIter *end)
989 g_return_val_if_fail (start != NULL, NULL);
990 g_return_val_if_fail (end != NULL, NULL);
992 check_invariants (start);
993 check_invariants (end);
995 return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
999 * gtk_text_iter_get_pixbuf:
1000 * @iter: an iterator
1002 * If the location pointed to by @iter contains a pixbuf, the pixbuf
1003 * is returned (with no new reference count added). Otherwise,
1004 * %NULL is returned.
1006 * Return value: the pixbuf at @iter
1009 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1011 GtkTextRealIter *real;
1013 g_return_val_if_fail (iter != NULL, NULL);
1015 real = gtk_text_iter_make_real (iter);
1020 check_invariants (iter);
1022 if (real->segment->type != >k_text_pixbuf_type)
1025 return real->segment->body.pixbuf.pixbuf;
1029 * gtk_text_iter_get_child_anchor:
1030 * @iter: an iterator
1032 * If the location pointed to by @iter contains a child anchor, the
1033 * anchor is returned (with no new reference count added). Otherwise,
1034 * %NULL is returned.
1036 * Return value: the anchor at @iter
1039 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1041 GtkTextRealIter *real;
1043 g_return_val_if_fail (iter != NULL, NULL);
1045 real = gtk_text_iter_make_real (iter);
1050 check_invariants (iter);
1052 if (real->segment->type != >k_text_child_type)
1055 return real->segment->body.child.obj;
1059 * gtk_text_iter_get_marks:
1060 * @iter: an iterator
1062 * Returns a list of all #GtkTextMark at this location. Because marks
1063 * are not iterable (they don't take up any "space" in the buffer,
1064 * they are just marks in between iterable locations), multiple marks
1065 * can exist in the same place. The returned list is not in any
1068 * Return value: list of #GtkTextMark
1071 gtk_text_iter_get_marks (const GtkTextIter *iter)
1073 GtkTextRealIter *real;
1074 GtkTextLineSegment *seg;
1077 g_return_val_if_fail (iter != NULL, NULL);
1079 real = gtk_text_iter_make_real (iter);
1084 check_invariants (iter);
1087 seg = real->any_segment;
1088 while (seg != real->segment)
1090 if (seg->type == >k_text_left_mark_type ||
1091 seg->type == >k_text_right_mark_type)
1092 retval = g_slist_prepend (retval, seg->body.mark.obj);
1097 /* The returned list isn't guaranteed to be in any special order,
1103 * gtk_text_iter_get_toggled_tags:
1104 * @iter: an iterator
1105 * @toggled_on: %TRUE to get toggled-on tags
1107 * Returns a list of #GtkTextTag that are toggled on or off at this
1108 * point. (If @toggled_on is %TRUE, the list contains tags that are
1109 * toggled on.) If a tag is toggled on at @iter, then some non-empty
1110 * range of characters following @iter has that tag applied to it. If
1111 * a tag is toggled off, then some non-empty range following @iter
1112 * does <emphasis>not</emphasis> have the tag applied to it.
1114 * Return value: tags toggled at this point
1117 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
1118 gboolean toggled_on)
1120 GtkTextRealIter *real;
1121 GtkTextLineSegment *seg;
1124 g_return_val_if_fail (iter != NULL, NULL);
1126 real = gtk_text_iter_make_real (iter);
1131 check_invariants (iter);
1134 seg = real->any_segment;
1135 while (seg != real->segment)
1139 if (seg->type == >k_text_toggle_on_type)
1141 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1146 if (seg->type == >k_text_toggle_off_type)
1148 retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1155 /* The returned list isn't guaranteed to be in any special order,
1161 * gtk_text_iter_begins_tag:
1162 * @iter: an iterator
1163 * @tag: a #GtkTextTag, or %NULL
1165 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1166 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1167 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1168 * <emphasis>start</emphasis> of the tagged range;
1169 * gtk_text_iter_has_tag () tells you whether an iterator is
1170 * <emphasis>within</emphasis> a tagged range.
1172 * Return value: whether @iter is the start of a range tagged with @tag
1175 gtk_text_iter_begins_tag (const GtkTextIter *iter,
1178 GtkTextRealIter *real;
1179 GtkTextLineSegment *seg;
1181 g_return_val_if_fail (iter != NULL, FALSE);
1183 real = gtk_text_iter_make_real (iter);
1188 check_invariants (iter);
1190 seg = real->any_segment;
1191 while (seg != real->segment)
1193 if (seg->type == >k_text_toggle_on_type)
1196 seg->body.toggle.info->tag == tag)
1207 * gtk_text_iter_ends_tag:
1208 * @iter: an iterator
1209 * @tag: a #GtkTextTag, or %NULL
1211 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1212 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1213 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1214 * <emphasis>end</emphasis> of the tagged range;
1215 * gtk_text_iter_has_tag () tells you whether an iterator is
1216 * <emphasis>within</emphasis> a tagged range.
1218 * Return value: whether @iter is the end of a range tagged with @tag
1222 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1225 GtkTextRealIter *real;
1226 GtkTextLineSegment *seg;
1228 g_return_val_if_fail (iter != NULL, FALSE);
1230 real = gtk_text_iter_make_real (iter);
1235 check_invariants (iter);
1237 seg = real->any_segment;
1238 while (seg != real->segment)
1240 if (seg->type == >k_text_toggle_off_type)
1243 seg->body.toggle.info->tag == tag)
1254 * gtk_text_iter_toggles_tag:
1255 * @iter: an iterator
1256 * @tag: a #GtkTextTag, or %NULL
1258 * This is equivalent to (gtk_text_iter_begins_tag () ||
1259 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1260 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1262 * Return value: whether @tag is toggled on or off at @iter
1265 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1268 GtkTextRealIter *real;
1269 GtkTextLineSegment *seg;
1271 g_return_val_if_fail (iter != NULL, FALSE);
1273 real = gtk_text_iter_make_real (iter);
1278 check_invariants (iter);
1280 seg = real->any_segment;
1281 while (seg != real->segment)
1283 if ( (seg->type == >k_text_toggle_off_type ||
1284 seg->type == >k_text_toggle_on_type) &&
1286 seg->body.toggle.info->tag == tag) )
1296 * gtk_text_iter_has_tag:
1297 * @iter: an iterator
1298 * @tag: a #GtkTextTag
1300 * Returns %TRUE if @iter is within a range tagged with @tag.
1302 * Return value: whether @iter is tagged with @tag
1305 gtk_text_iter_has_tag (const GtkTextIter *iter,
1308 GtkTextRealIter *real;
1310 g_return_val_if_fail (iter != NULL, FALSE);
1311 g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1313 real = gtk_text_iter_make_surreal (iter);
1318 check_invariants (iter);
1320 if (real->line_byte_offset >= 0)
1322 return _gtk_text_line_byte_has_tag (real->line, real->tree,
1323 real->line_byte_offset, tag);
1327 g_assert (real->line_char_offset >= 0);
1328 return _gtk_text_line_char_has_tag (real->line, real->tree,
1329 real->line_char_offset, tag);
1334 * gtk_text_iter_get_tags:
1335 * @iter: a #GtkTextIter
1337 * Returns a list of tags that apply to @iter, in ascending order of
1338 * priority (highest-priority tags are last). The #GtkTextTag in the
1339 * list don't have a reference added, but you have to free the list
1342 * Return value: list of #GtkTextTag
1345 gtk_text_iter_get_tags (const GtkTextIter *iter)
1352 g_return_val_if_fail (iter != NULL, NULL);
1354 /* Get the tags at this spot */
1355 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1357 /* No tags, use default style */
1358 if (tags == NULL || tag_count == 0)
1366 /* Sort tags in ascending order of priority */
1367 _gtk_text_tag_array_sort (tags, tag_count);
1371 while (i < tag_count)
1373 retval = g_slist_prepend (retval, tags[i]);
1379 /* Return tags in ascending order of priority */
1380 return g_slist_reverse (retval);
1384 * gtk_text_iter_editable:
1385 * @iter: an iterator
1386 * @default_setting: %TRUE if text is editable by default
1388 * Returns whether the character at @iter is within an editable region
1389 * of text. Non-editable text is "locked" and can't be changed by the
1390 * user via #GtkTextView. This function is simply a convenience
1391 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1392 * to this text affect editability, @default_setting will be returned.
1394 * You don't want to use this function to decide whether text can be
1395 * inserted at @iter, because for insertion you don't want to know
1396 * whether the char at @iter is inside an editable range, you want to
1397 * know whether a new character inserted at @iter would be inside an
1398 * editable range. Use gtk_text_iter_can_insert() to handle this
1401 * Return value: whether @iter is inside an editable range
1404 gtk_text_iter_editable (const GtkTextIter *iter,
1405 gboolean default_setting)
1407 GtkTextAttributes *values;
1410 g_return_val_if_fail (iter != NULL, FALSE);
1412 values = gtk_text_attributes_new ();
1414 values->editable = default_setting;
1416 gtk_text_iter_get_attributes (iter, values);
1418 retval = values->editable;
1420 gtk_text_attributes_unref (values);
1426 * gtk_text_iter_can_insert:
1427 * @iter: an iterator
1428 * @default_editability: %TRUE if text is editable by default
1430 * Considering the default editability of the buffer, and tags that
1431 * affect editability, determines whether text inserted at @iter would
1432 * be editable. If text inserted at @iter would be editable then the
1433 * user should be allowed to insert text at @iter.
1434 * gtk_text_buffer_insert_interactive() uses this function to decide
1435 * whether insertions are allowed at a given position.
1437 * Return value: whether text inserted at @iter would be editable
1440 gtk_text_iter_can_insert (const GtkTextIter *iter,
1441 gboolean default_editability)
1443 g_return_val_if_fail (iter != NULL, FALSE);
1445 if (gtk_text_iter_editable (iter, default_editability))
1447 /* If at start/end of buffer, default editability is used */
1448 else if ((gtk_text_iter_is_start (iter) ||
1449 gtk_text_iter_is_end (iter)) &&
1450 default_editability)
1454 /* if iter isn't editable, and the char before iter is,
1455 * then iter is the first char in an editable region
1456 * and thus insertion at iter results in editable text.
1458 GtkTextIter prev = *iter;
1459 gtk_text_iter_backward_char (&prev);
1460 return gtk_text_iter_editable (&prev, default_editability);
1466 * gtk_text_iter_get_language:
1467 * @iter: an iterator
1469 * A convenience wrapper around gtk_text_iter_get_attributes (),
1470 * which returns the language in effect at @iter. If no tags affecting
1471 * language apply to @iter, the return value is identical to that of
1472 * gtk_get_default_language ().
1474 * Return value: language in effect at @iter
1477 gtk_text_iter_get_language (const GtkTextIter *iter)
1479 GtkTextAttributes *values;
1480 PangoLanguage *retval;
1482 values = gtk_text_attributes_new ();
1484 gtk_text_iter_get_attributes (iter, values);
1486 retval = values->language;
1488 gtk_text_attributes_unref (values);
1494 * gtk_text_iter_starts_line:
1495 * @iter: an iterator
1497 * Returns %TRUE if @iter begins a paragraph,
1498 * i.e. if gtk_text_iter_get_line_offset () would return 0.
1499 * However this function is potentially more efficient than
1500 * gtk_text_iter_get_line_offset () because it doesn't have to compute
1501 * the offset, it just has to see whether it's 0.
1503 * Return value: whether @iter begins a line
1506 gtk_text_iter_starts_line (const GtkTextIter *iter)
1508 GtkTextRealIter *real;
1510 g_return_val_if_fail (iter != NULL, FALSE);
1512 real = gtk_text_iter_make_surreal (iter);
1517 check_invariants (iter);
1519 if (real->line_byte_offset >= 0)
1521 return (real->line_byte_offset == 0);
1525 g_assert (real->line_char_offset >= 0);
1526 return (real->line_char_offset == 0);
1531 * gtk_text_iter_ends_line:
1532 * @iter: an iterator
1534 * Returns %TRUE if @iter points to the start of the paragraph
1535 * delimiter characters for a line (delimiters will be either a
1536 * newline, a carriage return, a carriage return followed by a
1537 * newline, or a Unicode paragraph separator character). Note that an
1538 * iterator pointing to the \n of a \r\n pair will not be counted as
1539 * the end of a line, the line ends before the \r. The end iterator is
1540 * considered to be at the end of a line, even though there are no
1541 * paragraph delimiter chars there.
1543 * Return value: whether @iter is at the end of a line
1546 gtk_text_iter_ends_line (const GtkTextIter *iter)
1548 GtkTextRealIter *real;
1551 g_return_val_if_fail (iter != NULL, FALSE);
1553 real = gtk_text_iter_make_real (iter);
1555 check_invariants (iter);
1557 /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1558 * Unicode 3.0; update this if that changes.
1560 #define PARAGRAPH_SEPARATOR 0x2029
1562 wc = gtk_text_iter_get_char (iter);
1564 if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1566 else if (wc == '\n')
1568 /* need to determine if a \r precedes the \n, in which case
1569 * we aren't the end of the line
1571 GtkTextIter tmp = *iter;
1572 if (!gtk_text_iter_backward_char (&tmp))
1575 return gtk_text_iter_get_char (&tmp) != '\r';
1582 * gtk_text_iter_is_end:
1583 * @iter: an iterator
1585 * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1586 * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1587 * the most efficient way to check whether an iterator is the end
1590 * Return value: whether @iter is the end iterator
1593 gtk_text_iter_is_end (const GtkTextIter *iter)
1595 GtkTextRealIter *real;
1597 g_return_val_if_fail (iter != NULL, FALSE);
1599 real = gtk_text_iter_make_surreal (iter);
1604 check_invariants (iter);
1606 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1609 /* Now we need the segments validated */
1610 real = gtk_text_iter_make_real (iter);
1615 return _gtk_text_btree_is_end (real->tree, real->line,
1617 real->segment_byte_offset,
1618 real->segment_char_offset);
1622 * gtk_text_iter_is_start:
1623 * @iter: an iterator
1625 * Returns %TRUE if @iter is the first iterator in the buffer, that is
1626 * if @iter has a character offset of 0.
1628 * Return value: whether @iter is the first in the buffer
1631 gtk_text_iter_is_start (const GtkTextIter *iter)
1633 return gtk_text_iter_get_offset (iter) == 0;
1637 * gtk_text_iter_get_chars_in_line:
1638 * @iter: an iterator
1640 * Returns the number of characters in the line containing @iter,
1641 * including the paragraph delimiters.
1643 * Return value: number of characters in the line
1646 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1648 GtkTextRealIter *real;
1650 GtkTextLineSegment *seg;
1652 g_return_val_if_fail (iter != NULL, FALSE);
1654 real = gtk_text_iter_make_surreal (iter);
1659 check_invariants (iter);
1661 if (real->line_char_offset >= 0)
1663 /* We can start at the segments we've already found. */
1664 count = real->line_char_offset - real->segment_char_offset;
1665 seg = _gtk_text_iter_get_indexable_segment (iter);
1669 /* count whole line. */
1670 seg = real->line->segments;
1677 count += seg->char_count;
1682 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1683 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1689 * gtk_text_iter_get_bytes_in_line:
1690 * @iter: an iterator
1692 * Returns the number of bytes in the line containing @iter,
1693 * including the paragraph delimiters.
1695 * Return value: number of bytes in the line
1698 gtk_text_iter_get_bytes_in_line (const GtkTextIter *iter)
1700 GtkTextRealIter *real;
1702 GtkTextLineSegment *seg;
1704 g_return_val_if_fail (iter != NULL, FALSE);
1706 real = gtk_text_iter_make_surreal (iter);
1711 check_invariants (iter);
1713 if (real->line_byte_offset >= 0)
1715 /* We can start at the segments we've already found. */
1716 count = real->line_byte_offset - real->segment_byte_offset;
1717 seg = _gtk_text_iter_get_indexable_segment (iter);
1721 /* count whole line. */
1722 seg = real->line->segments;
1728 count += seg->byte_count;
1733 if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1734 count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1740 * gtk_text_iter_get_attributes:
1741 * @iter: an iterator
1742 * @values: a #GtkTextAttributes to be filled in
1744 * Computes the effect of any tags applied to this spot in the
1745 * text. The @values parameter should be initialized to the default
1746 * settings you wish to use if no tags are in effect. You'd typically
1747 * obtain the defaults from gtk_text_view_get_default_attributes().
1749 * gtk_text_iter_get_attributes () will modify @values, applying the
1750 * effects of any tags present at @iter. If any tags affected @values,
1751 * the function returns %TRUE.
1753 * Return value: %TRUE if @values was modified
1756 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1757 GtkTextAttributes *values)
1762 /* Get the tags at this spot */
1763 tags = _gtk_text_btree_get_tags (iter, &tag_count);
1765 /* No tags, use default style */
1766 if (tags == NULL || tag_count == 0)
1774 /* Sort tags in ascending order of priority */
1775 _gtk_text_tag_array_sort (tags, tag_count);
1777 _gtk_text_attributes_fill_from_tags (values,
1787 * Increments/decrements
1790 /* The return value of this indicates WHETHER WE MOVED.
1791 * The return value of public functions indicates
1792 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1794 * This function will not change the iterator if
1795 * it's already on the last (end iter) line, i.e. it
1796 * won't move to the end of the last line.
1799 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1801 if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1803 GtkTextLine *new_line;
1805 new_line = _gtk_text_line_next (real->line);
1806 g_assert (new_line);
1807 g_assert (new_line != real->line);
1808 g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1810 real->line = new_line;
1812 real->line_byte_offset = 0;
1813 real->line_char_offset = 0;
1815 real->segment_byte_offset = 0;
1816 real->segment_char_offset = 0;
1818 /* Find first segments in new line */
1819 real->any_segment = real->line->segments;
1820 real->segment = real->any_segment;
1821 while (real->segment->char_count == 0)
1822 real->segment = real->segment->next;
1828 /* There is no way to move forward a line; we were already at
1829 * the line containing the end iterator.
1830 * However we may not be at the end iterator itself.
1838 /* The return value of this indicates WHETHER WE MOVED.
1839 * The return value of public functions indicates
1840 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1843 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1845 GtkTextLine *new_line;
1847 new_line = _gtk_text_line_previous (real->line);
1849 g_assert (new_line != real->line);
1851 if (new_line != NULL)
1853 real->line = new_line;
1855 real->line_byte_offset = 0;
1856 real->line_char_offset = 0;
1858 real->segment_byte_offset = 0;
1859 real->segment_char_offset = 0;
1861 /* Find first segments in new line */
1862 real->any_segment = real->line->segments;
1863 real->segment = real->any_segment;
1864 while (real->segment->char_count == 0)
1865 real->segment = real->segment->next;
1871 /* There is no way to move backward; we were already
1872 at the first line. */
1874 /* We leave real->line as-is */
1876 /* Note that we didn't clamp to the start of the first line. */
1882 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1886 forward_char (GtkTextRealIter *real)
1888 GtkTextIter *iter = (GtkTextIter*)real;
1890 check_invariants ((GtkTextIter*)real);
1892 ensure_char_offsets (real);
1894 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1896 /* Need to move to the next segment; if no next segment,
1897 need to move to next line. */
1898 return _gtk_text_iter_forward_indexable_segment (iter);
1902 /* Just moving within a segment. Keep byte count
1903 up-to-date, if it was already up-to-date. */
1905 g_assert (real->segment->type == >k_text_char_type);
1907 if (real->line_byte_offset >= 0)
1910 const char * start =
1911 real->segment->body.chars + real->segment_byte_offset;
1913 bytes = g_utf8_next_char (start) - start;
1915 real->line_byte_offset += bytes;
1916 real->segment_byte_offset += bytes;
1918 g_assert (real->segment_byte_offset < real->segment->byte_count);
1921 real->line_char_offset += 1;
1922 real->segment_char_offset += 1;
1924 adjust_char_index (real, 1);
1926 g_assert (real->segment_char_offset < real->segment->char_count);
1928 /* We moved into the middle of a segment, so the any_segment
1929 must now be the segment we're in the middle of. */
1930 real->any_segment = real->segment;
1932 check_invariants ((GtkTextIter*)real);
1934 if (gtk_text_iter_is_end ((GtkTextIter*)real))
1942 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1944 /* Need to move to the next segment; if no next segment,
1945 need to move to next line. */
1946 GtkTextLineSegment *seg;
1947 GtkTextLineSegment *any_seg;
1948 GtkTextRealIter *real;
1952 g_return_val_if_fail (iter != NULL, FALSE);
1954 real = gtk_text_iter_make_real (iter);
1959 check_invariants (iter);
1961 if (real->line_char_offset >= 0)
1963 chars_skipped = real->segment->char_count - real->segment_char_offset;
1964 g_assert (chars_skipped > 0);
1969 if (real->line_byte_offset >= 0)
1971 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1972 g_assert (bytes_skipped > 0);
1977 /* Get first segment of any kind */
1978 any_seg = real->segment->next;
1979 /* skip non-indexable segments, if any */
1981 while (seg != NULL && seg->char_count == 0)
1986 real->any_segment = any_seg;
1987 real->segment = seg;
1989 if (real->line_byte_offset >= 0)
1991 g_assert (bytes_skipped > 0);
1992 real->segment_byte_offset = 0;
1993 real->line_byte_offset += bytes_skipped;
1996 if (real->line_char_offset >= 0)
1998 g_assert (chars_skipped > 0);
1999 real->segment_char_offset = 0;
2000 real->line_char_offset += chars_skipped;
2001 adjust_char_index (real, chars_skipped);
2004 check_invariants (iter);
2006 return !gtk_text_iter_is_end (iter);
2010 /* End of the line */
2011 if (forward_line_leaving_caches_unmodified (real))
2013 adjust_line_number (real, 1);
2014 if (real->line_char_offset >= 0)
2015 adjust_char_index (real, chars_skipped);
2017 g_assert (real->line_byte_offset == 0);
2018 g_assert (real->line_char_offset == 0);
2019 g_assert (real->segment_byte_offset == 0);
2020 g_assert (real->segment_char_offset == 0);
2021 g_assert (gtk_text_iter_starts_line (iter));
2023 check_invariants (iter);
2025 return !gtk_text_iter_is_end (iter);
2029 /* End of buffer, but iter is still at start of last segment,
2030 * not at the end iterator. We put it on the end iterator.
2033 check_invariants (iter);
2035 g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2036 g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2038 gtk_text_iter_forward_to_line_end (iter);
2040 g_assert (gtk_text_iter_is_end (iter));
2048 at_last_indexable_segment (GtkTextRealIter *real)
2050 GtkTextLineSegment *seg;
2052 /* Return TRUE if there are no indexable segments after
2056 seg = real->segment->next;
2059 if (seg->char_count > 0)
2066 /* Goes back to the start of the next segment, even if
2067 * we're not at the start of the current segment (always
2068 * ends up on a different segment if it returns TRUE)
2071 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2073 /* Move to the start of the previous segment; if no previous
2074 * segment, to the last segment in the previous line. This is
2075 * inherently a bit inefficient due to the singly-linked list and
2076 * tree nodes, but we can't afford the RAM for doubly-linked.
2078 GtkTextRealIter *real;
2079 GtkTextLineSegment *seg;
2080 GtkTextLineSegment *any_seg;
2081 GtkTextLineSegment *prev_seg;
2082 GtkTextLineSegment *prev_any_seg;
2086 g_return_val_if_fail (iter != NULL, FALSE);
2088 real = gtk_text_iter_make_real (iter);
2093 check_invariants (iter);
2095 /* Find first segments in line */
2096 any_seg = real->line->segments;
2098 while (seg->char_count == 0)
2101 if (seg == real->segment)
2103 /* Could probably do this case faster by hand-coding the
2107 /* We were already at the start of a line;
2108 * go back to the previous line.
2110 if (gtk_text_iter_backward_line (iter))
2112 /* Go forward to last indexable segment in line. */
2113 while (!at_last_indexable_segment (real))
2114 _gtk_text_iter_forward_indexable_segment (iter);
2116 check_invariants (iter);
2121 return FALSE; /* We were at the start of the first line. */
2124 /* We must be in the middle of a line; so find the indexable
2125 * segment just before our current segment.
2127 g_assert (seg != real->segment);
2131 prev_any_seg = any_seg;
2133 any_seg = seg->next;
2135 while (seg->char_count == 0)
2138 while (seg != real->segment);
2140 g_assert (prev_seg != NULL);
2141 g_assert (prev_any_seg != NULL);
2142 g_assert (prev_seg->char_count > 0);
2144 /* We skipped the entire previous segment, plus any
2145 * chars we were into the current segment.
2147 if (real->segment_byte_offset >= 0)
2148 bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2152 if (real->segment_char_offset >= 0)
2153 chars_skipped = prev_seg->char_count + real->segment_char_offset;
2157 real->segment = prev_seg;
2158 real->any_segment = prev_any_seg;
2159 real->segment_byte_offset = 0;
2160 real->segment_char_offset = 0;
2162 if (bytes_skipped >= 0)
2164 if (real->line_byte_offset >= 0)
2166 real->line_byte_offset -= bytes_skipped;
2167 g_assert (real->line_byte_offset >= 0);
2171 real->line_byte_offset = -1;
2173 if (chars_skipped >= 0)
2175 if (real->line_char_offset >= 0)
2177 real->line_char_offset -= chars_skipped;
2178 g_assert (real->line_char_offset >= 0);
2181 if (real->cached_char_index >= 0)
2183 real->cached_char_index -= chars_skipped;
2184 g_assert (real->cached_char_index >= 0);
2189 real->line_char_offset = -1;
2190 real->cached_char_index = -1;
2193 /* line number is unchanged. */
2195 check_invariants (iter);
2201 * gtk_text_iter_forward_char:
2202 * @iter: an iterator
2204 * Moves @iter forward by one character offset. Note that images
2205 * embedded in the buffer occupy 1 character slot, so
2206 * gtk_text_iter_forward_char () may actually move onto an image instead
2207 * of a character, if you have images in your buffer. If @iter is the
2208 * end iterator or one character before it, @iter will now point at
2209 * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2210 * convenience when writing loops.
2212 * Return value: whether @iter moved and is dereferenceable
2215 gtk_text_iter_forward_char (GtkTextIter *iter)
2217 GtkTextRealIter *real;
2219 g_return_val_if_fail (iter != NULL, FALSE);
2221 real = gtk_text_iter_make_real (iter);
2227 check_invariants (iter);
2228 return forward_char (real);
2233 * gtk_text_iter_backward_char:
2234 * @iter: an iterator
2236 * Moves backward by one character offset. Returns %TRUE if movement
2237 * was possible; if @iter was the first in the buffer (character
2238 * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2241 * Return value: whether movement was possible
2244 gtk_text_iter_backward_char (GtkTextIter *iter)
2246 g_return_val_if_fail (iter != NULL, FALSE);
2248 check_invariants (iter);
2250 return gtk_text_iter_backward_chars (iter, 1);
2254 Definitely we should try to linear scan as often as possible for
2255 movement within a single line, because we can't use the BTree to
2256 speed within-line searches up; for movement between lines, we would
2257 like to avoid the linear scan probably.
2259 Instead of using this constant, it might be nice to cache the line
2260 length in the iterator and linear scan if motion is within a single
2263 I guess you'd have to profile the various approaches.
2265 #define MAX_LINEAR_SCAN 150
2269 * gtk_text_iter_forward_chars:
2270 * @iter: an iterator
2271 * @count: number of characters to move, may be negative
2273 * Moves @count characters if possible (if @count would move past the
2274 * start or end of the buffer, moves to the start or end of the
2275 * buffer). The return value indicates whether the new position of
2276 * @iter is different from its original position, and dereferenceable
2277 * (the last iterator in the buffer is not dereferenceable). If @count
2278 * is 0, the function does nothing and returns %FALSE.
2280 * Return value: whether @iter moved and is dereferenceable
2283 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2285 GtkTextRealIter *real;
2287 g_return_val_if_fail (iter != NULL, FALSE);
2289 FIX_OVERFLOWS (count);
2291 real = gtk_text_iter_make_real (iter);
2295 else if (count == 0)
2298 return gtk_text_iter_backward_chars (iter, 0 - count);
2299 else if (count < MAX_LINEAR_SCAN)
2301 check_invariants (iter);
2305 if (!forward_char (real))
2310 return forward_char (real);
2314 gint current_char_index;
2315 gint new_char_index;
2317 check_invariants (iter);
2319 current_char_index = gtk_text_iter_get_offset (iter);
2321 if (current_char_index == _gtk_text_btree_char_count (real->tree))
2322 return FALSE; /* can't move forward */
2324 new_char_index = current_char_index + count;
2325 gtk_text_iter_set_offset (iter, new_char_index);
2327 check_invariants (iter);
2329 /* Return FALSE if we're on the non-dereferenceable end
2332 if (gtk_text_iter_is_end (iter))
2340 * gtk_text_iter_backward_chars:
2341 * @iter: an iterator
2342 * @count: number of characters to move
2344 * Moves @count characters backward, if possible (if @count would move
2345 * past the start or end of the buffer, moves to the start or end of
2346 * the buffer). The return value indicates whether the iterator moved
2347 * onto a dereferenceable position; if the iterator didn't move, or
2348 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2349 * the function does nothing and returns %FALSE.
2351 * Return value: whether @iter moved and is dereferenceable
2355 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2357 GtkTextRealIter *real;
2359 g_return_val_if_fail (iter != NULL, FALSE);
2361 FIX_OVERFLOWS (count);
2363 real = gtk_text_iter_make_real (iter);
2367 else if (count == 0)
2370 return gtk_text_iter_forward_chars (iter, 0 - count);
2372 ensure_char_offsets (real);
2373 check_invariants (iter);
2375 /* <, not <=, because if count == segment_char_offset
2376 * we're going to the front of the segment and the any_segment
2379 if (count < real->segment_char_offset)
2381 /* Optimize the within-segment case */
2382 g_assert (real->segment->char_count > 0);
2383 g_assert (real->segment->type == >k_text_char_type);
2385 real->segment_char_offset -= count;
2386 g_assert (real->segment_char_offset >= 0);
2388 if (real->line_byte_offset >= 0)
2390 gint new_byte_offset;
2393 new_byte_offset = 0;
2395 while (i < real->segment_char_offset)
2397 const char * start = real->segment->body.chars + new_byte_offset;
2398 new_byte_offset += g_utf8_next_char (start) - start;
2403 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2404 real->segment_byte_offset = new_byte_offset;
2407 real->line_char_offset -= count;
2409 adjust_char_index (real, 0 - count);
2411 check_invariants (iter);
2417 /* We need to go back into previous segments. For now,
2418 * just keep this really simple. FIXME
2419 * use backward_indexable_segment.
2421 if (TRUE || count > MAX_LINEAR_SCAN)
2423 gint current_char_index;
2424 gint new_char_index;
2426 current_char_index = gtk_text_iter_get_offset (iter);
2428 if (current_char_index == 0)
2429 return FALSE; /* can't move backward */
2431 new_char_index = current_char_index - count;
2432 if (new_char_index < 0)
2435 gtk_text_iter_set_offset (iter, new_char_index);
2437 check_invariants (iter);
2443 /* FIXME backward_indexable_segment here */
2452 /* These two can't be implemented efficiently (always have to use
2453 * a linear scan, since that's the only way to find all the non-text
2458 * gtk_text_iter_forward_text_chars:
2459 * @iter: a #GtkTextIter
2460 * @count: number of chars to move
2462 * Moves forward by @count text characters (pixbufs, widgets,
2463 * etc. do not count as characters for this). Equivalent to moving
2464 * through the results of gtk_text_iter_get_text (), rather than
2465 * gtk_text_iter_get_slice ().
2467 * Return value: whether @iter moved and is dereferenceable
2470 gtk_text_iter_forward_text_chars (GtkTextIter *iter,
2479 * gtk_text_iter_forward_text_chars:
2480 * @iter: a #GtkTextIter
2481 * @count: number of chars to move
2483 * Moves backward by @count text characters (pixbufs, widgets,
2484 * etc. do not count as characters for this). Equivalent to moving
2485 * through the results of gtk_text_iter_get_text (), rather than
2486 * gtk_text_iter_get_slice ().
2488 * Return value: whether @iter moved and is dereferenceable
2491 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2500 * gtk_text_iter_forward_line:
2501 * @iter: an iterator
2503 * Moves @iter to the start of the next line. Returns %TRUE if there
2504 * was a next line to move to, and %FALSE if @iter was simply moved to
2505 * the end of the buffer and is now not dereferenceable, or if @iter was
2506 * already at the end of the buffer.
2508 * Return value: whether @iter can be dereferenced
2511 gtk_text_iter_forward_line (GtkTextIter *iter)
2513 GtkTextRealIter *real;
2515 g_return_val_if_fail (iter != NULL, FALSE);
2517 real = gtk_text_iter_make_real (iter);
2522 check_invariants (iter);
2524 if (forward_line_leaving_caches_unmodified (real))
2526 invalidate_char_index (real);
2527 adjust_line_number (real, 1);
2529 check_invariants (iter);
2531 if (gtk_text_iter_is_end (iter))
2538 /* On the last line, move to end of it */
2540 if (!gtk_text_iter_is_end (iter))
2541 gtk_text_iter_forward_to_end (iter);
2543 check_invariants (iter);
2549 * gtk_text_iter_backward_line:
2550 * @iter: an iterator
2552 * Moves @iter to the start of the previous line. Returns %TRUE if
2553 * @iter could be moved; i.e. if @iter was at character offset 0, this
2554 * function returns %FALSE. Therefore if @iter was already on line 0,
2555 * but not at the start of the line, @iter is snapped to the start of
2556 * the line and the function returns %TRUE. (Note that this implies that
2557 * in a loop calling this function, the line number may not change on
2558 * every iteration, if your first iteration is on line 0.)
2560 * Return value: whether @iter moved
2563 gtk_text_iter_backward_line (GtkTextIter *iter)
2565 GtkTextLine *new_line;
2566 GtkTextRealIter *real;
2567 gboolean offset_will_change;
2570 g_return_val_if_fail (iter != NULL, FALSE);
2572 real = gtk_text_iter_make_real (iter);
2577 check_invariants (iter);
2579 new_line = _gtk_text_line_previous (real->line);
2581 offset_will_change = FALSE;
2582 if (real->line_char_offset > 0)
2583 offset_will_change = TRUE;
2585 if (new_line != NULL)
2587 real->line = new_line;
2589 adjust_line_number (real, -1);
2593 if (!offset_will_change)
2597 invalidate_char_index (real);
2599 real->line_byte_offset = 0;
2600 real->line_char_offset = 0;
2602 real->segment_byte_offset = 0;
2603 real->segment_char_offset = 0;
2605 /* Find first segment in line */
2606 real->any_segment = real->line->segments;
2607 real->segment = _gtk_text_line_byte_to_segment (real->line,
2610 g_assert (offset == 0);
2612 /* Note that if we are on the first line, we snap to the start of
2613 * the first line and return TRUE, so TRUE means the iterator
2614 * changed, not that the line changed; this is maybe a bit
2615 * weird. I'm not sure there's an obvious right thing to do though.
2618 check_invariants (iter);
2625 * gtk_text_iter_forward_lines:
2626 * @iter: a #GtkTextIter
2627 * @count: number of lines to move forward
2629 * Moves @count lines forward, if possible (if @count would move
2630 * past the start or end of the buffer, moves to the start or end of
2631 * the buffer). The return value indicates whether the iterator moved
2632 * onto a dereferenceable position; if the iterator didn't move, or
2633 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2634 * the function does nothing and returns %FALSE. If @count is negative,
2635 * moves backward by 0 - @count lines.
2637 * Return value: whether @iter moved and is dereferenceable
2640 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2642 FIX_OVERFLOWS (count);
2645 return gtk_text_iter_backward_lines (iter, 0 - count);
2646 else if (count == 0)
2648 else if (count == 1)
2650 check_invariants (iter);
2651 return gtk_text_iter_forward_line (iter);
2657 if (gtk_text_iter_is_end (iter))
2660 old_line = gtk_text_iter_get_line (iter);
2662 gtk_text_iter_set_line (iter, old_line + count);
2664 if ((gtk_text_iter_get_line (iter) - old_line) < count)
2666 /* count went past the last line, so move to end of last line */
2667 if (!gtk_text_iter_is_end (iter))
2668 gtk_text_iter_forward_to_end (iter);
2671 return !gtk_text_iter_is_end (iter);
2676 * gtk_text_iter_backward_lines:
2677 * @iter: a #GtkTextIter
2678 * @count: number of lines to move backward
2680 * Moves @count lines backward, if possible (if @count would move
2681 * past the start or end of the buffer, moves to the start or end of
2682 * the buffer). The return value indicates whether the iterator moved
2683 * onto a dereferenceable position; if the iterator didn't move, or
2684 * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2685 * the function does nothing and returns %FALSE. If @count is negative,
2686 * moves forward by 0 - @count lines.
2688 * Return value: whether @iter moved and is dereferenceable
2691 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2693 FIX_OVERFLOWS (count);
2696 return gtk_text_iter_forward_lines (iter, 0 - count);
2697 else if (count == 0)
2699 else if (count == 1)
2701 return gtk_text_iter_backward_line (iter);
2707 old_line = gtk_text_iter_get_line (iter);
2709 gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2711 return (gtk_text_iter_get_line (iter) != old_line);
2715 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2720 gboolean already_moved_initially);
2722 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2730 find_word_end_func (const PangoLogAttr *attrs,
2735 gboolean already_moved_initially)
2737 if (!already_moved_initially)
2740 /* Find end of next word */
2741 while (offset < min_offset + len &&
2742 !attrs[offset].is_word_end)
2745 *found_offset = offset;
2747 return offset < min_offset + len;
2751 is_word_end_func (const PangoLogAttr *attrs,
2756 return attrs[offset].is_word_end;
2760 find_word_start_func (const PangoLogAttr *attrs,
2765 gboolean already_moved_initially)
2767 if (!already_moved_initially)
2770 /* Find start of prev word */
2771 while (offset >= min_offset &&
2772 !attrs[offset].is_word_start)
2775 *found_offset = offset;
2777 return offset >= min_offset;
2781 is_word_start_func (const PangoLogAttr *attrs,
2786 return attrs[offset].is_word_start;
2790 inside_word_func (const PangoLogAttr *attrs,
2795 /* Find next word start or end */
2796 while (offset >= min_offset &&
2797 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2800 return attrs[offset].is_word_start;
2803 /* Sentence funcs */
2806 find_sentence_end_func (const PangoLogAttr *attrs,
2811 gboolean already_moved_initially)
2813 if (!already_moved_initially)
2816 /* Find end of next sentence */
2817 while (offset < min_offset + len &&
2818 !attrs[offset].is_sentence_end)
2821 *found_offset = offset;
2823 return offset < min_offset + len;
2827 is_sentence_end_func (const PangoLogAttr *attrs,
2832 return attrs[offset].is_sentence_end;
2836 find_sentence_start_func (const PangoLogAttr *attrs,
2841 gboolean already_moved_initially)
2843 if (!already_moved_initially)
2846 /* Find start of prev sentence */
2847 while (offset >= min_offset &&
2848 !attrs[offset].is_sentence_start)
2851 *found_offset = offset;
2853 return offset >= min_offset;
2857 is_sentence_start_func (const PangoLogAttr *attrs,
2862 return attrs[offset].is_sentence_start;
2866 inside_sentence_func (const PangoLogAttr *attrs,
2871 /* Find next sentence start or end */
2872 while (offset >= min_offset &&
2873 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2876 return attrs[offset].is_sentence_start;
2880 test_log_attrs (const GtkTextIter *iter,
2881 TestLogAttrFunc func)
2884 const PangoLogAttr *attrs;
2886 gboolean result = FALSE;
2888 g_return_val_if_fail (iter != NULL, FALSE);
2890 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2893 offset = gtk_text_iter_get_line_offset (iter);
2895 /* char_len may be 0 and attrs will be NULL if so, if
2896 * iter is the end iter and the last line is empty.
2898 * offset may be equal to char_len, since attrs contains an entry
2899 * for one past the end
2902 if (attrs && offset <= char_len)
2903 result = (* func) (attrs, offset, 0, char_len);
2909 find_line_log_attrs (const GtkTextIter *iter,
2910 FindLogAttrFunc func,
2912 gboolean already_moved_initially)
2915 const PangoLogAttr *attrs;
2917 gboolean result = FALSE;
2919 g_return_val_if_fail (iter != NULL, FALSE);
2921 attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2924 offset = gtk_text_iter_get_line_offset (iter);
2926 /* char_len may be 0 and attrs will be NULL if so, if
2927 * iter is the end iter and the last line is empty
2931 result = (* func) (attrs, offset, 0, char_len, found_offset,
2932 already_moved_initially);
2937 /* FIXME this function is very, very gratuitously slow */
2939 find_by_log_attrs (GtkTextIter *iter,
2940 FindLogAttrFunc func,
2942 gboolean already_moved_initially)
2946 gboolean found = FALSE;
2948 g_return_val_if_fail (iter != NULL, FALSE);
2952 found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2958 if (gtk_text_iter_forward_line (iter))
2959 return find_by_log_attrs (iter, func, forward,
2966 /* go to end of previous line. need to check that
2967 * line is > 0 because backward_line snaps to start of
2968 * line 0 if it's on line 0
2970 if (gtk_text_iter_get_line (iter) > 0 &&
2971 gtk_text_iter_backward_line (iter))
2973 if (!gtk_text_iter_ends_line (iter))
2974 gtk_text_iter_forward_to_line_end (iter);
2976 return find_by_log_attrs (iter, func, forward,
2985 gtk_text_iter_set_line_offset (iter, offset);
2988 (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2989 !gtk_text_iter_is_end (iter);
2994 * gtk_text_iter_forward_word_end:
2995 * @iter: a #GtkTextIter
2997 * Moves forward to the next word end. (If @iter is currently on a
2998 * word end, moves forward to the next one after that.) Word breaks
2999 * are determined by Pango and should be correct for nearly any
3000 * language (if not, the correct fix would be to the Pango word break
3003 * Return value: %TRUE if @iter moved and is not the end iterator
3006 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3008 return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3012 * gtk_text_iter_backward_word_start:
3013 * @iter: a #GtkTextIter
3015 * Moves backward to the previous word start. (If @iter is currently on a
3016 * word start, moves backward to the next one after that.) Word breaks
3017 * are determined by Pango and should be correct for nearly any
3018 * language (if not, the correct fix would be to the Pango word break
3021 * Return value: %TRUE if @iter moved and is not the end iterator
3024 gtk_text_iter_backward_word_start (GtkTextIter *iter)
3026 return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3029 /* FIXME a loop around a truly slow function means
3030 * a truly spectacularly slow function.
3034 * gtk_text_iter_forward_word_ends:
3035 * @iter: a #GtkTextIter
3036 * @count: number of times to move
3038 * Calls gtk_text_iter_forward_word_end() up to @count times.
3040 * Return value: %TRUE if @iter moved and is not the end iterator
3043 gtk_text_iter_forward_word_ends (GtkTextIter *iter,
3046 g_return_val_if_fail (iter != NULL, FALSE);
3048 FIX_OVERFLOWS (count);
3054 return gtk_text_iter_backward_word_starts (iter, -count);
3056 if (!gtk_text_iter_forward_word_end (iter))
3062 if (!gtk_text_iter_forward_word_end (iter))
3067 return !gtk_text_iter_is_end (iter);
3071 * gtk_text_iter_backward_word_starts
3072 * @iter: a #GtkTextIter
3073 * @count: number of times to move
3075 * Calls gtk_text_iter_backward_word_start() up to @count times.
3077 * Return value: %TRUE if @iter moved and is not the end iterator
3080 gtk_text_iter_backward_word_starts (GtkTextIter *iter,
3083 g_return_val_if_fail (iter != NULL, FALSE);
3085 FIX_OVERFLOWS (count);
3088 return gtk_text_iter_forward_word_ends (iter, -count);
3090 if (!gtk_text_iter_backward_word_start (iter))
3096 if (!gtk_text_iter_backward_word_start (iter))
3101 return !gtk_text_iter_is_end (iter);
3105 * gtk_text_iter_starts_word:
3106 * @iter: a #GtkTextIter
3108 * Determines whether @iter begins a natural-language word. Word
3109 * breaks are determined by Pango and should be correct for nearly any
3110 * language (if not, the correct fix would be to the Pango word break
3113 * Return value: %TRUE if @iter is at the start of a word
3116 gtk_text_iter_starts_word (const GtkTextIter *iter)
3118 return test_log_attrs (iter, is_word_start_func);
3122 * gtk_text_iter_ends_word:
3123 * @iter: a #GtkTextIter
3125 * Determines whether @iter ends a natural-language word. Word breaks
3126 * are determined by Pango and should be correct for nearly any
3127 * language (if not, the correct fix would be to the Pango word break
3130 * Return value: %TRUE if @iter is at the end of a word
3133 gtk_text_iter_ends_word (const GtkTextIter *iter)
3135 return test_log_attrs (iter, is_word_end_func);
3139 * gtk_text_iter_inside_word:
3140 * @iter: a #GtkTextIter
3142 * Determines whether @iter is inside a natural-language word (as
3143 * opposed to say inside some whitespace). Word breaks are determined
3144 * by Pango and should be correct for nearly any language (if not, the
3145 * correct fix would be to the Pango word break algorithms).
3147 * Return value: %TRUE if @iter is inside a word
3150 gtk_text_iter_inside_word (const GtkTextIter *iter)
3152 return test_log_attrs (iter, inside_word_func);
3156 * gtk_text_iter_starts_sentence:
3157 * @iter: a #GtkTextIter
3159 * Determines whether @iter begins a sentence. Sentence boundaries are
3160 * determined by Pango and should be correct for nearly any language
3161 * (if not, the correct fix would be to the Pango text boundary
3164 * Return value: %TRUE if @iter is at the start of a sentence.
3167 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3169 return test_log_attrs (iter, is_sentence_start_func);
3173 * gtk_text_iter_ends_sentence:
3174 * @iter: a #GtkTextIter
3176 * Determines whether @iter ends a sentence. Sentence boundaries are
3177 * determined by Pango and should be correct for nearly any language
3178 * (if not, the correct fix would be to the Pango text boundary
3181 * Return value: %TRUE if @iter is at the end of a sentence.
3184 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3186 return test_log_attrs (iter, is_sentence_end_func);
3190 * gtk_text_iter_inside_sentence:
3191 * @iter: a #GtkTextIter
3193 * Determines whether @iter is inside a sentence (as opposed to in
3194 * between two sentences, e.g. after a period and before the first
3195 * letter of the next sentence). Sentence boundaries are determined
3196 * by Pango and should be correct for nearly any language (if not, the
3197 * correct fix would be to the Pango text boundary algorithms).
3199 * Return value: %TRUE if @iter is inside a sentence.
3202 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3204 return test_log_attrs (iter, inside_sentence_func);
3208 * gtk_text_iter_forward_sentence_end:
3209 * @iter: a #GtkTextIter
3211 * Moves forward to the next sentence end. (If @iter is at the end of
3212 * a sentence, moves to the next end of sentence.) Sentence
3213 * boundaries are determined by Pango and should be correct for nearly
3214 * any language (if not, the correct fix would be to the Pango text
3215 * boundary algorithms).
3217 * Return value: %TRUE if @iter moved and is not the end iterator
3220 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3222 return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3226 * gtk_text_iter_backward_sentence_start:
3227 * @iter: a #GtkTextIter
3229 * Moves backward to the previous sentence start; if @iter is already at
3230 * the start of a sentence, moves backward to the next one. Sentence
3231 * boundaries are determined by Pango and should be correct for nearly
3232 * any language (if not, the correct fix would be to the Pango text
3233 * boundary algorithms).
3235 * Return value: %TRUE if @iter moved and is not the end iterator
3238 gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
3240 return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3243 /* FIXME a loop around a truly slow function means
3244 * a truly spectacularly slow function.
3247 * gtk_text_iter_forward_sentence_ends:
3248 * @iter: a #GtkTextIter
3249 * @count: number of sentences to move
3251 * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3252 * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3253 * negative, moves backward instead of forward.
3255 * Return value: %TRUE if @iter moved and is not the end iterator
3258 gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
3261 g_return_val_if_fail (iter != NULL, FALSE);
3267 return gtk_text_iter_backward_sentence_starts (iter, -count);
3269 if (!gtk_text_iter_forward_sentence_end (iter))
3275 if (!gtk_text_iter_forward_sentence_end (iter))
3280 return !gtk_text_iter_is_end (iter);
3284 * gtk_text_iter_backward_sentence_starts:
3285 * @iter: a #GtkTextIter
3286 * @count: number of sentences to move
3288 * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3289 * or until it returns %FALSE. If @count is negative, moves forward
3290 * instead of backward.
3292 * Return value: %TRUE if @iter moved and is not the end iterator
3295 gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
3298 g_return_val_if_fail (iter != NULL, FALSE);
3301 return gtk_text_iter_forward_sentence_ends (iter, -count);
3303 if (!gtk_text_iter_backward_sentence_start (iter))
3309 if (!gtk_text_iter_backward_sentence_start (iter))
3314 return !gtk_text_iter_is_end (iter);
3318 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3323 gboolean already_moved_initially)
3325 if (!already_moved_initially)
3328 while (offset < (min_offset + len) &&
3329 !attrs[offset].is_cursor_position)
3332 *found_offset = offset;
3334 return offset < (min_offset + len);
3338 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3343 gboolean already_moved_initially)
3345 if (!already_moved_initially)
3348 while (offset > min_offset &&
3349 !attrs[offset].is_cursor_position)
3352 *found_offset = offset;
3354 return offset >= min_offset;
3358 is_cursor_pos_func (const PangoLogAttr *attrs,
3363 return attrs[offset].is_cursor_position;
3367 * gtk_text_iter_forward_cursor_position:
3368 * @iter: a #GtkTextIter
3370 * Moves @iter forward by a single cursor position. Cursor positions
3371 * are (unsurprisingly) positions where the cursor can appear. Perhaps
3372 * surprisingly, there may not be a cursor position between all
3373 * characters. The most common example for European languages would be
3374 * a carriage return/newline sequence. For some Unicode characters,
3375 * the equivalent of say the letter "a" with an accent mark will be
3376 * represented as two characters, first the letter then a "combining
3377 * mark" that causes the accent to be rendered; so the cursor can't go
3378 * between those two characters. See also the #PangoLogAttr structure and
3379 * pango_break() function.
3381 * Return value: %TRUE if we moved and the new position is dereferenceable
3384 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3386 return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3390 * gtk_text_iter_backward_cursor_position:
3391 * @iter: a #GtkTextIter
3393 * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3395 * Return value: %TRUE if we moved and the new position is dereferenceable
3398 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3400 return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3404 * gtk_text_iter_forward_cursor_positions:
3405 * @iter: a #GtkTextIter
3406 * @count: number of positions to move
3408 * Moves up to @count cursor positions. See
3409 * gtk_text_iter_forward_cursor_position() for details.
3411 * Return value: %TRUE if we moved and the new position is dereferenceable
3414 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3417 g_return_val_if_fail (iter != NULL, FALSE);
3419 FIX_OVERFLOWS (count);
3425 return gtk_text_iter_backward_cursor_positions (iter, -count);
3427 if (!gtk_text_iter_forward_cursor_position (iter))
3433 if (!gtk_text_iter_forward_cursor_position (iter))
3438 return !gtk_text_iter_is_end (iter);
3442 * gtk_text_iter_backward_cursor_positions:
3443 * @iter: a #GtkTextIter
3444 * @count: number of positions to move
3446 * Moves up to @count cursor positions. See
3447 * gtk_text_iter_forward_cursor_position() for details.
3449 * Return value: %TRUE if we moved and the new position is dereferenceable
3452 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3455 g_return_val_if_fail (iter != NULL, FALSE);
3457 FIX_OVERFLOWS (count);
3463 return gtk_text_iter_forward_cursor_positions (iter, -count);
3465 if (!gtk_text_iter_backward_cursor_position (iter))
3471 if (!gtk_text_iter_backward_cursor_position (iter))
3476 return !gtk_text_iter_is_end (iter);
3480 * gtk_text_iter_is_cursor_position:
3481 * @iter: a #GtkTextIter
3483 * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3484 * pango_break() for details on what a cursor position is.
3486 * Return value: %TRUE if the cursor can be placed at @iter
3489 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3491 return test_log_attrs (iter, is_cursor_pos_func);
3495 * gtk_text_iter_set_line_offset:
3496 * @iter: a #GtkTextIter
3497 * @char_on_line: a character offset relative to the start of @iter's current line
3499 * Moves @iter within a line, to a new <emphasis>character</emphasis>
3500 * (not byte) offset. The given character offset must be less than or
3501 * equal to the number of characters in the line; if equal, @iter
3502 * moves to the start of the next line. See
3503 * gtk_text_iter_set_line_index() if you have a byte index rather than
3504 * a character offset.
3508 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3511 GtkTextRealIter *real;
3514 g_return_if_fail (iter != NULL);
3516 real = gtk_text_iter_make_surreal (iter);
3521 check_invariants (iter);
3523 chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3525 g_return_if_fail (char_on_line <= chars_in_line);
3527 if (char_on_line < chars_in_line)
3528 iter_set_from_char_offset (real, real->line, char_on_line);
3530 gtk_text_iter_forward_line (iter); /* set to start of next line */
3532 check_invariants (iter);
3536 * gtk_text_iter_set_line_index:
3537 * @iter: a #GtkTextIter
3538 * @byte_on_line: a byte index relative to the start of @iter's current line
3540 * Same as gtk_text_iter_set_line_offset(), but works with a
3541 * <emphasis>byte</emphasis> index. The given byte index must be at
3542 * the start of a character, it can't be in the middle of a UTF-8
3543 * encoded character.
3547 gtk_text_iter_set_line_index (GtkTextIter *iter,
3550 GtkTextRealIter *real;
3553 g_return_if_fail (iter != NULL);
3555 real = gtk_text_iter_make_surreal (iter);
3560 check_invariants (iter);
3562 bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3564 g_return_if_fail (byte_on_line <= bytes_in_line);
3566 if (byte_on_line < bytes_in_line)
3567 iter_set_from_byte_offset (real, real->line, byte_on_line);
3569 gtk_text_iter_forward_line (iter);
3571 if (real->segment->type == >k_text_char_type &&
3572 (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3573 g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3574 "character; this will crash the text buffer. "
3575 "Byte indexes must refer to the start of a character.",
3576 G_STRLOC, byte_on_line);
3578 check_invariants (iter);
3583 * gtk_text_iter_set_visible_line_offset:
3584 * @iter: a #GtkTextIter
3585 * @char_on_line: a character offset
3587 * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3588 * characters, i.e. text with a tag making it invisible is not
3589 * counted in the offset.
3592 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3595 gint chars_seen = 0;
3598 g_return_if_fail (iter != NULL);
3602 /* For now we use a ludicrously slow implementation */
3603 while (chars_seen < char_on_line)
3605 if (!_gtk_text_btree_char_is_invisible (&pos))
3608 if (!gtk_text_iter_forward_char (&pos))
3611 if (chars_seen == char_on_line)
3615 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3618 gtk_text_iter_forward_line (iter);
3622 bytes_in_char (GtkTextIter *iter)
3624 return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3628 * gtk_text_iter_set_visible_line_index:
3629 * @iter: a #GtkTextIter
3630 * @byte_on_line: a byte index
3632 * Like gtk_text_iter_set_line_index(), but the index is in visible
3633 * bytes, i.e. text with a tag making it invisible is not counted
3637 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3640 gint bytes_seen = 0;
3643 g_return_if_fail (iter != NULL);
3647 /* For now we use a ludicrously slow implementation */
3648 while (bytes_seen < byte_on_line)
3650 if (!_gtk_text_btree_char_is_invisible (&pos))
3651 bytes_seen += bytes_in_char (&pos);
3653 if (!gtk_text_iter_forward_char (&pos))
3656 if (bytes_seen >= byte_on_line)
3660 if (bytes_seen > byte_on_line)
3661 g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3662 "character; this will crash the text buffer. "
3663 "Byte indexes must refer to the start of a character.",
3664 G_STRLOC, byte_on_line);
3666 if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3669 gtk_text_iter_forward_line (iter);
3673 * gtk_text_iter_set_line:
3674 * @iter: a #GtkTextIter
3675 * @line_number: line number (counted from 0)
3677 * Moves iterator @iter to the start of the line @line_number. If
3678 * @line_number is negative or larger than the number of lines in the
3679 * buffer, moves @iter to the start of the last line in the buffer.
3683 gtk_text_iter_set_line (GtkTextIter *iter,
3688 GtkTextRealIter *real;
3690 g_return_if_fail (iter != NULL);
3692 real = gtk_text_iter_make_surreal (iter);
3697 check_invariants (iter);
3699 line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3701 iter_set_from_char_offset (real, line, 0);
3703 /* We might as well cache this, since we know it. */
3704 real->cached_line_number = real_line;
3706 check_invariants (iter);
3710 * gtk_text_iter_set_offset:
3711 * @iter: a #GtkTextIter
3712 * @char_offset: a character number
3714 * Sets @iter to point to @char_offset. @char_offset counts from the start
3715 * of the entire text buffer, starting with 0.
3718 gtk_text_iter_set_offset (GtkTextIter *iter,
3722 GtkTextRealIter *real;
3724 gint real_char_index;
3726 g_return_if_fail (iter != NULL);
3728 real = gtk_text_iter_make_surreal (iter);
3733 check_invariants (iter);
3735 if (real->cached_char_index >= 0 &&
3736 real->cached_char_index == char_offset)
3739 line = _gtk_text_btree_get_line_at_char (real->tree,
3744 iter_set_from_char_offset (real, line, real_char_index - line_start);
3746 /* Go ahead and cache this since we have it. */
3747 real->cached_char_index = real_char_index;
3749 check_invariants (iter);
3753 * gtk_text_iter_forward_to_end:
3754 * @iter: a #GtkTextIter
3756 * Moves @iter forward to the "end iterator," which points one past the last
3757 * valid character in the buffer. gtk_text_iter_get_char() called on the
3758 * end iterator returns 0, which is convenient for writing loops.
3761 gtk_text_iter_forward_to_end (GtkTextIter *iter)
3763 GtkTextBuffer *buffer;
3764 GtkTextRealIter *real;
3766 g_return_if_fail (iter != NULL);
3768 real = gtk_text_iter_make_surreal (iter);
3773 buffer = _gtk_text_btree_get_buffer (real->tree);
3775 gtk_text_buffer_get_end_iter (buffer, iter);
3778 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3779 * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3780 * If all else fails we could cache the para delimiter pos in the iter.
3781 * I think forward_to_line_end() actually gets called fairly often.
3784 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3789 if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3790 _gtk_text_iter_get_btree (&end)))
3792 gtk_text_iter_forward_to_end (&end);
3796 /* if we aren't on the last line, go forward to start of next line, then scan
3797 * back for the delimiters on the previous line
3799 gtk_text_iter_forward_line (&end);
3800 gtk_text_iter_backward_char (&end);
3801 while (!gtk_text_iter_ends_line (&end))
3802 gtk_text_iter_backward_char (&end);
3805 return gtk_text_iter_get_line_offset (&end);
3809 * gtk_text_iter_forward_to_line_end:
3810 * @iter: a #GtkTextIter
3812 * Moves the iterator to point to the paragraph delimiter characters,
3813 * which will be either a newline, a carriage return, a carriage
3814 * return/newline in sequence, or the Unicode paragraph separator
3815 * character. If the iterator is already at the paragraph delimiter
3816 * characters, moves to the paragraph delimiter characters for the
3817 * next line. If @iter is on the last line in the buffer, which does
3818 * not end in paragraph delimiters, moves to the end iterator (end of
3819 * the last line), and returns %FALSE.
3821 * Return value: %TRUE if we moved and the new location is not the end iterator
3824 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3826 gint current_offset;
3830 g_return_val_if_fail (iter != NULL, FALSE);
3832 current_offset = gtk_text_iter_get_line_offset (iter);
3833 new_offset = find_paragraph_delimiter_for_line (iter);
3835 if (current_offset < new_offset)
3837 /* Move to end of this line. */
3838 gtk_text_iter_set_line_offset (iter, new_offset);
3839 return !gtk_text_iter_is_end (iter);
3843 /* Move to end of next line. */
3844 if (gtk_text_iter_forward_line (iter))
3846 /* We don't want to move past all
3849 if (!gtk_text_iter_ends_line (iter))
3850 gtk_text_iter_forward_to_line_end (iter);
3851 return !gtk_text_iter_is_end (iter);
3859 * gtk_text_iter_forward_to_tag_toggle:
3860 * @iter: a #GtkTextIter
3861 * @tag: a #GtkTextTag, or %NULL
3863 * Moves forward to the next toggle (on or off) of the
3864 * #GtkTextTag @tag, or to the next toggle of any tag if
3865 * @tag is %NULL. If no matching tag toggles are found,
3866 * returns %FALSE, otherwise %TRUE. Does not return toggles
3867 * located at @iter, only toggles after @iter. Sets @iter to
3868 * the location of the toggle, or to the end of the buffer
3869 * if no toggle is found.
3871 * Return value: whether we found a tag toggle after @iter
3874 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3877 GtkTextLine *next_line;
3878 GtkTextLine *current_line;
3879 GtkTextRealIter *real;
3881 g_return_val_if_fail (iter != NULL, FALSE);
3883 real = gtk_text_iter_make_real (iter);
3888 check_invariants (iter);
3890 current_line = real->line;
3891 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3894 while (_gtk_text_iter_forward_indexable_segment (iter))
3896 /* If we went forward to a line that couldn't contain a toggle
3897 for the tag, then skip forward to a line that could contain
3898 it. This potentially skips huge hunks of the tree, so we
3899 aren't a purely linear search. */
3900 if (real->line != current_line)
3902 if (next_line == NULL)
3904 /* End of search. Set to end of buffer. */
3905 _gtk_text_btree_get_end_iter (real->tree, iter);
3909 if (real->line != next_line)
3910 iter_set_from_byte_offset (real, next_line, 0);
3912 current_line = real->line;
3913 next_line = _gtk_text_line_next_could_contain_tag (current_line,
3918 if (gtk_text_iter_toggles_tag (iter, tag))
3920 /* If there's a toggle here, it isn't indexable so
3921 any_segment can't be the indexable segment. */
3922 g_assert (real->any_segment != real->segment);
3927 /* Check end iterator for tags */
3928 if (gtk_text_iter_toggles_tag (iter, tag))
3930 /* If there's a toggle here, it isn't indexable so
3931 any_segment can't be the indexable segment. */
3932 g_assert (real->any_segment != real->segment);
3936 /* Reached end of buffer */
3941 * gtk_text_iter_backward_to_tag_toggle:
3942 * @iter: a #GtkTextIter
3943 * @tag: a #GtkTextTag, or %NULL
3945 * Moves backward to the next toggle (on or off) of the
3946 * #GtkTextTag @tag, or to the next toggle of any tag if
3947 * @tag is %NULL. If no matching tag toggles are found,
3948 * returns %FALSE, otherwise %TRUE. Does not return toggles
3949 * located at @iter, only toggles before @iter. Sets @iter
3950 * to the location of the toggle, or the start of the buffer
3951 * if no toggle is found.
3953 * Return value: whether we found a tag toggle before @iter
3956 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
3959 GtkTextLine *prev_line;
3960 GtkTextLine *current_line;
3961 GtkTextRealIter *real;
3963 g_return_val_if_fail (iter != NULL, FALSE);
3965 real = gtk_text_iter_make_real (iter);
3970 check_invariants (iter);
3972 current_line = real->line;
3973 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
3977 /* If we're at segment start, go to the previous segment;
3978 * if mid-segment, snap to start of current segment.
3980 if (is_segment_start (real))
3982 if (!_gtk_text_iter_backward_indexable_segment (iter))
3987 ensure_char_offsets (real);
3989 if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
3995 /* If we went backward to a line that couldn't contain a toggle
3996 * for the tag, then skip backward further to a line that
3997 * could contain it. This potentially skips huge hunks of the
3998 * tree, so we aren't a purely linear search.
4000 if (real->line != current_line)
4002 if (prev_line == NULL)
4004 /* End of search. Set to start of buffer. */
4005 _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4009 if (real->line != prev_line)
4011 /* Set to last segment in prev_line (could do this
4014 iter_set_from_byte_offset (real, prev_line, 0);
4016 while (!at_last_indexable_segment (real))
4017 _gtk_text_iter_forward_indexable_segment (iter);
4020 current_line = real->line;
4021 prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4026 if (gtk_text_iter_toggles_tag (iter, tag))
4028 /* If there's a toggle here, it isn't indexable so
4029 * any_segment can't be the indexable segment.
4031 g_assert (real->any_segment != real->segment);
4035 while (_gtk_text_iter_backward_indexable_segment (iter));
4037 /* Reached front of buffer */
4042 matches_pred (GtkTextIter *iter,
4043 GtkTextCharPredicate pred,
4048 ch = gtk_text_iter_get_char (iter);
4050 return (*pred) (ch, user_data);
4054 * gtk_text_iter_forward_find_char:
4055 * @iter: a #GtkTextIter
4056 * @pred: a function to be called on each character
4057 * @user_data: user data for @pred
4058 * @limit: search limit, or %NULL for none
4060 * Advances @iter, calling @pred on each character. If
4061 * @pred returns %TRUE, returns %TRUE and stops scanning.
4062 * If @pred never returns %TRUE, @iter is set to @limit if
4063 * @limit is non-%NULL, otherwise to the end iterator.
4065 * Return value: whether a match was found
4068 gtk_text_iter_forward_find_char (GtkTextIter *iter,
4069 GtkTextCharPredicate pred,
4071 const GtkTextIter *limit)
4073 g_return_val_if_fail (iter != NULL, FALSE);
4074 g_return_val_if_fail (pred != NULL, FALSE);
4077 gtk_text_iter_compare (iter, limit) >= 0)
4080 while ((limit == NULL ||
4081 !gtk_text_iter_equal (limit, iter)) &&
4082 gtk_text_iter_forward_char (iter))
4084 if (matches_pred (iter, pred, user_data))
4092 * gtk_text_iter_backward_find_char:
4093 * @iter: a #GtkTextIter
4094 * @pred: function to be called on each character
4095 * @user_data: user data for @pred
4096 * @limit: search limit, or %NULL for none
4098 * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4100 * Return value: whether a match was found
4103 gtk_text_iter_backward_find_char (GtkTextIter *iter,
4104 GtkTextCharPredicate pred,
4106 const GtkTextIter *limit)
4108 g_return_val_if_fail (iter != NULL, FALSE);
4109 g_return_val_if_fail (pred != NULL, FALSE);
4112 gtk_text_iter_compare (iter, limit) <= 0)
4115 while ((limit == NULL ||
4116 !gtk_text_iter_equal (limit, iter)) &&
4117 gtk_text_iter_backward_char (iter))
4119 if (matches_pred (iter, pred, user_data))
4127 forward_chars_with_skipping (GtkTextIter *iter,
4129 gboolean skip_invisible,
4130 gboolean skip_nontext)
4135 g_return_if_fail (count >= 0);
4141 gboolean ignored = FALSE;
4144 gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4149 _gtk_text_btree_char_is_invisible (iter))
4152 gtk_text_iter_forward_char (iter);
4160 lines_match (const GtkTextIter *start,
4161 const gchar **lines,
4162 gboolean visible_only,
4164 GtkTextIter *match_start,
4165 GtkTextIter *match_end)
4172 if (*lines == NULL || **lines == '\0')
4175 *match_start = *start;
4178 *match_end = *start;
4183 gtk_text_iter_forward_line (&next);
4185 /* No more text in buffer, but *lines is nonempty */
4186 if (gtk_text_iter_equal (start, &next))
4194 line_text = gtk_text_iter_get_visible_slice (start, &next);
4196 line_text = gtk_text_iter_get_slice (start, &next);
4201 line_text = gtk_text_iter_get_visible_text (start, &next);
4203 line_text = gtk_text_iter_get_text (start, &next);
4206 if (match_start) /* if this is the first line we're matching */
4207 found = strstr (line_text, *lines);
4210 /* If it's not the first line, we have to match from the
4211 * start of the line.
4213 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4225 /* Get offset to start of search string */
4226 offset = g_utf8_strlen (line_text, found - line_text);
4230 /* If match start needs to be returned, set it to the
4231 * start of the search string.
4235 *match_start = next;
4237 forward_chars_with_skipping (match_start, offset,
4238 visible_only, !slice);
4241 /* Go to end of search string */
4242 offset += g_utf8_strlen (*lines, -1);
4244 forward_chars_with_skipping (&next, offset,
4245 visible_only, !slice);
4254 /* pass NULL for match_start, since we don't need to find the
4257 return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4260 /* strsplit () that retains the delimiter as part of the string. */
4262 strbreakup (const char *string,
4263 const char *delimiter,
4266 GSList *string_list = NULL, *slist;
4267 gchar **str_array, *s;
4270 g_return_val_if_fail (string != NULL, NULL);
4271 g_return_val_if_fail (delimiter != NULL, NULL);
4274 max_tokens = G_MAXINT;
4276 s = strstr (string, delimiter);
4279 guint delimiter_len = strlen (delimiter);
4286 len = s - string + delimiter_len;
4287 new_string = g_new (gchar, len + 1);
4288 strncpy (new_string, string, len);
4289 new_string[len] = 0;
4290 string_list = g_slist_prepend (string_list, new_string);
4292 string = s + delimiter_len;
4293 s = strstr (string, delimiter);
4295 while (--max_tokens && s);
4300 string_list = g_slist_prepend (string_list, g_strdup (string));
4303 str_array = g_new (gchar*, n);
4307 str_array[i--] = NULL;
4308 for (slist = string_list; slist; slist = slist->next)
4309 str_array[i--] = slist->data;
4311 g_slist_free (string_list);
4317 * gtk_text_iter_forward_search:
4318 * @iter: start of search
4319 * @str: a search string
4320 * @flags: flags affecting how the search is done
4321 * @match_start: return location for start of match, or %NULL
4322 * @match_end: return location for end of match, or %NULL
4323 * @limit: bound for the search, or %NULL for the end of the buffer
4325 * Searches forward for @str. Any match is returned by setting
4326 * @match_start to the first character of the match and @match_end to the
4327 * first character after the match. The search will not continue past
4328 * @limit. Note that a search is a linear or O(n) operation, so you
4329 * may wish to use @limit to avoid locking up your UI on large
4332 * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4333 * have invisible text interspersed in @str. i.e. @str will be a
4334 * possibly-noncontiguous subsequence of the matched range. similarly,
4335 * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4336 * pixbufs or child widgets mixed inside the matched range. If these
4337 * flags are not given, the match must be exact; the special 0xFFFC
4338 * character in @str will match embedded pixbufs or child widgets.
4340 * Return value: whether a match was found
4343 gtk_text_iter_forward_search (const GtkTextIter *iter,
4345 GtkTextSearchFlags flags,
4346 GtkTextIter *match_start,
4347 GtkTextIter *match_end,
4348 const GtkTextIter *limit)
4350 gchar **lines = NULL;
4352 gboolean retval = FALSE;
4354 gboolean visible_only;
4357 g_return_val_if_fail (iter != NULL, FALSE);
4358 g_return_val_if_fail (str != NULL, FALSE);
4361 gtk_text_iter_compare (iter, limit) >= 0)
4366 /* If we can move one char, return the empty string there */
4369 if (gtk_text_iter_forward_char (&match))
4372 gtk_text_iter_equal (&match, limit))
4376 *match_start = match;
4385 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4386 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4388 /* locate all lines */
4390 lines = strbreakup (str, "\n", -1);
4396 /* This loop has an inefficient worst-case, where
4397 * gtk_text_iter_get_text () is called repeatedly on
4403 gtk_text_iter_compare (&search, limit) >= 0)
4406 if (lines_match (&search, (const gchar**)lines,
4407 visible_only, slice, &match, &end))
4409 if (limit == NULL ||
4411 gtk_text_iter_compare (&end, limit) < 0))
4416 *match_start = match;
4425 while (gtk_text_iter_forward_line (&search));
4427 g_strfreev ((gchar**)lines);
4433 vectors_equal_ignoring_trailing (gchar **vec1,
4436 /* Ignores trailing chars in vec2's last line */
4445 if (strcmp (*i1, *i2) != 0)
4447 if (*(i2 + 1) == NULL) /* if this is the last line */
4449 gint len1 = strlen (*i1);
4450 gint len2 = strlen (*i2);
4453 strncmp (*i1, *i2, len1) == 0)
4455 /* We matched ignoring the trailing stuff in vec2 */
4480 typedef struct _LinesWindow LinesWindow;
4486 GtkTextIter first_line_start;
4487 GtkTextIter first_line_end;
4489 gboolean visible_only;
4493 lines_window_init (LinesWindow *win,
4494 const GtkTextIter *start)
4497 GtkTextIter line_start;
4498 GtkTextIter line_end;
4500 /* If we start on line 1, there are 2 lines to search (0 and 1), so
4503 if (gtk_text_iter_is_start (start) ||
4504 gtk_text_iter_get_line (start) + 1 < win->n_lines)
4506 /* Already at the end, or not enough lines to match */
4507 win->lines = g_new0 (gchar*, 1);
4512 line_start = *start;
4515 /* Move to start iter to start of line */
4516 gtk_text_iter_set_line_offset (&line_start, 0);
4518 if (gtk_text_iter_equal (&line_start, &line_end))
4520 /* we were already at the start; so go back one line */
4521 gtk_text_iter_backward_line (&line_start);
4524 win->first_line_start = line_start;
4525 win->first_line_end = line_end;
4527 win->lines = g_new0 (gchar*, win->n_lines + 1);
4529 i = win->n_lines - 1;
4536 if (win->visible_only)
4537 line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4539 line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4543 if (win->visible_only)
4544 line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4546 line_text = gtk_text_iter_get_text (&line_start, &line_end);
4549 win->lines[i] = line_text;
4551 line_end = line_start;
4552 gtk_text_iter_backward_line (&line_start);
4559 lines_window_back (LinesWindow *win)
4561 GtkTextIter new_start;
4564 new_start = win->first_line_start;
4566 if (!gtk_text_iter_backward_line (&new_start))
4570 win->first_line_start = new_start;
4571 win->first_line_end = new_start;
4573 gtk_text_iter_forward_line (&win->first_line_end);
4578 if (win->visible_only)
4579 line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4580 &win->first_line_end);
4582 line_text = gtk_text_iter_get_slice (&win->first_line_start,
4583 &win->first_line_end);
4587 if (win->visible_only)
4588 line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4589 &win->first_line_end);
4591 line_text = gtk_text_iter_get_text (&win->first_line_start,
4592 &win->first_line_end);
4595 /* Move lines to make room for first line. */
4596 g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4598 *win->lines = line_text;
4600 /* Free old last line and NULL-terminate */
4601 g_free (win->lines[win->n_lines]);
4602 win->lines[win->n_lines] = NULL;
4608 lines_window_free (LinesWindow *win)
4610 g_strfreev (win->lines);
4614 my_strrstr (const gchar *haystack,
4615 const gchar *needle)
4617 /* FIXME GLib should have a nice implementation in it, this
4621 gint haystack_len = strlen (haystack);
4622 gint needle_len = strlen (needle);
4623 const gchar *needle_end = needle + needle_len;
4624 const gchar *haystack_rend = haystack - 1;
4625 const gchar *needle_rend = needle - 1;
4628 p = haystack + haystack_len;
4629 while (p != haystack)
4631 const gchar *n = needle_end - 1;
4632 const gchar *s = p - 1;
4633 while (s != haystack_rend &&
4641 if (n == needle_rend)
4651 * gtk_text_iter_backward_search:
4652 * @iter: a #GtkTextIter where the search begins
4653 * @str: search string
4654 * @flags: bitmask of flags affecting the search
4655 * @match_start: return location for start of match, or %NULL
4656 * @match_end: return location for end of match, or %NULL
4657 * @limit: location of last possible @match_start, or %NULL for start of buffer
4659 * Same as gtk_text_iter_forward_search(), but moves backward.
4661 * Return value: whether a match was found
4664 gtk_text_iter_backward_search (const GtkTextIter *iter,
4666 GtkTextSearchFlags flags,
4667 GtkTextIter *match_start,
4668 GtkTextIter *match_end,
4669 const GtkTextIter *limit)
4671 gchar **lines = NULL;
4675 gboolean retval = FALSE;
4676 gboolean visible_only;
4679 g_return_val_if_fail (iter != NULL, FALSE);
4680 g_return_val_if_fail (str != NULL, FALSE);
4683 gtk_text_iter_compare (limit, iter) > 0)
4688 /* If we can move one char, return the empty string there */
4689 GtkTextIter match = *iter;
4691 if (limit && gtk_text_iter_equal (limit, &match))
4694 if (gtk_text_iter_backward_char (&match))
4697 *match_start = match;
4706 visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4707 slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4709 /* locate all lines */
4711 lines = strbreakup (str, "\n", -1);
4721 win.n_lines = n_lines;
4723 win.visible_only = visible_only;
4725 lines_window_init (&win, iter);
4727 if (*win.lines == NULL)
4732 gchar *first_line_match;
4735 gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4737 /* We're now before the search limit, abort. */
4741 /* If there are multiple lines, the first line will
4742 * end in '\n', so this will only match at the
4743 * end of the first line, which is correct.
4745 first_line_match = my_strrstr (*win.lines, *lines);
4747 if (first_line_match &&
4748 vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4753 GtkTextIter start_tmp;
4755 /* Offset to start of search string */
4756 offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4758 next = win.first_line_start;
4760 forward_chars_with_skipping (&start_tmp, offset,
4761 visible_only, !slice);
4764 gtk_text_iter_compare (limit, &start_tmp) > 0)
4765 goto out; /* match was bogus */
4768 *match_start = start_tmp;
4770 /* Go to end of search string */
4774 offset += g_utf8_strlen (*l, -1);
4778 forward_chars_with_skipping (&next, offset,
4779 visible_only, !slice);
4788 while (lines_window_back (&win));
4791 lines_window_free (&win);
4802 * gtk_text_iter_equal:
4803 * @lhs: a #GtkTextIter
4804 * @rhs: another #GtkTextIter
4806 * Tests whether two iterators are equal, using the fastest possible
4807 * mechanism. This function is very fast; you can expect it to perform
4808 * better than e.g. getting the character offset for each iterator and
4809 * comparing the offsets yourself. Also, it's a bit faster than
4810 * gtk_text_iter_compare().
4812 * Return value: %TRUE if the iterators point to the same place in the buffer
4815 gtk_text_iter_equal (const GtkTextIter *lhs,
4816 const GtkTextIter *rhs)
4818 GtkTextRealIter *real_lhs;
4819 GtkTextRealIter *real_rhs;
4821 real_lhs = (GtkTextRealIter*)lhs;
4822 real_rhs = (GtkTextRealIter*)rhs;
4824 check_invariants (lhs);
4825 check_invariants (rhs);
4827 if (real_lhs->line != real_rhs->line)
4829 else if (real_lhs->line_byte_offset >= 0 &&
4830 real_rhs->line_byte_offset >= 0)
4831 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4834 /* the ensure_char_offsets () calls do nothing if the char offsets
4835 are already up-to-date. */
4836 ensure_char_offsets (real_lhs);
4837 ensure_char_offsets (real_rhs);
4838 return real_lhs->line_char_offset == real_rhs->line_char_offset;
4843 * gtk_text_iter_compare:
4844 * @lhs: a #GtkTextIter
4845 * @rhs: another #GtkTextIter
4847 * A qsort()-style function that returns negative if @lhs is less than
4848 * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4849 * Ordering is in character offset order, i.e. the first character in the buffer
4850 * is less than the second character in the buffer.
4852 * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4855 gtk_text_iter_compare (const GtkTextIter *lhs,
4856 const GtkTextIter *rhs)
4858 GtkTextRealIter *real_lhs;
4859 GtkTextRealIter *real_rhs;
4861 real_lhs = gtk_text_iter_make_surreal (lhs);
4862 real_rhs = gtk_text_iter_make_surreal (rhs);
4864 if (real_lhs == NULL ||
4866 return -1; /* why not */
4868 check_invariants (lhs);
4869 check_invariants (rhs);
4871 if (real_lhs->line == real_rhs->line)
4873 gint left_index, right_index;
4875 if (real_lhs->line_byte_offset >= 0 &&
4876 real_rhs->line_byte_offset >= 0)
4878 left_index = real_lhs->line_byte_offset;
4879 right_index = real_rhs->line_byte_offset;
4883 /* the ensure_char_offsets () calls do nothing if
4884 the offsets are already up-to-date. */
4885 ensure_char_offsets (real_lhs);
4886 ensure_char_offsets (real_rhs);
4887 left_index = real_lhs->line_char_offset;
4888 right_index = real_rhs->line_char_offset;
4891 if (left_index < right_index)
4893 else if (left_index > right_index)
4902 line1 = gtk_text_iter_get_line (lhs);
4903 line2 = gtk_text_iter_get_line (rhs);
4906 else if (line1 > line2)
4914 * gtk_text_iter_in_range:
4915 * @iter: a #GtkTextIter
4916 * @start: start of range
4917 * @end: end of range
4919 * Checks whether @iter falls in the range [@start, @end).
4920 * @start and @end must be in ascending order.
4922 * Return value: %TRUE if @iter is in the range
4925 gtk_text_iter_in_range (const GtkTextIter *iter,
4926 const GtkTextIter *start,
4927 const GtkTextIter *end)
4929 g_return_val_if_fail (iter != NULL, FALSE);
4930 g_return_val_if_fail (start != NULL, FALSE);
4931 g_return_val_if_fail (end != NULL, FALSE);
4932 g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
4934 return gtk_text_iter_compare (iter, start) >= 0 &&
4935 gtk_text_iter_compare (iter, end) < 0;
4939 * gtk_text_iter_order:
4940 * @first: a #GtkTextIter
4941 * @second: another #GtkTextIter
4943 * Swaps the value of @first and @second if @second comes before
4944 * @first in the buffer. That is, ensures that @first and @second are
4945 * in sequence. Most text buffer functions that take a range call this
4946 * automatically on your behalf, so there's no real reason to call it yourself
4947 * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
4948 * that expect a pre-sorted range.
4952 gtk_text_iter_order (GtkTextIter *first,
4953 GtkTextIter *second)
4955 g_return_if_fail (first != NULL);
4956 g_return_if_fail (second != NULL);
4958 if (gtk_text_iter_compare (first, second) > 0)
4969 * Init iterators from the BTree
4973 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
4977 GtkTextRealIter *real = (GtkTextRealIter*)iter;
4978 gint real_char_index;
4982 g_return_if_fail (iter != NULL);
4983 g_return_if_fail (tree != NULL);
4985 line = _gtk_text_btree_get_line_at_char (tree, char_index,
4986 &line_start, &real_char_index);
4988 iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
4990 real->cached_char_index = real_char_index;
4992 check_invariants (iter);
4996 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5001 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5005 g_return_if_fail (iter != NULL);
5006 g_return_if_fail (tree != NULL);
5008 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5010 iter_init_from_char_offset (iter, tree, line, char_on_line);
5012 /* We might as well cache this, since we know it. */
5013 real->cached_line_number = real_line;
5015 check_invariants (iter);
5019 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
5024 GtkTextRealIter *real = (GtkTextRealIter*)iter;
5028 g_return_if_fail (iter != NULL);
5029 g_return_if_fail (tree != NULL);
5031 line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5033 iter_init_from_byte_offset (iter, tree, line, byte_index);
5035 /* We might as well cache this, since we know it. */
5036 real->cached_line_number = real_line;
5038 check_invariants (iter);
5042 _gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
5047 g_return_if_fail (iter != NULL);
5048 g_return_if_fail (tree != NULL);
5049 g_return_if_fail (line != NULL);
5051 iter_init_from_byte_offset (iter, tree, line, byte_offset);
5053 check_invariants (iter);
5057 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
5063 g_return_val_if_fail (iter != NULL, FALSE);
5064 g_return_val_if_fail (tree != NULL, FALSE);
5066 line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5070 /* Set iter to last in tree */
5071 _gtk_text_btree_get_end_iter (tree, iter);
5072 check_invariants (iter);
5077 iter_init_from_byte_offset (iter, tree, line, 0);
5078 gtk_text_iter_forward_to_tag_toggle (iter, tag);
5079 check_invariants (iter);
5085 _gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
5089 g_return_val_if_fail (iter != NULL, FALSE);
5090 g_return_val_if_fail (tree != NULL, FALSE);
5092 _gtk_text_btree_get_end_iter (tree, iter);
5093 gtk_text_iter_backward_to_tag_toggle (iter, tag);
5094 check_invariants (iter);
5100 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5102 const gchar *mark_name)
5106 g_return_val_if_fail (iter != NULL, FALSE);
5107 g_return_val_if_fail (tree != NULL, FALSE);
5109 mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5115 _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5116 check_invariants (iter);
5122 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5126 GtkTextLineSegment *seg;
5128 g_return_if_fail (iter != NULL);
5129 g_return_if_fail (tree != NULL);
5130 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5132 seg = mark->segment;
5134 iter_init_from_segment (iter, tree,
5135 seg->body.mark.line, seg);
5136 g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5137 check_invariants (iter);
5141 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree *tree,
5143 GtkTextChildAnchor *anchor)
5145 GtkTextLineSegment *seg;
5147 g_return_if_fail (iter != NULL);
5148 g_return_if_fail (tree != NULL);
5149 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5151 seg = anchor->segment;
5153 g_assert (seg->body.child.line != NULL);
5155 iter_init_from_segment (iter, tree,
5156 seg->body.child.line, seg);
5157 g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5158 check_invariants (iter);
5162 _gtk_text_btree_get_end_iter (GtkTextBTree *tree,
5165 g_return_if_fail (iter != NULL);
5166 g_return_if_fail (tree != NULL);
5168 _gtk_text_btree_get_iter_at_char (tree,
5170 _gtk_text_btree_char_count (tree));
5171 check_invariants (iter);
5175 _gtk_text_iter_check (const GtkTextIter *iter)
5177 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5178 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5179 GtkTextLineSegment *byte_segment = NULL;
5180 GtkTextLineSegment *byte_any_segment = NULL;
5181 GtkTextLineSegment *char_segment = NULL;
5182 GtkTextLineSegment *char_any_segment = NULL;
5183 gboolean segments_updated;
5185 /* This function checks our class invariants for the Iter class. */
5187 g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5189 if (real->chars_changed_stamp !=
5190 _gtk_text_btree_get_chars_changed_stamp (real->tree))
5191 g_error ("iterator check failed: invalid iterator");
5193 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5194 g_error ("iterator check failed: both char and byte offsets are invalid");
5196 segments_updated = (real->segments_changed_stamp ==
5197 _gtk_text_btree_get_segments_changed_stamp (real->tree));
5200 printf ("checking iter, segments %s updated, byte %d char %d\n",
5201 segments_updated ? "are" : "aren't",
5202 real->line_byte_offset,
5203 real->line_char_offset);
5206 if (segments_updated)
5208 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5209 g_error ("iterator check failed: both char and byte segment offsets are invalid");
5211 if (real->segment->char_count == 0)
5212 g_error ("iterator check failed: segment is not indexable.");
5214 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5215 g_error ("segment char offset is not properly up-to-date");
5217 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5218 g_error ("segment byte offset is not properly up-to-date");
5220 if (real->segment_byte_offset >= 0 &&
5221 real->segment_byte_offset >= real->segment->byte_count)
5222 g_error ("segment byte offset is too large.");
5224 if (real->segment_char_offset >= 0 &&
5225 real->segment_char_offset >= real->segment->char_count)
5226 g_error ("segment char offset is too large.");
5229 if (real->line_byte_offset >= 0)
5231 _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5232 &byte_segment, &byte_any_segment,
5233 &seg_byte_offset, &line_byte_offset);
5235 if (line_byte_offset != real->line_byte_offset)
5236 g_error ("wrong byte offset was stored in iterator");
5238 if (segments_updated)
5240 if (real->segment != byte_segment)
5241 g_error ("wrong segment was stored in iterator");
5243 if (real->any_segment != byte_any_segment)
5244 g_error ("wrong any_segment was stored in iterator");
5246 if (seg_byte_offset != real->segment_byte_offset)
5247 g_error ("wrong segment byte offset was stored in iterator");
5249 if (byte_segment->type == >k_text_char_type)
5252 p = byte_segment->body.chars + seg_byte_offset;
5254 if (!gtk_text_byte_begins_utf8_char (p))
5255 g_error ("broken iterator byte index pointed into the middle of a character");
5260 if (real->line_char_offset >= 0)
5262 _gtk_text_line_char_locate (real->line, real->line_char_offset,
5263 &char_segment, &char_any_segment,
5264 &seg_char_offset, &line_char_offset);
5266 if (line_char_offset != real->line_char_offset)
5267 g_error ("wrong char offset was stored in iterator");
5269 if (segments_updated)
5271 if (real->segment != char_segment)
5272 g_error ("wrong segment was stored in iterator");
5274 if (real->any_segment != char_any_segment)
5275 g_error ("wrong any_segment was stored in iterator");
5277 if (seg_char_offset != real->segment_char_offset)
5278 g_error ("wrong segment char offset was stored in iterator");
5280 if (char_segment->type == >k_text_char_type)
5283 p = g_utf8_offset_to_pointer (char_segment->body.chars,
5286 /* hmm, not likely to happen eh */
5287 if (!gtk_text_byte_begins_utf8_char (p))
5288 g_error ("broken iterator char offset pointed into the middle of a character");
5293 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5295 if (byte_segment != char_segment)
5296 g_error ("char and byte offsets did not point to the same segment");
5298 if (byte_any_segment != char_any_segment)
5299 g_error ("char and byte offsets did not point to the same any segment");
5301 /* Make sure the segment offsets are equivalent, if it's a char
5303 if (char_segment->type == >k_text_char_type)
5305 gint byte_offset = 0;
5306 gint char_offset = 0;
5307 while (char_offset < seg_char_offset)
5309 const char * start = char_segment->body.chars + byte_offset;
5310 byte_offset += g_utf8_next_char (start) - start;
5314 if (byte_offset != seg_byte_offset)
5315 g_error ("byte offset did not correspond to char offset");
5318 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5320 if (char_offset != seg_char_offset)
5321 g_error ("char offset did not correspond to byte offset");
5323 if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5324 g_error ("byte index for iterator does not index the start of a character");
5328 if (real->cached_line_number >= 0)
5332 should_be = _gtk_text_line_get_number (real->line);
5333 if (real->cached_line_number != should_be)
5334 g_error ("wrong line number was cached");
5337 if (real->cached_char_index >= 0)
5339 if (real->line_char_offset >= 0) /* only way we can check it
5340 efficiently, not a real
5345 char_index = _gtk_text_line_char_index (real->line);
5346 char_index += real->line_char_offset;
5348 if (real->cached_char_index != char_index)
5349 g_error ("wrong char index was cached");
5353 if (_gtk_text_line_is_last (real->line, real->tree))
5354 g_error ("Iterator was on last line (past the end iterator)");