1 #include "gtktextiter.h"
2 #include "gtktextbtree.h"
3 #include "gtktextiterprivate.h"
7 typedef struct _GtkTextRealIter GtkTextRealIter;
9 struct _GtkTextRealIter {
10 /* Always-valid information */
13 /* At least one of these is always valid;
14 if invalid, they are -1.
16 If the line byte offset is valid, so is the segment byte offset;
17 and ditto for char offsets. */
18 gint line_byte_offset;
19 gint line_char_offset;
20 /* These two are valid if >= 0 */
21 gint cached_char_index;
22 gint cached_line_number;
23 /* Stamps to detect the buffer changing under us */
24 gint chars_changed_stamp;
25 gint segments_changed_stamp;
26 /* Valid if the segments_changed_stamp is up-to-date */
27 GtkTextLineSegment *segment; /* indexable segment we index */
28 GtkTextLineSegment *any_segment; /* first segment in our location,
29 maybe same as "segment" */
30 /* One of these will always be valid if segments_changed_stamp is
31 up-to-date. If invalid, they are -1.
33 If the line byte offset is valid, so is the segment byte offset;
34 and ditto for char offsets. */
35 gint segment_byte_offset;
36 gint segment_char_offset;
37 /* These are here for binary-compatible expansion space. */
42 /* These "set" functions should not assume any fields
43 other than the char stamp and the tree are valid.
46 iter_set_common(GtkTextRealIter *iter,
49 /* Update segments stamp */
50 iter->segments_changed_stamp =
51 gtk_text_btree_get_segments_changed_stamp(iter->tree);
55 iter->line_byte_offset = -1;
56 iter->line_char_offset = -1;
57 iter->segment_byte_offset = -1;
58 iter->segment_char_offset = -1;
59 iter->cached_char_index = -1;
60 iter->cached_line_number = -1;
64 iter_set_from_byte_offset(GtkTextRealIter *iter,
68 iter_set_common(iter, line);
70 gtk_text_line_byte_locate(iter->line,
74 &iter->segment_byte_offset,
75 &iter->line_byte_offset);
80 iter_set_from_char_offset(GtkTextRealIter *iter,
84 iter_set_common(iter, line);
86 gtk_text_line_char_locate(iter->line,
90 &iter->segment_char_offset,
91 &iter->line_char_offset);
95 iter_set_from_segment(GtkTextRealIter *iter,
97 GtkTextLineSegment *segment)
99 GtkTextLineSegment *seg;
102 /* This could theoretically be optimized by computing all the iter
103 fields in this same loop, but I'm skipping it for now. */
105 seg = line->segments;
106 while (seg != segment)
108 byte_offset += seg->byte_count;
112 iter_set_from_byte_offset(iter, line, byte_offset);
115 /* This function ensures that the segment-dependent information is
116 truly computed lazily; often we don't need to do the full make_real
118 static GtkTextRealIter*
119 gtk_text_iter_make_surreal(const GtkTextIter *_iter)
121 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
123 if (iter->chars_changed_stamp !=
124 gtk_text_btree_get_chars_changed_stamp(iter->tree))
126 g_warning("Invalid text buffer iterator: either the iterator is uninitialized, or the characters/pixmaps/widgets in the buffer have been modified since the iterator was created.\nYou must use marks, character numbers, or line numbers to preserve a position across buffer modifications.\nYou can apply tags and insert marks without invalidating your iterators, however.");
130 /* We don't update the segments information since we are becoming
131 only surreal. However we do invalidate the segments information
132 if appropriate, to be sure we segfault if we try to use it and we
133 should have used make_real. */
135 if (iter->segments_changed_stamp !=
136 gtk_text_btree_get_segments_changed_stamp(iter->tree))
138 iter->segment = NULL;
139 iter->any_segment = NULL;
140 /* set to segfault-causing values. */
141 iter->segment_byte_offset = -10000;
142 iter->segment_char_offset = -10000;
148 static GtkTextRealIter*
149 gtk_text_iter_make_real(const GtkTextIter *_iter)
151 GtkTextRealIter *iter;
153 iter = gtk_text_iter_make_surreal(_iter);
155 if (iter->segments_changed_stamp !=
156 gtk_text_btree_get_segments_changed_stamp(iter->tree))
158 if (iter->line_byte_offset >= 0)
160 iter_set_from_byte_offset(iter,
162 iter->line_byte_offset);
166 g_assert(iter->line_char_offset >= 0);
168 iter_set_from_char_offset(iter,
170 iter->line_char_offset);
174 g_assert(iter->segment != NULL);
175 g_assert(iter->any_segment != NULL);
176 g_assert(iter->segment->char_count > 0);
181 static GtkTextRealIter*
182 iter_init_common(GtkTextIter *_iter,
185 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
187 g_return_val_if_fail(iter != NULL, NULL);
188 g_return_val_if_fail(tree != NULL, NULL);
192 iter->chars_changed_stamp =
193 gtk_text_btree_get_chars_changed_stamp(iter->tree);
198 static GtkTextRealIter*
199 iter_init_from_segment(GtkTextIter *iter,
202 GtkTextLineSegment *segment)
204 GtkTextRealIter *real;
206 g_return_val_if_fail(line != NULL, NULL);
208 real = iter_init_common(iter, tree);
210 iter_set_from_segment(real, line, segment);
215 static GtkTextRealIter*
216 iter_init_from_byte_offset(GtkTextIter *iter,
219 gint line_byte_offset)
221 GtkTextRealIter *real;
223 g_return_val_if_fail(line != NULL, NULL);
225 real = iter_init_common(iter, tree);
227 iter_set_from_byte_offset(real, line, line_byte_offset);
232 static GtkTextRealIter*
233 iter_init_from_char_offset(GtkTextIter *iter,
236 gint line_char_offset)
238 GtkTextRealIter *real;
240 g_return_val_if_fail(line != NULL, NULL);
242 real = iter_init_common(iter, tree);
244 iter_set_from_char_offset(real, line, line_char_offset);
250 invalidate_segment(GtkTextRealIter *iter)
252 iter->segments_changed_stamp -= 1;
256 invalidate_char_index(GtkTextRealIter *iter)
258 iter->cached_char_index = -1;
262 invalidate_line_number(GtkTextRealIter *iter)
264 iter->cached_line_number = -1;
268 adjust_char_index(GtkTextRealIter *iter, gint count)
270 if (iter->cached_char_index >= 0)
271 iter->cached_char_index += count;
275 adjust_line_number(GtkTextRealIter *iter, gint count)
277 if (iter->cached_line_number >= 0)
278 iter->cached_line_number += count;
282 adjust_char_offsets(GtkTextRealIter *iter, gint count)
284 if (iter->line_char_offset >= 0)
286 iter->line_char_offset += count;
287 g_assert(iter->segment_char_offset >= 0);
288 iter->segment_char_offset += count;
293 adjust_byte_offsets(GtkTextRealIter *iter, gint count)
295 if (iter->line_byte_offset >= 0)
297 iter->line_byte_offset += count;
298 g_assert(iter->segment_byte_offset >= 0);
299 iter->segment_byte_offset += count;
304 ensure_char_offsets(GtkTextRealIter *iter)
306 if (iter->line_char_offset < 0)
308 g_assert(iter->line_byte_offset >= 0);
310 gtk_text_line_byte_to_char_offsets(iter->line,
311 iter->line_byte_offset,
312 &iter->line_char_offset,
313 &iter->segment_char_offset);
318 ensure_byte_offsets(GtkTextRealIter *iter)
320 if (iter->line_byte_offset < 0)
322 g_assert(iter->line_char_offset >= 0);
324 gtk_text_line_char_to_byte_offsets(iter->line,
325 iter->line_char_offset,
326 &iter->line_byte_offset,
327 &iter->segment_byte_offset);
333 check_invariants(const GtkTextIter *iter)
335 if (gtk_debug_flags & GTK_DEBUG_TEXT)
336 gtk_text_iter_check(iter);
339 #define check_invariants(x)
343 gtk_text_iter_get_buffer(const GtkTextIter *iter)
345 GtkTextRealIter *real;
347 g_return_val_if_fail(iter != NULL, NULL);
349 real = gtk_text_iter_make_surreal(iter);
354 check_invariants(iter);
356 return gtk_text_btree_get_buffer(real->tree);
360 gtk_text_iter_copy(const GtkTextIter *iter)
362 GtkTextIter *new_iter;
364 g_return_val_if_fail(iter != NULL, NULL);
366 new_iter = g_new(GtkTextIter, 1);
374 gtk_text_iter_free(GtkTextIter *iter)
376 g_return_if_fail(iter != NULL);
382 gtk_text_iter_get_indexable_segment(const GtkTextIter *iter)
384 GtkTextRealIter *real;
386 g_return_val_if_fail(iter != NULL, 0);
388 real = gtk_text_iter_make_real(iter);
393 check_invariants(iter);
395 g_assert(real->segment != NULL);
397 return real->segment;
401 gtk_text_iter_get_any_segment(const GtkTextIter *iter)
403 GtkTextRealIter *real;
405 g_return_val_if_fail(iter != NULL, 0);
407 real = gtk_text_iter_make_real(iter);
412 check_invariants(iter);
414 g_assert(real->any_segment != NULL);
416 return real->any_segment;
420 gtk_text_iter_get_segment_byte(const GtkTextIter *iter)
422 GtkTextRealIter *real;
424 g_return_val_if_fail(iter != NULL, 0);
426 real = gtk_text_iter_make_real(iter);
431 ensure_byte_offsets(real);
433 check_invariants(iter);
435 return real->segment_byte_offset;
439 gtk_text_iter_get_segment_char(const GtkTextIter *iter)
441 GtkTextRealIter *real;
443 g_return_val_if_fail(iter != NULL, 0);
445 real = gtk_text_iter_make_real(iter);
450 ensure_char_offsets(real);
452 check_invariants(iter);
454 return real->segment_char_offset;
457 /* This function does not require a still-valid
460 gtk_text_iter_get_line(const GtkTextIter *iter)
462 const GtkTextRealIter *real;
464 g_return_val_if_fail(iter != NULL, 0);
466 real = (const GtkTextRealIter*)iter;
471 /* This function does not require a still-valid
474 gtk_text_iter_get_btree(const GtkTextIter *iter)
476 const GtkTextRealIter *real;
478 g_return_val_if_fail(iter != NULL, 0);
480 real = (const GtkTextRealIter*)iter;
490 gtk_text_iter_get_char_index(const GtkTextIter *iter)
492 GtkTextRealIter *real;
494 g_return_val_if_fail(iter != NULL, 0);
496 real = gtk_text_iter_make_surreal(iter);
501 if (real->cached_char_index < 0)
503 real->cached_char_index =
504 gtk_text_line_char_index(real->line);
505 ensure_char_offsets(real);
506 real->cached_char_index += real->line_char_offset;
509 check_invariants(iter);
511 return real->cached_char_index;
515 gtk_text_iter_get_line_number(const GtkTextIter *iter)
517 GtkTextRealIter *real;
519 g_return_val_if_fail(iter != NULL, 0);
521 real = gtk_text_iter_make_surreal(iter);
526 if (real->cached_line_number < 0)
527 real->cached_line_number =
528 gtk_text_line_get_number(real->line);
530 check_invariants(iter);
532 return real->cached_line_number;
536 gtk_text_iter_get_line_char(const GtkTextIter *iter)
539 GtkTextRealIter *real;
541 g_return_val_if_fail(iter != NULL, 0);
543 real = gtk_text_iter_make_surreal(iter);
548 ensure_char_offsets(real);
550 check_invariants(iter);
552 return real->line_char_offset;
556 gtk_text_iter_get_line_byte(const GtkTextIter *iter)
558 GtkTextRealIter *real;
560 g_return_val_if_fail(iter != NULL, 0);
562 real = gtk_text_iter_make_surreal(iter);
567 ensure_byte_offsets(real);
569 check_invariants(iter);
571 return real->line_byte_offset;
579 gtk_text_iter_get_char(const GtkTextIter *iter)
581 GtkTextRealIter *real;
583 g_return_val_if_fail(iter != NULL, 0);
585 real = gtk_text_iter_make_real(iter);
590 check_invariants(iter);
592 /* FIXME probably want to special-case the end iterator
593 and either have an error or return 0 */
595 if (real->segment->type == >k_text_char_type)
597 ensure_byte_offsets(real);
599 return g_utf8_get_char (real->segment->body.chars +
600 real->segment_byte_offset);
604 /* Unicode "unknown character" 0xFFFD */
605 return gtk_text_unknown_char;
610 gtk_text_iter_get_slice (const GtkTextIter *start,
611 const GtkTextIter *end)
613 g_return_val_if_fail(start != NULL, NULL);
614 g_return_val_if_fail(end != NULL, NULL);
616 check_invariants(start);
617 check_invariants(end);
619 return gtk_text_btree_get_text(start, end, TRUE, TRUE);
623 gtk_text_iter_get_text (const GtkTextIter *start,
624 const GtkTextIter *end)
626 g_return_val_if_fail(start != NULL, NULL);
627 g_return_val_if_fail(end != NULL, NULL);
629 check_invariants(start);
630 check_invariants(end);
632 return gtk_text_btree_get_text(start, end, TRUE, FALSE);
636 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
637 const GtkTextIter *end)
639 g_return_val_if_fail(start != NULL, NULL);
640 g_return_val_if_fail(end != NULL, NULL);
642 check_invariants(start);
643 check_invariants(end);
645 return gtk_text_btree_get_text(start, end, FALSE, TRUE);
649 gtk_text_iter_get_visible_text (const GtkTextIter *start,
650 const GtkTextIter *end)
652 g_return_val_if_fail(start != NULL, NULL);
653 g_return_val_if_fail(end != NULL, NULL);
655 check_invariants(start);
656 check_invariants(end);
658 return gtk_text_btree_get_text(start, end, FALSE, FALSE);
662 gtk_text_iter_get_pixmap (const GtkTextIter *iter,
666 GtkTextRealIter *real;
668 g_return_val_if_fail(iter != NULL, FALSE);
669 g_return_val_if_fail(pixmap != NULL, FALSE);
670 g_return_val_if_fail(mask != NULL, FALSE);
675 real = gtk_text_iter_make_real(iter);
680 check_invariants(iter);
682 if (real->segment->type != >k_text_pixmap_type)
686 *pixmap = real->segment->body.pixmap.pixmap;
687 *mask = real->segment->body.pixmap.pixmap;
694 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
697 GtkTextRealIter *real;
698 GtkTextLineSegment *seg;
701 g_return_val_if_fail(iter != NULL, NULL);
703 real = gtk_text_iter_make_real(iter);
708 check_invariants(iter);
711 seg = real->any_segment;
712 while (seg != real->segment)
716 if (seg->type == >k_text_toggle_on_type)
718 retval = g_slist_prepend(retval, seg->body.toggle.info->tag);
723 if (seg->type == >k_text_toggle_off_type)
725 retval = g_slist_prepend(retval, seg->body.toggle.info->tag);
732 /* The returned list isn't guaranteed to be in any special order,
738 gtk_text_iter_begins_tag (const GtkTextIter *iter,
741 GtkTextRealIter *real;
742 GtkTextLineSegment *seg;
744 g_return_val_if_fail(iter != NULL, FALSE);
746 real = gtk_text_iter_make_real(iter);
751 check_invariants(iter);
753 seg = real->any_segment;
754 while (seg != real->segment)
756 if (seg->type == >k_text_toggle_on_type)
759 seg->body.toggle.info->tag == tag)
770 gtk_text_iter_ends_tag (const GtkTextIter *iter,
773 GtkTextRealIter *real;
774 GtkTextLineSegment *seg;
776 g_return_val_if_fail(iter != NULL, FALSE);
778 real = gtk_text_iter_make_real(iter);
783 check_invariants(iter);
785 seg = real->any_segment;
786 while (seg != real->segment)
788 if (seg->type == >k_text_toggle_off_type)
791 seg->body.toggle.info->tag == tag)
802 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
805 GtkTextRealIter *real;
806 GtkTextLineSegment *seg;
808 g_return_val_if_fail(iter != NULL, FALSE);
810 real = gtk_text_iter_make_real(iter);
815 check_invariants(iter);
817 seg = real->any_segment;
818 while (seg != real->segment)
820 if ( (seg->type == >k_text_toggle_off_type ||
821 seg->type == >k_text_toggle_on_type) &&
823 seg->body.toggle.info->tag == tag) )
833 gtk_text_iter_has_tag (const GtkTextIter *iter,
836 GtkTextRealIter *real;
838 g_return_val_if_fail(iter != NULL, FALSE);
839 g_return_val_if_fail(GTK_IS_TEXT_TAG(tag), FALSE);
841 real = gtk_text_iter_make_surreal(iter);
846 check_invariants(iter);
848 if (real->line_byte_offset >= 0)
850 return gtk_text_line_byte_has_tag(real->line, real->tree,
851 real->line_byte_offset, tag);
855 g_assert(real->line_char_offset >= 0);
856 return gtk_text_line_char_has_tag(real->line, real->tree,
857 real->line_char_offset, tag);
862 gtk_text_iter_starts_line (const GtkTextIter *iter)
864 GtkTextRealIter *real;
866 g_return_val_if_fail(iter != NULL, FALSE);
868 real = gtk_text_iter_make_surreal(iter);
873 check_invariants(iter);
875 if (real->line_byte_offset >= 0)
877 return (real->line_byte_offset == 0);
881 g_assert(real->line_char_offset >= 0);
882 return (real->line_char_offset == 0);
887 gtk_text_iter_ends_line (const GtkTextIter *iter)
889 g_return_val_if_fail(iter != NULL, FALSE);
891 check_invariants(iter);
893 return gtk_text_iter_get_char(iter) == '\n';
897 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
899 GtkTextRealIter *real;
901 GtkTextLineSegment *seg;
903 g_return_val_if_fail(iter != NULL, FALSE);
905 real = gtk_text_iter_make_surreal(iter);
910 check_invariants(iter);
912 if (real->line_char_offset >= 0)
914 /* We can start at the segments we've already found. */
915 count = real->line_char_offset - real->segment_char_offset;
916 seg = gtk_text_iter_get_indexable_segment(iter);
920 /* count whole line. */
921 seg = real->line->segments;
928 count += seg->char_count;
937 * Increments/decrements
941 forward_line_leaving_caches_unmodified(GtkTextRealIter *real)
943 GtkTextLine *new_line;
945 new_line = gtk_text_line_next(real->line);
947 g_assert(new_line != real->line);
949 if (new_line != NULL)
951 real->line = new_line;
953 real->line_byte_offset = 0;
954 real->line_char_offset = 0;
956 real->segment_byte_offset = 0;
957 real->segment_char_offset = 0;
959 /* Find first segments in new line */
960 real->any_segment = real->line->segments;
961 real->segment = real->any_segment;
962 while (real->segment->char_count == 0)
963 real->segment = real->segment->next;
969 /* There is no way to move forward; we were already
970 at the "end" index. (the end index is the last
971 line pointer, segment_byte_offset of 0) */
973 g_assert(real->line_char_offset == 0 ||
974 real->line_byte_offset == 0);
976 /* The only indexable segment allowed on the bogus
977 line at the end is a single char segment containing
979 if (real->segments_changed_stamp ==
980 gtk_text_btree_get_segments_changed_stamp(real->tree))
982 g_assert(real->segment->type == >k_text_char_type);
983 g_assert(real->segment->char_count == 1);
985 /* We leave real->line as-is */
992 forward_char(GtkTextRealIter *real)
994 GtkTextIter *iter = (GtkTextIter*)real;
996 check_invariants((GtkTextIter*)real);
998 ensure_char_offsets(real);
1000 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1002 /* Need to move to the next segment; if no next segment,
1003 need to move to next line. */
1004 return gtk_text_iter_forward_indexable_segment(iter);
1008 /* Just moving within a segment. Keep byte count
1009 up-to-date, if it was already up-to-date. */
1011 g_assert(real->segment->type == >k_text_char_type);
1013 if (real->line_byte_offset >= 0)
1016 const char * start =
1017 real->segment->body.chars + real->segment_byte_offset;
1019 bytes = g_utf8_next_char (start) - start;
1021 real->line_byte_offset += bytes;
1022 real->segment_byte_offset += bytes;
1024 g_assert(real->segment_byte_offset < real->segment->byte_count);
1027 real->line_char_offset += 1;
1028 real->segment_char_offset += 1;
1030 adjust_char_index(real, 1);
1032 g_assert(real->segment_char_offset < real->segment->char_count);
1034 /* We moved into the middle of a segment, so the any_segment
1035 must now be the segment we're in the middle of. */
1036 real->any_segment = real->segment;
1038 check_invariants((GtkTextIter*)real);
1045 gtk_text_iter_forward_indexable_segment(GtkTextIter *iter)
1047 /* Need to move to the next segment; if no next segment,
1048 need to move to next line. */
1049 GtkTextLineSegment *seg;
1050 GtkTextLineSegment *any_seg;
1051 GtkTextRealIter *real;
1055 g_return_val_if_fail(iter != NULL, FALSE);
1057 real = gtk_text_iter_make_real(iter);
1062 check_invariants(iter);
1064 if (real->line_char_offset >= 0)
1066 chars_skipped = real->segment->char_count - real->segment_char_offset;
1067 g_assert(chars_skipped > 0);
1072 if (real->line_byte_offset >= 0)
1074 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1075 g_assert(bytes_skipped > 0);
1080 /* Get first segment of any kind */
1081 any_seg = real->segment->next;
1082 /* skip non-indexable segments, if any */
1084 while (seg != NULL && seg->char_count == 0)
1089 real->any_segment = any_seg;
1090 real->segment = seg;
1092 if (real->line_byte_offset >= 0)
1094 g_assert(bytes_skipped > 0);
1095 real->segment_byte_offset = 0;
1096 real->line_byte_offset += bytes_skipped;
1099 if (real->line_char_offset >= 0)
1101 g_assert(chars_skipped > 0);
1102 real->segment_char_offset = 0;
1103 real->line_char_offset += chars_skipped;
1104 adjust_char_index(real, chars_skipped);
1107 check_invariants(iter);
1113 /* End of the line */
1114 if (forward_line_leaving_caches_unmodified(real))
1116 adjust_line_number(real, 1);
1117 if (real->line_char_offset >= 0)
1118 adjust_char_index(real, chars_skipped);
1120 check_invariants(iter);
1122 g_assert(real->line_byte_offset == 0);
1123 g_assert(real->line_char_offset == 0);
1124 g_assert(real->segment_byte_offset == 0);
1125 g_assert(real->segment_char_offset == 0);
1126 g_assert(gtk_text_iter_starts_line(iter));
1128 check_invariants(iter);
1136 check_invariants(iter);
1144 gtk_text_iter_backward_indexable_segment(GtkTextIter *iter)
1151 gtk_text_iter_forward_char(GtkTextIter *iter)
1153 GtkTextRealIter *real;
1155 g_return_val_if_fail(iter != NULL, FALSE);
1157 real = gtk_text_iter_make_real(iter);
1163 check_invariants(iter);
1164 return forward_char(real);
1169 gtk_text_iter_backward_char(GtkTextIter *iter)
1171 g_return_val_if_fail(iter != NULL, FALSE);
1173 check_invariants(iter);
1175 return gtk_text_iter_backward_chars(iter, 1);
1179 Definitely we should try to linear scan as often as possible for
1180 movement within a single line, because we can't use the BTree to
1181 speed within-line searches up; for movement between lines, we would
1182 like to avoid the linear scan probably.
1184 Instead of using this constant, it might be nice to cache the line
1185 length in the iterator and linear scan if motion is within a single
1188 I guess you'd have to profile the various approaches.
1190 #define MAX_LINEAR_SCAN 300
1193 gtk_text_iter_forward_chars(GtkTextIter *iter, gint count)
1195 GtkTextRealIter *real;
1197 g_return_val_if_fail(iter != NULL, FALSE);
1199 real = gtk_text_iter_make_real(iter);
1203 else if (count == 0)
1206 return gtk_text_iter_backward_chars(iter, 0 - count);
1207 else if (count < MAX_LINEAR_SCAN)
1209 check_invariants(iter);
1213 if (!forward_char(real))
1218 return forward_char(real);
1222 gint current_char_index;
1223 gint new_char_index;
1225 check_invariants(iter);
1227 current_char_index = gtk_text_iter_get_char_index(iter);
1229 if (current_char_index == gtk_text_btree_char_count(real->tree))
1230 return FALSE; /* can't move forward */
1232 new_char_index = current_char_index + count;
1233 gtk_text_iter_set_char_index(iter, new_char_index);
1235 check_invariants(iter);
1242 gtk_text_iter_backward_chars(GtkTextIter *iter, gint count)
1244 GtkTextRealIter *real;
1246 g_return_val_if_fail(iter != NULL, FALSE);
1248 real = gtk_text_iter_make_real(iter);
1252 else if (count == 0)
1255 return gtk_text_iter_forward_chars(iter, 0 - count);
1257 ensure_char_offsets(real);
1258 check_invariants(iter);
1260 if (count <= real->segment_char_offset)
1262 /* Optimize the within-segment case */
1263 g_assert(real->segment->char_count > 0);
1264 g_assert(real->segment->type == >k_text_char_type);
1266 real->segment_char_offset -= count;
1267 g_assert(real->segment_char_offset >= 0);
1269 if (real->line_byte_offset >= 0)
1271 gint new_byte_offset;
1274 new_byte_offset = 0;
1276 while (i < real->segment_char_offset)
1278 const char * start = real->segment->body.chars + new_byte_offset;
1279 new_byte_offset += g_utf8_next_char (start) - start;
1284 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
1285 real->segment_byte_offset = new_byte_offset;
1288 real->line_char_offset -= count;
1290 adjust_char_index(real, 0 - count);
1292 check_invariants(iter);
1298 /* We need to go back into previous segments. For now,
1299 just keep this really simple. */
1300 gint current_char_index;
1301 gint new_char_index;
1303 current_char_index = gtk_text_iter_get_char_index(iter);
1305 if (current_char_index == 0)
1306 return FALSE; /* can't move backward */
1308 new_char_index = current_char_index - count;
1309 if (new_char_index < 0)
1311 gtk_text_iter_set_char_index(iter, new_char_index);
1313 check_invariants(iter);
1320 gtk_text_iter_forward_line(GtkTextIter *iter)
1322 GtkTextRealIter *real;
1324 g_return_val_if_fail(iter != NULL, FALSE);
1326 real = gtk_text_iter_make_real(iter);
1331 check_invariants(iter);
1333 if (forward_line_leaving_caches_unmodified(real))
1335 invalidate_char_index(real);
1336 adjust_line_number(real, 1);
1338 check_invariants(iter);
1344 check_invariants(iter);
1350 gtk_text_iter_backward_line(GtkTextIter *iter)
1352 GtkTextLine *new_line;
1353 GtkTextRealIter *real;
1354 gboolean offset_will_change;
1357 g_return_val_if_fail(iter != NULL, FALSE);
1359 real = gtk_text_iter_make_real(iter);
1364 check_invariants(iter);
1366 new_line = gtk_text_line_previous(real->line);
1368 offset_will_change = FALSE;
1369 if (real->line_char_offset > 0)
1370 offset_will_change = TRUE;
1372 if (new_line != NULL)
1374 real->line = new_line;
1376 adjust_line_number(real, -1);
1380 if (!offset_will_change)
1384 invalidate_char_index(real);
1386 real->line_byte_offset = 0;
1387 real->line_char_offset = 0;
1389 real->segment_byte_offset = 0;
1390 real->segment_char_offset = 0;
1392 /* Find first segment in line */
1393 real->any_segment = real->line->segments;
1394 real->segment = gtk_text_line_byte_to_segment(real->line,
1397 g_assert(offset == 0);
1399 /* Note that if we are on the first line, we snap to the start
1400 of the first line and return TRUE, so TRUE means the
1401 iterator changed, not that the line changed; this is maybe
1402 a bit weird. I'm not sure there's an obvious right thing
1405 check_invariants(iter);
1411 gtk_text_iter_forward_lines(GtkTextIter *iter, gint count)
1414 return gtk_text_iter_backward_lines(iter, 0 - count);
1415 else if (count == 0)
1417 else if (count == 1)
1419 check_invariants(iter);
1420 return gtk_text_iter_forward_line(iter);
1426 old_line = gtk_text_iter_get_line_number(iter);
1428 gtk_text_iter_set_line_number(iter, old_line + count);
1430 check_invariants(iter);
1432 return (gtk_text_iter_get_line_number(iter) != old_line);
1437 gtk_text_iter_backward_lines(GtkTextIter *iter, gint count)
1440 return gtk_text_iter_forward_lines(iter, 0 - count);
1441 else if (count == 0)
1443 else if (count == 1)
1445 return gtk_text_iter_backward_line(iter);
1451 old_line = gtk_text_iter_get_line_number(iter);
1453 gtk_text_iter_set_line_number(iter, MAX(old_line - count, 0));
1455 return (gtk_text_iter_get_line_number(iter) != old_line);
1460 is_word_char(gunichar ch, gpointer user_data)
1462 /* will likely need some i18n help FIXME */
1467 is_not_word_char(gunichar ch, gpointer user_data)
1469 return !is_word_char(ch, user_data);
1473 gtk_text_iter_is_in_word(const GtkTextIter *iter)
1477 ch = gtk_text_iter_get_char(iter);
1479 return is_word_char(ch, NULL);
1483 gtk_text_iter_forward_word_end(GtkTextIter *iter)
1488 g_return_val_if_fail(iter != NULL, FALSE);
1492 in_word = gtk_text_iter_is_in_word(iter);
1496 if (!gtk_text_iter_forward_find_char(iter, is_word_char, NULL))
1497 return !gtk_text_iter_equal(iter, &start);
1504 gtk_text_iter_forward_find_char(iter, is_not_word_char, NULL);
1506 return !gtk_text_iter_equal(iter, &start);
1510 gtk_text_iter_backward_word_start(GtkTextIter *iter)
1515 g_return_val_if_fail(iter != NULL, FALSE);
1519 in_word = gtk_text_iter_is_in_word(iter);
1523 if (!gtk_text_iter_backward_find_char(iter, is_word_char, NULL))
1524 return !gtk_text_iter_equal(iter, &start);
1531 gtk_text_iter_backward_find_char(iter, is_not_word_char, NULL);
1532 gtk_text_iter_forward_char(iter); /* point to first char of word,
1533 not first non-word char. */
1535 return !gtk_text_iter_equal(iter, &start);
1539 gtk_text_iter_forward_word_ends(GtkTextIter *iter,
1542 g_return_val_if_fail(iter != NULL, FALSE);
1543 g_return_val_if_fail(count > 0, FALSE);
1545 if (!gtk_text_iter_forward_word_end(iter))
1551 if (!gtk_text_iter_forward_word_end(iter))
1559 gtk_text_iter_backward_word_starts(GtkTextIter *iter,
1562 g_return_val_if_fail(iter != NULL, FALSE);
1563 g_return_val_if_fail(count > 0, FALSE);
1565 if (!gtk_text_iter_backward_word_start(iter))
1571 if (!gtk_text_iter_backward_word_start(iter))
1578 /* up/down lines maintain the char offset, while forward/backward lines
1579 always sets the char offset to 0. */
1581 gtk_text_iter_up_lines (GtkTextIter *iter,
1587 return gtk_text_iter_down_lines(iter, 0 - count);
1589 char_offset = gtk_text_iter_get_line_char(iter);
1591 if (!gtk_text_iter_backward_line(iter))
1597 if (!gtk_text_iter_backward_line(iter))
1602 gtk_text_iter_set_line_char(iter, char_offset);
1608 gtk_text_iter_down_lines (GtkTextIter *iter,
1614 return gtk_text_iter_up_lines(iter, 0 - count);
1616 char_offset = gtk_text_iter_get_line_char(iter);
1618 if (!gtk_text_iter_forward_line(iter))
1624 if (!gtk_text_iter_forward_line(iter))
1629 gtk_text_iter_set_line_char(iter, char_offset);
1635 gtk_text_iter_set_line_char(GtkTextIter *iter,
1638 GtkTextRealIter *real;
1640 g_return_if_fail(iter != NULL);
1642 real = gtk_text_iter_make_surreal(iter);
1647 check_invariants(iter);
1649 iter_set_from_char_offset(real, real->line, char_on_line);
1651 check_invariants(iter);
1655 gtk_text_iter_set_line_number(GtkTextIter *iter, gint line_number)
1659 GtkTextRealIter *real;
1661 g_return_if_fail(iter != NULL);
1663 real = gtk_text_iter_make_surreal(iter);
1668 check_invariants(iter);
1670 line = gtk_text_btree_get_line(real->tree, line_number, &real_line);
1672 iter_set_from_char_offset(real, line, 0);
1674 /* We might as well cache this, since we know it. */
1675 real->cached_line_number = real_line;
1677 check_invariants(iter);
1681 gtk_text_iter_set_char_index(GtkTextIter *iter, gint char_index)
1684 GtkTextRealIter *real;
1686 gint real_char_index;
1688 g_return_if_fail(iter != NULL);
1690 real = gtk_text_iter_make_surreal(iter);
1695 check_invariants(iter);
1697 if (real->cached_char_index >= 0 &&
1698 real->cached_char_index == char_index)
1701 line = gtk_text_btree_get_line_at_char(real->tree,
1706 iter_set_from_char_offset(real, line, real_char_index - line_start);
1708 /* Go ahead and cache this since we have it. */
1709 real->cached_char_index = real_char_index;
1711 check_invariants(iter);
1715 gtk_text_iter_forward_to_end (GtkTextIter *iter)
1717 GtkTextBuffer *buffer;
1718 GtkTextRealIter *real;
1720 g_return_if_fail(iter != NULL);
1722 real = gtk_text_iter_make_surreal(iter);
1727 buffer = gtk_text_btree_get_buffer(real->tree);
1729 gtk_text_buffer_get_last_iter(buffer, iter);
1733 gtk_text_iter_forward_to_newline(GtkTextIter *iter)
1735 gint current_offset;
1738 g_return_val_if_fail(iter != NULL, FALSE);
1740 current_offset = gtk_text_iter_get_line_char(iter);
1741 new_offset = gtk_text_iter_get_chars_in_line(iter) - 1;
1743 if (current_offset < new_offset)
1745 /* Move to end of this line. */
1746 gtk_text_iter_set_line_char(iter, new_offset);
1751 /* Move to end of next line. */
1752 if (gtk_text_iter_forward_line(iter))
1754 gtk_text_iter_forward_to_newline(iter);
1763 gtk_text_iter_forward_find_tag_toggle (GtkTextIter *iter,
1766 GtkTextLine *next_line;
1767 GtkTextLine *current_line;
1768 GtkTextRealIter *real;
1770 g_return_val_if_fail(iter != NULL, FALSE);
1772 real = gtk_text_iter_make_real(iter);
1777 check_invariants(iter);
1779 current_line = real->line;
1780 next_line = gtk_text_line_next_could_contain_tag(current_line,
1783 while (gtk_text_iter_forward_indexable_segment(iter))
1785 /* If we went forward to a line that couldn't contain a toggle
1786 for the tag, then skip forward to a line that could contain
1787 it. This potentially skips huge hunks of the tree, so we
1788 aren't a purely linear search. */
1789 if (real->line != current_line)
1791 if (next_line == NULL)
1793 /* End of search. Set to end of buffer. */
1794 gtk_text_btree_get_last_iter(real->tree, iter);
1798 if (real->line != next_line)
1799 iter_set_from_byte_offset(real, next_line, 0);
1801 current_line = real->line;
1802 next_line = gtk_text_line_next_could_contain_tag(current_line,
1807 if (gtk_text_iter_toggles_tag(iter, tag))
1809 /* If there's a toggle here, it isn't indexable so
1810 any_segment can't be the indexable segment. */
1811 g_assert(real->any_segment != real->segment);
1816 /* Reached end of buffer */
1821 gtk_text_iter_backward_find_tag_toggle (GtkTextIter *iter,
1829 matches_pred(GtkTextIter *iter,
1830 GtkTextViewCharPredicate pred,
1835 ch = gtk_text_iter_get_char(iter);
1837 return (*pred) (ch, user_data);
1841 gtk_text_iter_forward_find_char (GtkTextIter *iter,
1842 GtkTextViewCharPredicate pred,
1845 g_return_val_if_fail(iter != NULL, FALSE);
1846 g_return_val_if_fail(pred != NULL, FALSE);
1848 while (gtk_text_iter_forward_char(iter))
1850 if (matches_pred(iter, pred, user_data))
1858 gtk_text_iter_backward_find_char (GtkTextIter *iter,
1859 GtkTextViewCharPredicate pred,
1862 g_return_val_if_fail(iter != NULL, FALSE);
1863 g_return_val_if_fail(pred != NULL, FALSE);
1865 while (gtk_text_iter_backward_char(iter))
1867 if (matches_pred(iter, pred, user_data))
1879 gtk_text_iter_equal(const GtkTextIter *lhs, const GtkTextIter *rhs)
1881 GtkTextRealIter *real_lhs;
1882 GtkTextRealIter *real_rhs;
1884 real_lhs = (GtkTextRealIter*)lhs;
1885 real_rhs = (GtkTextRealIter*)rhs;
1887 check_invariants(lhs);
1888 check_invariants(rhs);
1890 if (real_lhs->line != real_rhs->line)
1892 else if (real_lhs->line_byte_offset >= 0 &&
1893 real_rhs->line_byte_offset >= 0)
1894 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
1897 /* the ensure_char_offsets() calls do nothing if the char offsets
1898 are already up-to-date. */
1899 ensure_char_offsets(real_lhs);
1900 ensure_char_offsets(real_rhs);
1901 return real_lhs->line_char_offset == real_rhs->line_char_offset;
1906 gtk_text_iter_compare(const GtkTextIter *lhs, const GtkTextIter *rhs)
1908 GtkTextRealIter *real_lhs;
1909 GtkTextRealIter *real_rhs;
1911 real_lhs = gtk_text_iter_make_surreal(lhs);
1912 real_rhs = gtk_text_iter_make_surreal(rhs);
1914 check_invariants(lhs);
1915 check_invariants(rhs);
1917 if (real_lhs == NULL ||
1919 return -1; /* why not */
1921 if (real_lhs->line == real_rhs->line)
1923 gint left_index, right_index;
1925 if (real_lhs->line_byte_offset >= 0 &&
1926 real_rhs->line_byte_offset >= 0)
1928 left_index = real_lhs->line_byte_offset;
1929 right_index = real_rhs->line_byte_offset;
1933 /* the ensure_char_offsets() calls do nothing if
1934 the offsets are already up-to-date. */
1935 ensure_char_offsets(real_lhs);
1936 ensure_char_offsets(real_rhs);
1937 left_index = real_lhs->line_char_offset;
1938 right_index = real_rhs->line_char_offset;
1941 if (left_index < right_index)
1943 else if (left_index > right_index)
1952 line1 = gtk_text_iter_get_line_number(lhs);
1953 line2 = gtk_text_iter_get_line_number(rhs);
1956 else if (line1 > line2)
1964 gtk_text_iter_in_region (const GtkTextIter *iter,
1965 const GtkTextIter *start,
1966 const GtkTextIter *end)
1968 return gtk_text_iter_compare(iter, start) >= 0 &&
1969 gtk_text_iter_compare(iter, end) < 0;
1973 gtk_text_iter_reorder (GtkTextIter *first,
1974 GtkTextIter *second)
1976 g_return_if_fail(first != NULL);
1977 g_return_if_fail(second != NULL);
1979 if (gtk_text_iter_compare(first, second) > 0)
1990 * Init iterators from the BTree
1994 gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
1998 GtkTextRealIter *real = (GtkTextRealIter*)iter;
1999 gint real_char_index;
2003 g_return_if_fail(iter != NULL);
2004 g_return_if_fail(tree != NULL);
2006 line = gtk_text_btree_get_line_at_char(tree, char_index,
2007 &line_start, &real_char_index);
2009 iter_init_from_char_offset(iter, tree, line, real_char_index - line_start);
2011 real->cached_char_index = real_char_index;
2013 check_invariants(iter);
2017 gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
2022 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2026 g_return_if_fail(iter != NULL);
2027 g_return_if_fail(tree != NULL);
2029 line = gtk_text_btree_get_line(tree, line_number, &real_line);
2031 iter_init_from_char_offset(iter, tree, line, char_on_line);
2033 /* We might as well cache this, since we know it. */
2034 real->cached_line_number = real_line;
2036 check_invariants(iter);
2040 gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
2045 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2049 g_return_if_fail(iter != NULL);
2050 g_return_if_fail(tree != NULL);
2052 line = gtk_text_btree_get_line(tree, line_number, &real_line);
2054 iter_init_from_byte_offset(iter, tree, line, byte_index);
2056 /* We might as well cache this, since we know it. */
2057 real->cached_line_number = real_line;
2059 check_invariants(iter);
2063 gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
2068 g_return_if_fail(iter != NULL);
2069 g_return_if_fail(tree != NULL);
2070 g_return_if_fail(line != NULL);
2072 iter_init_from_byte_offset(iter, tree, line, byte_offset);
2074 check_invariants(iter);
2078 gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
2084 g_return_val_if_fail(iter != NULL, FALSE);
2085 g_return_val_if_fail(tree != NULL, FALSE);
2087 line = gtk_text_btree_first_could_contain_tag(tree, tag);
2091 /* Set iter to last in tree */
2092 gtk_text_btree_get_last_iter(tree, iter);
2093 check_invariants(iter);
2098 iter_init_from_byte_offset(iter, tree, line, 0);
2099 gtk_text_iter_forward_find_tag_toggle(iter, tag);
2100 check_invariants(iter);
2106 gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
2112 g_return_val_if_fail(iter != NULL, FALSE);
2113 g_return_val_if_fail(tree != NULL, FALSE);
2115 line = gtk_text_btree_last_could_contain_tag(tree, tag);
2119 /* Set iter to first in tree */
2120 gtk_text_btree_get_iter_at_line_char(tree, iter, 0, 0);
2121 check_invariants(iter);
2126 iter_init_from_byte_offset(iter, tree, line, -1);
2127 gtk_text_iter_backward_find_tag_toggle(iter, tag);
2128 check_invariants(iter);
2134 gtk_text_btree_get_iter_from_string (GtkTextBTree *tree,
2136 const gchar *string)
2138 g_return_val_if_fail(iter != NULL, FALSE);
2139 g_return_val_if_fail(tree != NULL, FALSE);
2145 gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
2147 const gchar *mark_name)
2151 g_return_val_if_fail(iter != NULL, FALSE);
2152 g_return_val_if_fail(tree != NULL, FALSE);
2154 mark = gtk_text_btree_get_mark_by_name(tree, mark_name);
2160 gtk_text_btree_get_iter_at_mark(tree, iter, mark);
2161 check_invariants(iter);
2167 gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
2171 GtkTextLineSegment *seg = (GtkTextLineSegment*) mark;
2173 g_return_if_fail(iter != NULL);
2174 g_return_if_fail(tree != NULL);
2175 g_return_if_fail(GTK_IS_TEXT_MARK (mark));
2177 iter_init_from_segment(iter, tree,
2178 seg->body.mark.line, seg);
2179 g_assert(seg->body.mark.line == gtk_text_iter_get_line(iter));
2180 check_invariants(iter);
2184 gtk_text_btree_get_last_iter (GtkTextBTree *tree,
2187 g_return_if_fail(iter != NULL);
2188 g_return_if_fail(tree != NULL);
2190 gtk_text_btree_get_iter_at_char(tree,
2192 gtk_text_btree_char_count(tree));
2193 check_invariants(iter);
2197 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
2199 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2201 g_return_if_fail(iter != NULL);
2203 if (real->chars_changed_stamp != gtk_text_btree_get_chars_changed_stamp(real->tree))
2204 g_print(" %20s: <invalidated iterator>\n", desc);
2207 check_invariants(iter);
2208 g_print(" %20s: line %d / char %d / line char %d / line byte %d\n",
2210 gtk_text_iter_get_line_number(iter),
2211 gtk_text_iter_get_char_index(iter),
2212 gtk_text_iter_get_line_char(iter),
2213 gtk_text_iter_get_line_byte(iter));
2214 check_invariants(iter);
2219 gtk_text_iter_check(const GtkTextIter *iter)
2221 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
2222 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
2223 GtkTextLineSegment *byte_segment;
2224 GtkTextLineSegment *byte_any_segment;
2225 GtkTextLineSegment *char_segment;
2226 GtkTextLineSegment *char_any_segment;
2227 gboolean segments_updated;
2229 /* We are going to check our class invariants for the Iter class. */
2231 if (real->chars_changed_stamp !=
2232 gtk_text_btree_get_chars_changed_stamp(real->tree))
2233 g_error("iterator check failed: invalid iterator");
2235 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
2236 g_error("iterator check failed: both char and byte offsets are invalid");
2238 segments_updated = (real->segments_changed_stamp ==
2239 gtk_text_btree_get_segments_changed_stamp(real->tree));
2242 printf("checking iter, segments %s updated, byte %d char %d\n",
2243 segments_updated ? "are" : "aren't",
2244 real->line_byte_offset,
2245 real->line_char_offset);
2248 if (real->line_byte_offset == 97 &&
2249 real->line_char_offset == 95)
2252 if (segments_updated)
2254 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
2255 g_error("iterator check failed: both char and byte segment offsets are invalid");
2257 if (real->segment->char_count == 0)
2258 g_error("iterator check failed: segment is not indexable.");
2260 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
2261 g_error("segment char offset is not properly up-to-date");
2263 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
2264 g_error("segment byte offset is not properly up-to-date");
2266 if (real->segment_byte_offset >= 0 &&
2267 real->segment_byte_offset >= real->segment->byte_count)
2268 g_error("segment byte offset is too large.");
2270 if (real->segment_char_offset >= 0 &&
2271 real->segment_char_offset >= real->segment->char_count)
2272 g_error("segment char offset is too large.");
2275 if (real->line_byte_offset >= 0)
2277 gtk_text_line_byte_locate(real->line, real->line_byte_offset,
2278 &byte_segment, &byte_any_segment,
2279 &seg_byte_offset, &line_byte_offset);
2281 if (line_byte_offset != real->line_byte_offset)
2282 g_error("wrong byte offset was stored in iterator");
2284 if (segments_updated)
2286 if (real->segment != byte_segment)
2287 g_error("wrong segment was stored in iterator");
2289 if (real->any_segment != byte_any_segment)
2290 g_error("wrong any_segment was stored in iterator");
2292 if (seg_byte_offset != real->segment_byte_offset)
2293 g_error("wrong segment byte offset was stored in iterator");
2297 if (real->line_char_offset >= 0)
2299 gtk_text_line_char_locate(real->line, real->line_char_offset,
2300 &char_segment, &char_any_segment,
2301 &seg_char_offset, &line_char_offset);
2303 if (line_char_offset != real->line_char_offset)
2304 g_error("wrong char offset was stored in iterator");
2306 if (segments_updated)
2308 if (real->segment != char_segment)
2309 g_error("wrong segment was stored in iterator");
2311 if (real->any_segment != char_any_segment)
2312 g_error("wrong any_segment was stored in iterator");
2314 if (seg_char_offset != real->segment_char_offset)
2315 g_error("wrong segment char offset was stored in iterator");
2319 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
2321 if (byte_segment != char_segment)
2322 g_error("char and byte offsets did not point to the same segment");
2324 if (byte_any_segment != char_any_segment)
2325 g_error("char and byte offsets did not point to the same any segment");
2327 /* Make sure the segment offsets are equivalent, if it's a char
2329 if (char_segment->type == >k_text_char_type)
2331 gint byte_offset = 0;
2332 gint char_offset = 0;
2333 while (char_offset < seg_char_offset)
2335 const char * start = char_segment->body.chars + byte_offset;
2336 byte_offset += g_utf8_next_char (start) - start;
2340 if (byte_offset != seg_byte_offset)
2341 g_error("byte offset did not correspond to char offset");
2344 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
2346 if (char_offset != seg_char_offset)
2347 g_error("char offset did not correspond to byte offset");
2351 if (real->cached_line_number >= 0)
2355 should_be = gtk_text_line_get_number(real->line);
2356 if (real->cached_line_number != should_be)
2357 g_error("wrong line number was cached");
2360 if (real->cached_char_index >= 0)
2362 if (real->line_char_offset >= 0) /* only way we can check it
2363 efficiently, not a real
2368 char_index = gtk_text_line_char_index(real->line);
2369 char_index += real->line_char_offset;
2371 if (real->cached_char_index != char_index)
2372 g_error("wrong char index was cached");