1 #include "gtktextiter.h"
2 #include "gtktextbtree.h"
3 #include "gtktextiterprivate.h"
8 typedef struct _GtkTextRealIter GtkTextRealIter;
10 struct _GtkTextRealIter {
11 /* Always-valid information */
14 /* At least one of these is always valid;
15 if invalid, they are -1.
17 If the line byte offset is valid, so is the segment byte offset;
18 and ditto for char offsets. */
19 gint line_byte_offset;
20 gint line_char_offset;
21 /* These two are valid if >= 0 */
22 gint cached_char_index;
23 gint cached_line_number;
24 /* Stamps to detect the buffer changing under us */
25 gint chars_changed_stamp;
26 gint segments_changed_stamp;
27 /* Valid if the segments_changed_stamp is up-to-date */
28 GtkTextLineSegment *segment; /* indexable segment we index */
29 GtkTextLineSegment *any_segment; /* first segment in our location,
30 maybe same as "segment" */
31 /* One of these will always be valid if segments_changed_stamp is
32 up-to-date. If invalid, they are -1.
34 If the line byte offset is valid, so is the segment byte offset;
35 and ditto for char offsets. */
36 gint segment_byte_offset;
37 gint segment_char_offset;
38 /* Pads are here for binary-compatible expansion space. */
43 /* These "set" functions should not assume any fields
44 other than the char stamp and the tree are valid.
47 iter_set_common(GtkTextRealIter *iter,
50 /* Update segments stamp */
51 iter->segments_changed_stamp =
52 gtk_text_btree_get_segments_changed_stamp(iter->tree);
56 iter->line_byte_offset = -1;
57 iter->line_char_offset = -1;
58 iter->segment_byte_offset = -1;
59 iter->segment_char_offset = -1;
60 iter->cached_char_index = -1;
61 iter->cached_line_number = -1;
65 iter_set_from_byte_offset(GtkTextRealIter *iter,
69 iter_set_common(iter, line);
71 gtk_text_line_byte_locate(iter->line,
75 &iter->segment_byte_offset,
76 &iter->line_byte_offset);
81 iter_set_from_char_offset(GtkTextRealIter *iter,
85 iter_set_common(iter, line);
87 gtk_text_line_char_locate(iter->line,
91 &iter->segment_char_offset,
92 &iter->line_char_offset);
96 iter_set_from_segment(GtkTextRealIter *iter,
98 GtkTextLineSegment *segment)
100 GtkTextLineSegment *seg;
103 /* This could theoretically be optimized by computing all the iter
104 fields in this same loop, but I'm skipping it for now. */
106 seg = line->segments;
107 while (seg != segment)
109 byte_offset += seg->byte_count;
113 iter_set_from_byte_offset(iter, line, byte_offset);
116 /* This function ensures that the segment-dependent information is
117 truly computed lazily; often we don't need to do the full make_real
118 work. This ensures the btree and line are valid, but doesn't
119 update the segments. */
120 static GtkTextRealIter*
121 gtk_text_iter_make_surreal(const GtkTextIter *_iter)
123 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
125 if (iter->chars_changed_stamp !=
126 gtk_text_btree_get_chars_changed_stamp(iter->tree))
128 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.");
132 /* We don't update the segments information since we are becoming
133 only surreal. However we do invalidate the segments information
134 if appropriate, to be sure we segfault if we try to use it and we
135 should have used make_real. */
137 if (iter->segments_changed_stamp !=
138 gtk_text_btree_get_segments_changed_stamp(iter->tree))
140 iter->segment = NULL;
141 iter->any_segment = NULL;
142 /* set to segfault-causing values. */
143 iter->segment_byte_offset = -10000;
144 iter->segment_char_offset = -10000;
150 static GtkTextRealIter*
151 gtk_text_iter_make_real(const GtkTextIter *_iter)
153 GtkTextRealIter *iter;
155 iter = gtk_text_iter_make_surreal(_iter);
157 if (iter->segments_changed_stamp !=
158 gtk_text_btree_get_segments_changed_stamp(iter->tree))
160 if (iter->line_byte_offset >= 0)
162 iter_set_from_byte_offset(iter,
164 iter->line_byte_offset);
168 g_assert(iter->line_char_offset >= 0);
170 iter_set_from_char_offset(iter,
172 iter->line_char_offset);
176 g_assert(iter->segment != NULL);
177 g_assert(iter->any_segment != NULL);
178 g_assert(iter->segment->char_count > 0);
183 static GtkTextRealIter*
184 iter_init_common(GtkTextIter *_iter,
187 GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
189 g_return_val_if_fail(iter != NULL, NULL);
190 g_return_val_if_fail(tree != NULL, NULL);
194 iter->chars_changed_stamp =
195 gtk_text_btree_get_chars_changed_stamp(iter->tree);
200 static GtkTextRealIter*
201 iter_init_from_segment(GtkTextIter *iter,
204 GtkTextLineSegment *segment)
206 GtkTextRealIter *real;
208 g_return_val_if_fail(line != NULL, NULL);
210 real = iter_init_common(iter, tree);
212 iter_set_from_segment(real, line, segment);
217 static GtkTextRealIter*
218 iter_init_from_byte_offset(GtkTextIter *iter,
221 gint line_byte_offset)
223 GtkTextRealIter *real;
225 g_return_val_if_fail(line != NULL, NULL);
227 real = iter_init_common(iter, tree);
229 iter_set_from_byte_offset(real, line, line_byte_offset);
234 static GtkTextRealIter*
235 iter_init_from_char_offset(GtkTextIter *iter,
238 gint line_char_offset)
240 GtkTextRealIter *real;
242 g_return_val_if_fail(line != NULL, NULL);
244 real = iter_init_common(iter, tree);
246 iter_set_from_char_offset(real, line, line_char_offset);
252 invalidate_segment(GtkTextRealIter *iter)
254 iter->segments_changed_stamp -= 1;
258 invalidate_char_index(GtkTextRealIter *iter)
260 iter->cached_char_index = -1;
264 invalidate_line_number(GtkTextRealIter *iter)
266 iter->cached_line_number = -1;
270 adjust_char_index(GtkTextRealIter *iter, gint count)
272 if (iter->cached_char_index >= 0)
273 iter->cached_char_index += count;
277 adjust_line_number(GtkTextRealIter *iter, gint count)
279 if (iter->cached_line_number >= 0)
280 iter->cached_line_number += count;
284 adjust_char_offsets(GtkTextRealIter *iter, gint count)
286 if (iter->line_char_offset >= 0)
288 iter->line_char_offset += count;
289 g_assert(iter->segment_char_offset >= 0);
290 iter->segment_char_offset += count;
295 adjust_byte_offsets(GtkTextRealIter *iter, gint count)
297 if (iter->line_byte_offset >= 0)
299 iter->line_byte_offset += count;
300 g_assert(iter->segment_byte_offset >= 0);
301 iter->segment_byte_offset += count;
306 ensure_char_offsets(GtkTextRealIter *iter)
308 if (iter->line_char_offset < 0)
310 g_assert(iter->line_byte_offset >= 0);
312 gtk_text_line_byte_to_char_offsets(iter->line,
313 iter->line_byte_offset,
314 &iter->line_char_offset,
315 &iter->segment_char_offset);
320 ensure_byte_offsets(GtkTextRealIter *iter)
322 if (iter->line_byte_offset < 0)
324 g_assert(iter->line_char_offset >= 0);
326 gtk_text_line_char_to_byte_offsets(iter->line,
327 iter->line_char_offset,
328 &iter->line_byte_offset,
329 &iter->segment_byte_offset);
335 check_invariants(const GtkTextIter *iter)
337 if (gtk_debug_flags & GTK_DEBUG_TEXT)
338 gtk_text_iter_check(iter);
341 #define check_invariants(x)
345 * gtk_text_iter_get_buffer:
348 * Return the #GtkTextBuffer this iterator is associated with
350 * Return value: the buffer
353 gtk_text_iter_get_buffer(const GtkTextIter *iter)
355 GtkTextRealIter *real;
357 g_return_val_if_fail(iter != NULL, NULL);
359 real = gtk_text_iter_make_surreal(iter);
364 check_invariants(iter);
366 return gtk_text_btree_get_buffer(real->tree);
370 * gtk_text_iter_copy:
373 * Create a dynamically-allocated copy of an iterator. This function
374 * is not useful in applications, because iterators can be copied with a
375 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
376 * function is used by language bindings.
378 * Return value: a copy of the @iter, free with gtk_text_iter_free()
381 gtk_text_iter_copy(const GtkTextIter *iter)
383 GtkTextIter *new_iter;
385 g_return_val_if_fail(iter != NULL, NULL);
387 new_iter = g_new(GtkTextIter, 1);
395 * gtk_text_iter_free:
396 * @iter: a dynamically-allocated iterator
398 * Free an iterator allocated on the heap. This function
399 * is intended for use in language bindings, and is not
400 * especially useful for applications, because iterators can
401 * simply be allocated on the stack.
405 gtk_text_iter_free(GtkTextIter *iter)
407 g_return_if_fail(iter != NULL);
413 gtk_text_iter_get_indexable_segment(const GtkTextIter *iter)
415 GtkTextRealIter *real;
417 g_return_val_if_fail(iter != NULL, 0);
419 real = gtk_text_iter_make_real(iter);
424 check_invariants(iter);
426 g_assert(real->segment != NULL);
428 return real->segment;
432 gtk_text_iter_get_any_segment(const GtkTextIter *iter)
434 GtkTextRealIter *real;
436 g_return_val_if_fail(iter != NULL, 0);
438 real = gtk_text_iter_make_real(iter);
443 check_invariants(iter);
445 g_assert(real->any_segment != NULL);
447 return real->any_segment;
451 gtk_text_iter_get_segment_byte(const GtkTextIter *iter)
453 GtkTextRealIter *real;
455 g_return_val_if_fail(iter != NULL, 0);
457 real = gtk_text_iter_make_real(iter);
462 ensure_byte_offsets(real);
464 check_invariants(iter);
466 return real->segment_byte_offset;
470 gtk_text_iter_get_segment_char(const GtkTextIter *iter)
472 GtkTextRealIter *real;
474 g_return_val_if_fail(iter != NULL, 0);
476 real = gtk_text_iter_make_real(iter);
481 ensure_char_offsets(real);
483 check_invariants(iter);
485 return real->segment_char_offset;
488 /* This function does not require a still-valid
491 gtk_text_iter_get_text_line(const GtkTextIter *iter)
493 const GtkTextRealIter *real;
495 g_return_val_if_fail(iter != NULL, 0);
497 real = (const GtkTextRealIter*)iter;
502 /* This function does not require a still-valid
505 gtk_text_iter_get_btree(const GtkTextIter *iter)
507 const GtkTextRealIter *real;
509 g_return_val_if_fail(iter != NULL, 0);
511 real = (const GtkTextRealIter*)iter;
521 * gtk_text_iter_get_offset:
524 * Returns the character offset of an iterator.
525 * Each character in a #GtkTextBuffer has an offset,
526 * starting with 0 for the first character in the buffer.
527 * Use gtk_text_buffer_get_iter_at_offset() to convert an
528 * offset back into an iterator.
530 * Return value: a character offset
533 gtk_text_iter_get_offset(const GtkTextIter *iter)
535 GtkTextRealIter *real;
537 g_return_val_if_fail(iter != NULL, 0);
539 real = gtk_text_iter_make_surreal(iter);
544 if (real->cached_char_index < 0)
546 real->cached_char_index =
547 gtk_text_line_char_index(real->line);
548 ensure_char_offsets(real);
549 real->cached_char_index += real->line_char_offset;
552 check_invariants(iter);
554 return real->cached_char_index;
558 * gtk_text_iter_get_line:
561 * Returns the line number containing the iterator. Lines in
562 * a #GtkTextBuffer are numbered beginning with 0 for the first
563 * line in the buffer.
565 * Return value: a line number
568 gtk_text_iter_get_line(const GtkTextIter *iter)
570 GtkTextRealIter *real;
572 g_return_val_if_fail(iter != NULL, 0);
574 real = gtk_text_iter_make_surreal(iter);
579 if (real->cached_line_number < 0)
580 real->cached_line_number =
581 gtk_text_line_get_number(real->line);
583 check_invariants(iter);
585 return real->cached_line_number;
589 * gtk_text_iter_get_line_offset:
592 * Returns the character offset of the iterator,
593 * counting from the start of a newline-terminated line.
594 * The first character on the line has offset 0.
596 * Return value: offset from start of line
599 gtk_text_iter_get_line_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 ensure_char_offsets(real);
613 check_invariants(iter);
615 return real->line_char_offset;
619 * gtk_text_iter_get_line_index:
622 * Returns the byte index of the iterator, counting
623 * from the start of a newline-terminated line.
624 * Remember that #GtkTextBuffer encodes text in
625 * UTF-8, and that characters can require a variable
626 * number of bytes to represent.
628 * Return value: distance from start of line, in bytes
631 gtk_text_iter_get_line_index(const GtkTextIter *iter)
633 GtkTextRealIter *real;
635 g_return_val_if_fail(iter != NULL, 0);
637 real = gtk_text_iter_make_surreal(iter);
642 ensure_byte_offsets(real);
644 check_invariants(iter);
646 return real->line_byte_offset;
654 * gtk_text_iter_get_char:
657 * Returns the Unicode character at this iterator. (Equivalent to
658 * operator* on a C++ iterator.) If the iterator points at a
659 * non-character element, such as an image embedded in the buffer, the
660 * Unicode "unknown" character 0xFFFD is returned.
662 * Return value: a Unicode character
665 gtk_text_iter_get_char(const GtkTextIter *iter)
667 GtkTextRealIter *real;
669 g_return_val_if_fail(iter != NULL, 0);
671 real = gtk_text_iter_make_real(iter);
676 check_invariants(iter);
678 /* FIXME probably want to special-case the end iterator
679 and either have an error or return 0 */
681 if (real->segment->type == >k_text_char_type)
683 ensure_byte_offsets(real);
685 return g_utf8_get_char (real->segment->body.chars +
686 real->segment_byte_offset);
690 /* Unicode "unknown character" 0xFFFD */
691 return gtk_text_unknown_char;
696 * gtk_text_iter_get_slice:
697 * @start: iterator at start of a range
698 * @end: iterator at end of a range
700 * Returns the text in the given range. A "slice" is an array of
701 * characters encoded in UTF-8 format, including the Unicode "unknown"
702 * character 0xFFFD for iterable non-character elements in the buffer,
703 * such as images. Because images are encoded in the slice, byte and
704 * character offsets in the returned array will correspond to byte
705 * offsets in the text buffer.
707 * Return value: slice of text from the buffer
710 gtk_text_iter_get_slice (const GtkTextIter *start,
711 const GtkTextIter *end)
713 g_return_val_if_fail(start != NULL, NULL);
714 g_return_val_if_fail(end != NULL, NULL);
716 check_invariants(start);
717 check_invariants(end);
719 return gtk_text_btree_get_text(start, end, TRUE, TRUE);
723 * gtk_text_iter_get_text:
724 * @start: iterator at start of a range
725 * @end: iterator at end of a range
727 * Returns <emphasis>text</emphasis> in the given range. If the range
728 * contains non-text elements such as images, the character and byte
729 * offsets in the returned string will not correspond to character and
730 * byte offsets in the buffer. If you want offsets to correspond, see
731 * gtk_text_iter_get_slice().
733 * Return value: array of characters from the buffer
736 gtk_text_iter_get_text (const GtkTextIter *start,
737 const GtkTextIter *end)
739 g_return_val_if_fail(start != NULL, NULL);
740 g_return_val_if_fail(end != NULL, NULL);
742 check_invariants(start);
743 check_invariants(end);
745 return gtk_text_btree_get_text(start, end, TRUE, FALSE);
749 * gtk_text_iter_get_visible_slice:
750 * @start: iterator at start of range
751 * @end: iterator at end of range
753 * Like gtk_text_iter_get_slice(), but invisible text is not included.
754 * Invisible text is usually invisible because a #GtkTextTag with the
755 * "invisible" attribute turned on has been applied to it.
757 * Return value: slice of text from the buffer
760 gtk_text_iter_get_visible_slice (const GtkTextIter *start,
761 const GtkTextIter *end)
763 g_return_val_if_fail(start != NULL, NULL);
764 g_return_val_if_fail(end != NULL, NULL);
766 check_invariants(start);
767 check_invariants(end);
769 return gtk_text_btree_get_text(start, end, FALSE, TRUE);
773 * gtk_text_iter_get_visible_text:
774 * @start: iterator at start of range
775 * @end: iterator at end of range
777 * Like gtk_text_iter_get_text(), but invisible text is not included.
778 * Invisible text is usually invisible because a #GtkTextTag with the
779 * "invisible" attribute turned on has been applied to it.
781 * Return value: string containing visible text in the range
784 gtk_text_iter_get_visible_text (const GtkTextIter *start,
785 const GtkTextIter *end)
787 g_return_val_if_fail(start != NULL, NULL);
788 g_return_val_if_fail(end != NULL, NULL);
790 check_invariants(start);
791 check_invariants(end);
793 return gtk_text_btree_get_text(start, end, FALSE, FALSE);
797 * gtk_text_iter_get_pixmap:
799 * @pixmap: return location for the pixmap
800 * @mask: return location for the mask
802 * If the location pointed to by @iter contains a pixmap, the pixmap
803 * is placed in @pixmap, the mask is placed in @mask, and
804 * gtk_text_iter_get_pixmap() returns TRUE. If @iter points at
805 * something else, FALSE will be returned and @pixmap/@mask will
806 * remain unchanged. The pixmap and mask do not have their reference
807 * count incremented. If the pixmap has no mask, NULL is returned for
810 * Return value: whether the iterator pointed at a pixmap
813 gtk_text_iter_get_pixmap (const GtkTextIter *iter,
817 GtkTextRealIter *real;
819 g_return_val_if_fail(iter != NULL, FALSE);
820 g_return_val_if_fail(pixmap != NULL, FALSE);
821 g_return_val_if_fail(mask != NULL, FALSE);
826 real = gtk_text_iter_make_real(iter);
831 check_invariants(iter);
833 if (real->segment->type != >k_text_pixmap_type)
838 *pixmap = real->segment->body.pixmap.pixmap;
840 *mask = real->segment->body.pixmap.pixmap;
847 * gtk_text_iter_get_marks:
850 * Returns a list of all #GtkTextMark at this location. Because marks
851 * are not iterable (they don't take up any "space" in the buffer,
852 * they are just marks in between iterable locations), multiple marks
853 * can exist in the same place. The returned list is not in any
856 * Return value: list of #GtkTextMark
859 gtk_text_iter_get_marks (const GtkTextIter *iter)
861 GtkTextRealIter *real;
862 GtkTextLineSegment *seg;
865 g_return_val_if_fail(iter != NULL, NULL);
867 real = gtk_text_iter_make_real(iter);
872 check_invariants(iter);
875 seg = real->any_segment;
876 while (seg != real->segment)
878 if (seg->type == >k_text_left_mark_type ||
879 seg->type == >k_text_right_mark_type)
880 retval = g_slist_prepend(retval, (GtkTextMark*)seg);
885 /* The returned list isn't guaranteed to be in any special order,
891 * gtk_text_iter_get_toggled_tags:
893 * @toggled_on: TRUE to get toggled-on tags
895 * Returns a list of #GtkTextTag that are toggled on or off at this
896 * point. (If @toggled_on is TRUE, the list contains tags that are
897 * toggled on.) If a tag is toggled on at @iter, then some non-empty
898 * range of characters following @iter has that tag applied to it. If
899 * a tag is toggled off, then some non-empty range following @iter
900 * does <emphasis>not</emphasis> have the tag applied to it.
902 * Return value: tags toggled at this point
905 gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
908 GtkTextRealIter *real;
909 GtkTextLineSegment *seg;
912 g_return_val_if_fail(iter != NULL, NULL);
914 real = gtk_text_iter_make_real(iter);
919 check_invariants(iter);
922 seg = real->any_segment;
923 while (seg != real->segment)
927 if (seg->type == >k_text_toggle_on_type)
929 retval = g_slist_prepend(retval, seg->body.toggle.info->tag);
934 if (seg->type == >k_text_toggle_off_type)
936 retval = g_slist_prepend(retval, seg->body.toggle.info->tag);
943 /* The returned list isn't guaranteed to be in any special order,
949 * gtk_text_iter_begins_tag:
951 * @tag: a #GtkTextTag, or NULL
953 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
954 * is NULL, returns TRUE if any tag is toggled on at this point. Note
955 * that the gtk_text_iter_begins_tag() returns TRUE if @iter is the
956 * <emphasis>start</emphasis> of the tagged range;
957 * gtk_text_iter_has_tag() tells you whether an iterator is
958 * <emphasis>within</emphasis> a tagged range.
960 * Return value: whether @iter is the start of a range tagged with @tag
963 gtk_text_iter_begins_tag (const GtkTextIter *iter,
966 GtkTextRealIter *real;
967 GtkTextLineSegment *seg;
969 g_return_val_if_fail(iter != NULL, FALSE);
971 real = gtk_text_iter_make_real(iter);
976 check_invariants(iter);
978 seg = real->any_segment;
979 while (seg != real->segment)
981 if (seg->type == >k_text_toggle_on_type)
984 seg->body.toggle.info->tag == tag)
995 * gtk_text_iter_ends_tag:
997 * @tag: a #GtkTextTag, or NULL
999 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
1000 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1001 * that the gtk_text_iter_ends_tag() returns TRUE if @iter is the
1002 * <emphasis>end</emphasis> of the tagged range;
1003 * gtk_text_iter_has_tag() tells you whether an iterator is
1004 * <emphasis>within</emphasis> a tagged range.
1006 * Return value: whether @iter is the end of a range tagged with @tag
1010 gtk_text_iter_ends_tag (const GtkTextIter *iter,
1013 GtkTextRealIter *real;
1014 GtkTextLineSegment *seg;
1016 g_return_val_if_fail(iter != NULL, FALSE);
1018 real = gtk_text_iter_make_real(iter);
1023 check_invariants(iter);
1025 seg = real->any_segment;
1026 while (seg != real->segment)
1028 if (seg->type == >k_text_toggle_off_type)
1031 seg->body.toggle.info->tag == tag)
1042 * gtk_text_iter_toggles_tag:
1043 * @iter: an iterator
1044 * @tag: a #GtkTextTag, or NULL
1046 * This is equivalent to (gtk_text_iter_begins_tag() ||
1047 * gtk_text_iter_ends_tag()), i.e. it tells you whether a range with
1048 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1050 * Return value: whether @tag is toggled on or off at @iter
1053 gtk_text_iter_toggles_tag (const GtkTextIter *iter,
1056 GtkTextRealIter *real;
1057 GtkTextLineSegment *seg;
1059 g_return_val_if_fail(iter != NULL, FALSE);
1061 real = gtk_text_iter_make_real(iter);
1066 check_invariants(iter);
1068 seg = real->any_segment;
1069 while (seg != real->segment)
1071 if ( (seg->type == >k_text_toggle_off_type ||
1072 seg->type == >k_text_toggle_on_type) &&
1074 seg->body.toggle.info->tag == tag) )
1084 * gtk_text_iter_has_tag:
1085 * @iter: an iterator
1086 * @tag: a #GtkTextTag
1088 * Returns TRUE if @iter is within a range tagged with @tag.
1090 * Return value: whether @iter is tagged with @tag
1093 gtk_text_iter_has_tag (const GtkTextIter *iter,
1096 GtkTextRealIter *real;
1098 g_return_val_if_fail(iter != NULL, FALSE);
1099 g_return_val_if_fail(GTK_IS_TEXT_TAG(tag), FALSE);
1101 real = gtk_text_iter_make_surreal(iter);
1106 check_invariants(iter);
1108 if (real->line_byte_offset >= 0)
1110 return gtk_text_line_byte_has_tag(real->line, real->tree,
1111 real->line_byte_offset, tag);
1115 g_assert(real->line_char_offset >= 0);
1116 return gtk_text_line_char_has_tag(real->line, real->tree,
1117 real->line_char_offset, tag);
1122 * gtk_text_iter_editable:
1123 * @iter: an iterator
1124 * @default_setting: TRUE if text is editable by default
1126 * Returns whether @iter is within an editable region of text.
1127 * Non-editable text is "locked" and can't be changed by the user via
1128 * #GtkTextView. This function is simply a convenience wrapper around
1129 * gtk_text_iter_get_attributes(). If no tags applied to this text
1130 * affect editability, @default_setting will be returned.
1132 * Return value: whether @iter is inside an editable range
1135 gtk_text_iter_editable (const GtkTextIter *iter,
1136 gboolean default_setting)
1138 GtkTextAttributes *values;
1141 values = gtk_text_attributes_new ();
1143 values->editable = default_setting;
1145 gtk_text_iter_get_attributes (iter, values);
1147 retval = values->editable;
1149 gtk_text_attributes_unref (values);
1155 * gtk_text_iter_get_language:
1156 * @iter: an iterator
1158 * A convenience wrapper around gtk_text_iter_get_attributes(),
1159 * which returns the language in effect at @iter. If no tags affecting
1160 * language * apply to @iter, the return value is identical to that of
1161 * gtk_get_default_language().
1163 * Return value: language in effect at @iter
1166 gtk_text_iter_get_language (const GtkTextIter *iter)
1168 GtkTextAttributes *values;
1171 values = gtk_text_attributes_new ();
1173 gtk_text_iter_get_attributes (iter, values);
1175 retval = g_strdup (values->language);
1177 gtk_text_attributes_unref (values);
1183 * gtk_text_iter_starts_line:
1184 * @iter: an iterator
1186 * Returns TRUE if @iter begins a newline-terminated line,
1187 * i.e. gtk_text_iter_get_line_offset() would return 0.
1188 * However this function is potentially more efficient than
1189 * gtk_text_iter_get_line_offset() because it doesn't have to compute
1190 * the offset, it just has to see whether it's 0.
1192 * Return value: whether @iter begins a line
1195 gtk_text_iter_starts_line (const GtkTextIter *iter)
1197 GtkTextRealIter *real;
1199 g_return_val_if_fail(iter != NULL, FALSE);
1201 real = gtk_text_iter_make_surreal(iter);
1206 check_invariants(iter);
1208 if (real->line_byte_offset >= 0)
1210 return (real->line_byte_offset == 0);
1214 g_assert(real->line_char_offset >= 0);
1215 return (real->line_char_offset == 0);
1220 * gtk_text_iter_ends_line:
1221 * @iter: an iterator
1223 * Returns TRUE if @iter points to a newline character.
1225 * Return value: whether @iter is at the end of a line
1228 gtk_text_iter_ends_line (const GtkTextIter *iter)
1230 g_return_val_if_fail(iter != NULL, FALSE);
1232 check_invariants(iter);
1234 return gtk_text_iter_get_char(iter) == '\n';
1238 * gtk_text_iter_is_last:
1239 * @iter: an iterator
1241 * Returns TRUE if @iter is the end iterator, i.e. one past the last
1242 * dereferenceable iterator in the buffer. gtk_text_iter_is_last() is
1243 * the most efficient way to check whether an iterator is the end
1246 * Return value: whether @iter is the end iterator
1249 gtk_text_iter_is_last (const GtkTextIter *iter)
1251 GtkTextRealIter *real;
1253 g_return_val_if_fail(iter != NULL, FALSE);
1255 real = gtk_text_iter_make_surreal(iter);
1260 check_invariants(iter);
1262 return gtk_text_line_is_last(real->line, real->tree);
1266 * gtk_text_iter_is_first:
1267 * @iter: an iterator
1269 * Returns TRUE if @iter is the first iterator in the buffer, that is
1270 * if @iter has a character offset of 0.
1272 * Return value: whether @iter is the first in the buffer
1275 gtk_text_iter_is_first (const GtkTextIter *iter)
1277 return gtk_text_iter_get_offset (iter) == 0;
1281 * gtk_text_iter_get_chars_in_line:
1282 * @iter: an iterator
1284 * Returns the number of characters in the line containing @iter,
1285 * including the terminating newline.
1287 * Return value: number of characters in the line
1290 gtk_text_iter_get_chars_in_line (const GtkTextIter *iter)
1292 GtkTextRealIter *real;
1294 GtkTextLineSegment *seg;
1296 g_return_val_if_fail(iter != NULL, FALSE);
1298 real = gtk_text_iter_make_surreal(iter);
1303 check_invariants(iter);
1305 if (real->line_char_offset >= 0)
1307 /* We can start at the segments we've already found. */
1308 count = real->line_char_offset - real->segment_char_offset;
1309 seg = gtk_text_iter_get_indexable_segment(iter);
1313 /* count whole line. */
1314 seg = real->line->segments;
1321 count += seg->char_count;
1330 * gtk_text_iter_get_attributes:
1331 * @iter: an iterator
1332 * @values: a #GtkTextAttributes to be filled in
1334 * Computes the effect of any tags applied to this spot in the
1335 * text. The @values parameter should be initialized to the default
1336 * settings you wish to use if no tags are in effect.
1337 * gtk_text_iter_get_attributes() will modify @values, applying the
1338 * effects of any tags present at @iter. If any tags affected @values,
1339 * the function returns TRUE.
1341 * Return value: TRUE if @values was modified
1344 gtk_text_iter_get_attributes (const GtkTextIter *iter,
1345 GtkTextAttributes *values)
1350 /* Get the tags at this spot */
1351 tags = gtk_text_btree_get_tags (iter, &tag_count);
1353 /* No tags, use default style */
1354 if (tags == NULL || tag_count == 0)
1362 /* Sort tags in ascending order of priority */
1363 gtk_text_tag_array_sort (tags, tag_count);
1365 gtk_text_attributes_fill_from_tags (values,
1375 * Increments/decrements
1378 /* The return value of this indicates WHETHER WE MOVED.
1379 * The return value of public functions indicates
1380 * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1383 forward_line_leaving_caches_unmodified(GtkTextRealIter *real)
1385 GtkTextLine *new_line;
1387 new_line = gtk_text_line_next(real->line);
1389 g_assert(new_line != real->line);
1391 if (new_line != NULL)
1393 real->line = new_line;
1395 real->line_byte_offset = 0;
1396 real->line_char_offset = 0;
1398 real->segment_byte_offset = 0;
1399 real->segment_char_offset = 0;
1401 /* Find first segments in new line */
1402 real->any_segment = real->line->segments;
1403 real->segment = real->any_segment;
1404 while (real->segment->char_count == 0)
1405 real->segment = real->segment->next;
1411 /* There is no way to move forward; we were already
1412 at the "end" index. (the end index is the last
1413 line pointer, segment_byte_offset of 0) */
1415 g_assert(real->line_char_offset == 0 ||
1416 real->line_byte_offset == 0);
1418 /* The only indexable segment allowed on the bogus
1419 line at the end is a single char segment containing
1421 if (real->segments_changed_stamp ==
1422 gtk_text_btree_get_segments_changed_stamp(real->tree))
1424 g_assert(real->segment->type == >k_text_char_type);
1425 g_assert(real->segment->char_count == 1);
1427 /* We leave real->line as-is */
1434 forward_char(GtkTextRealIter *real)
1436 GtkTextIter *iter = (GtkTextIter*)real;
1438 check_invariants((GtkTextIter*)real);
1440 ensure_char_offsets(real);
1442 if ( (real->segment_char_offset + 1) == real->segment->char_count)
1444 /* Need to move to the next segment; if no next segment,
1445 need to move to next line. */
1446 return gtk_text_iter_forward_indexable_segment(iter);
1450 /* Just moving within a segment. Keep byte count
1451 up-to-date, if it was already up-to-date. */
1453 g_assert(real->segment->type == >k_text_char_type);
1455 if (real->line_byte_offset >= 0)
1458 const char * start =
1459 real->segment->body.chars + real->segment_byte_offset;
1461 bytes = g_utf8_next_char (start) - start;
1463 real->line_byte_offset += bytes;
1464 real->segment_byte_offset += bytes;
1466 g_assert(real->segment_byte_offset < real->segment->byte_count);
1469 real->line_char_offset += 1;
1470 real->segment_char_offset += 1;
1472 adjust_char_index(real, 1);
1474 g_assert(real->segment_char_offset < real->segment->char_count);
1476 /* We moved into the middle of a segment, so the any_segment
1477 must now be the segment we're in the middle of. */
1478 real->any_segment = real->segment;
1480 check_invariants((GtkTextIter*)real);
1482 /* FIXME we don't currently return FALSE if
1483 * we moved onto the end iterator
1491 gtk_text_iter_forward_indexable_segment(GtkTextIter *iter)
1493 /* Need to move to the next segment; if no next segment,
1494 need to move to next line. */
1495 GtkTextLineSegment *seg;
1496 GtkTextLineSegment *any_seg;
1497 GtkTextRealIter *real;
1501 g_return_val_if_fail(iter != NULL, FALSE);
1503 real = gtk_text_iter_make_real(iter);
1508 check_invariants(iter);
1510 if (real->line_char_offset >= 0)
1512 chars_skipped = real->segment->char_count - real->segment_char_offset;
1513 g_assert(chars_skipped > 0);
1518 if (real->line_byte_offset >= 0)
1520 bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1521 g_assert(bytes_skipped > 0);
1526 /* Get first segment of any kind */
1527 any_seg = real->segment->next;
1528 /* skip non-indexable segments, if any */
1530 while (seg != NULL && seg->char_count == 0)
1535 real->any_segment = any_seg;
1536 real->segment = seg;
1538 if (real->line_byte_offset >= 0)
1540 g_assert(bytes_skipped > 0);
1541 real->segment_byte_offset = 0;
1542 real->line_byte_offset += bytes_skipped;
1545 if (real->line_char_offset >= 0)
1547 g_assert(chars_skipped > 0);
1548 real->segment_char_offset = 0;
1549 real->line_char_offset += chars_skipped;
1550 adjust_char_index(real, chars_skipped);
1553 check_invariants(iter);
1559 /* End of the line */
1560 if (forward_line_leaving_caches_unmodified(real))
1562 adjust_line_number(real, 1);
1563 if (real->line_char_offset >= 0)
1564 adjust_char_index(real, chars_skipped);
1566 check_invariants(iter);
1568 g_assert(real->line_byte_offset == 0);
1569 g_assert(real->line_char_offset == 0);
1570 g_assert(real->segment_byte_offset == 0);
1571 g_assert(real->segment_char_offset == 0);
1572 g_assert(gtk_text_iter_starts_line(iter));
1574 check_invariants(iter);
1576 if (gtk_text_iter_is_last (iter))
1585 check_invariants(iter);
1593 gtk_text_iter_backward_indexable_segment(GtkTextIter *iter)
1602 * gtk_text_iter_next_char:
1603 * @iter: an iterator
1605 * Moves @iter forward by one character offset. Note that images
1606 * embedded in the buffer occupy 1 character slot, so
1607 * gtk_text_iter_next_char() may actually move onto an image instead
1608 * of a character, if you have images in your buffer. If @iter is the
1609 * end iterator or one character before it, @iter will now point at
1610 * the end iterator, and gtk_text_iter_next_char() returns FALSE for
1611 * convenience when writing loops.
1613 * Return value: whether the new position is the end iterator
1616 gtk_text_iter_next_char(GtkTextIter *iter)
1618 GtkTextRealIter *real;
1620 g_return_val_if_fail(iter != NULL, FALSE);
1622 real = gtk_text_iter_make_real(iter);
1628 check_invariants(iter);
1629 return forward_char(real);
1634 * gtk_text_iter_prev_char:
1635 * @iter: an iterator
1637 * Moves backward by one character offset. Returns TRUE if movement
1638 * was possible; if @iter was the first in the buffer (character
1639 * offset 0), gtk_text_iter_prev_char() returns FALSE for convenience when
1642 * Return value: whether movement was possible
1645 gtk_text_iter_prev_char(GtkTextIter *iter)
1647 g_return_val_if_fail(iter != NULL, FALSE);
1649 check_invariants(iter);
1651 return gtk_text_iter_backward_chars(iter, 1);
1655 Definitely we should try to linear scan as often as possible for
1656 movement within a single line, because we can't use the BTree to
1657 speed within-line searches up; for movement between lines, we would
1658 like to avoid the linear scan probably.
1660 Instead of using this constant, it might be nice to cache the line
1661 length in the iterator and linear scan if motion is within a single
1664 I guess you'd have to profile the various approaches.
1666 #define MAX_LINEAR_SCAN 300
1670 * gtk_text_iter_forward_chars:
1671 * @iter: an iterator
1672 * @count: number of characters to move, may be negative
1674 * Moves @count characters if possible (if @count would move past the
1675 * start or end of the buffer, moves to the start or end of the
1676 * buffer). If @count is positive, the return value indicates whether
1677 * @iter was moved to a dereferenceable location (FALSE is returned if
1678 * @iter was moved to the non-dereferenceable end iterator). If @count
1679 * is negative, the return value indicates whether @iter was already
1680 * at character offset 0. If @count is 0, the function does nothing
1681 * and returns FALSE.
1683 * Return value: whether @iter moved or is dereferenceable
1686 gtk_text_iter_forward_chars(GtkTextIter *iter, gint count)
1688 GtkTextRealIter *real;
1690 g_return_val_if_fail(iter != NULL, FALSE);
1692 real = gtk_text_iter_make_real(iter);
1696 else if (count == 0)
1699 return gtk_text_iter_backward_chars(iter, 0 - count);
1700 else if (count < MAX_LINEAR_SCAN)
1702 check_invariants(iter);
1706 if (!forward_char(real))
1711 return forward_char(real);
1715 gint current_char_index;
1716 gint new_char_index;
1718 check_invariants(iter);
1720 current_char_index = gtk_text_iter_get_offset(iter);
1722 if (current_char_index == gtk_text_btree_char_count(real->tree))
1723 return FALSE; /* can't move forward */
1725 new_char_index = current_char_index + count;
1726 gtk_text_iter_set_offset(iter, new_char_index);
1728 check_invariants(iter);
1730 /* Return FALSE if we're on the non-dereferenceable end
1733 if (gtk_text_iter_is_last (iter))
1741 * gtk_text_iter_backward_chars:
1742 * @iter: an iterator
1743 * @count: number of characters to move
1745 * Moves @count characters backward, if possible (if @count would move
1746 * past the start or end of the buffer, moves to the start or end of
1747 * the buffer). If @count is negative, the return value indicates
1748 * whether @iter was moved to a dereferenceable location (FALSE is
1749 * returned if @iter was moved to the non-dereferenceable end
1750 * iterator). If @count is positive, the return value indicates
1751 * whether @iter was already at character offset 0. If @count is 0,
1752 * the function does nothing and returns FALSE.
1754 * Return value: whether @iter moved or is dereferenceable
1758 gtk_text_iter_backward_chars(GtkTextIter *iter, gint count)
1760 GtkTextRealIter *real;
1762 g_return_val_if_fail(iter != NULL, FALSE);
1764 real = gtk_text_iter_make_real(iter);
1768 else if (count == 0)
1771 return gtk_text_iter_forward_chars(iter, 0 - count);
1773 ensure_char_offsets(real);
1774 check_invariants(iter);
1776 if (count <= real->segment_char_offset)
1778 /* Optimize the within-segment case */
1779 g_assert(real->segment->char_count > 0);
1780 g_assert(real->segment->type == >k_text_char_type);
1782 real->segment_char_offset -= count;
1783 g_assert(real->segment_char_offset >= 0);
1785 if (real->line_byte_offset >= 0)
1787 gint new_byte_offset;
1790 new_byte_offset = 0;
1792 while (i < real->segment_char_offset)
1794 const char * start = real->segment->body.chars + new_byte_offset;
1795 new_byte_offset += g_utf8_next_char (start) - start;
1800 real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
1801 real->segment_byte_offset = new_byte_offset;
1804 real->line_char_offset -= count;
1806 adjust_char_index(real, 0 - count);
1808 check_invariants(iter);
1814 /* We need to go back into previous segments. For now,
1815 just keep this really simple. */
1816 gint current_char_index;
1817 gint new_char_index;
1819 current_char_index = gtk_text_iter_get_offset(iter);
1821 if (current_char_index == 0)
1822 return FALSE; /* can't move backward */
1824 new_char_index = current_char_index - count;
1825 if (new_char_index < 0)
1827 gtk_text_iter_set_offset(iter, new_char_index);
1829 check_invariants(iter);
1836 * gtk_text_iter_forward_line:
1837 * @iter: an iterator
1839 * Moves @iter to the start of the next line. Returns TRUE if there
1840 * was a next line to move to, and FALSE if @iter was simply moved to
1841 * the end of the buffer and is now not dereferenceable.
1843 * Return value: whether @iter can be dereferenced
1846 gtk_text_iter_forward_line(GtkTextIter *iter)
1848 GtkTextRealIter *real;
1850 g_return_val_if_fail(iter != NULL, FALSE);
1852 real = gtk_text_iter_make_real(iter);
1857 check_invariants(iter);
1859 if (forward_line_leaving_caches_unmodified(real))
1861 invalidate_char_index(real);
1862 adjust_line_number(real, 1);
1864 check_invariants(iter);
1866 if (gtk_text_iter_is_last (iter))
1873 check_invariants(iter);
1879 * gtk_text_iter_backward_line:
1880 * @iter: an iterator
1882 * Moves @iter to the start of the previous line. Returns TRUE if
1883 * @iter could be moved; i.e. if @iter was at character offset 0, this
1884 * function returns FALSE. Therefore if @iter was already on line 0,
1885 * but not at the start of the line, @iter is snapped to the start of
1886 * the line and the function returns TRUE.
1888 * Return value: whether @iter moved
1891 gtk_text_iter_backward_line(GtkTextIter *iter)
1893 GtkTextLine *new_line;
1894 GtkTextRealIter *real;
1895 gboolean offset_will_change;
1898 g_return_val_if_fail(iter != NULL, FALSE);
1900 real = gtk_text_iter_make_real(iter);
1905 check_invariants(iter);
1907 new_line = gtk_text_line_previous(real->line);
1909 offset_will_change = FALSE;
1910 if (real->line_char_offset > 0)
1911 offset_will_change = TRUE;
1913 if (new_line != NULL)
1915 real->line = new_line;
1917 adjust_line_number(real, -1);
1921 if (!offset_will_change)
1925 invalidate_char_index(real);
1927 real->line_byte_offset = 0;
1928 real->line_char_offset = 0;
1930 real->segment_byte_offset = 0;
1931 real->segment_char_offset = 0;
1933 /* Find first segment in line */
1934 real->any_segment = real->line->segments;
1935 real->segment = gtk_text_line_byte_to_segment(real->line,
1938 g_assert(offset == 0);
1940 /* Note that if we are on the first line, we snap to the start
1941 of the first line and return TRUE, so TRUE means the
1942 iterator changed, not that the line changed; this is maybe
1943 a bit weird. I'm not sure there's an obvious right thing
1946 check_invariants(iter);
1952 gtk_text_iter_forward_lines(GtkTextIter *iter, gint count)
1955 return gtk_text_iter_backward_lines(iter, 0 - count);
1956 else if (count == 0)
1958 else if (count == 1)
1960 check_invariants(iter);
1961 return gtk_text_iter_forward_line(iter);
1967 old_line = gtk_text_iter_get_line(iter);
1969 gtk_text_iter_set_line(iter, old_line + count);
1971 check_invariants(iter);
1973 /* FIXME this needs to return FALSE if we moved onto the
1976 return (gtk_text_iter_get_line(iter) != old_line);
1981 gtk_text_iter_backward_lines(GtkTextIter *iter, gint count)
1984 return gtk_text_iter_forward_lines(iter, 0 - count);
1985 else if (count == 0)
1987 else if (count == 1)
1989 return gtk_text_iter_backward_line(iter);
1995 old_line = gtk_text_iter_get_line(iter);
1997 gtk_text_iter_set_line(iter, MAX(old_line - count, 0));
1999 return (gtk_text_iter_get_line(iter) != old_line);
2003 typedef gboolean (* FindLogAttrFunc) (PangoLogAttr *attrs,
2007 gint *found_offset);
2010 find_word_end_func (PangoLogAttr *attrs,
2016 ++offset; /* We always go to the NEXT word end */
2018 /* Find start of next word */
2019 while (offset < min_offset + len &&
2020 !attrs[offset].is_word_stop)
2024 while (offset < min_offset + len &&
2025 !attrs[offset].is_white)
2028 *found_offset = offset;
2030 return offset < min_offset + len;
2034 find_word_start_func (PangoLogAttr *attrs,
2040 --offset; /* We always go to the NEXT word start */
2042 /* Find end of prev word */
2043 while (offset >= min_offset &&
2044 attrs[offset].is_white)
2048 while (offset >= min_offset &&
2049 !attrs[offset].is_word_stop)
2052 *found_offset = offset;
2054 return offset >= min_offset;
2057 /* FIXME this function is very, very gratuitously slow */
2059 find_by_log_attrs (GtkTextIter *iter,
2060 FindLogAttrFunc func,
2067 gint char_len, byte_len;
2068 PangoLogAttr *attrs;
2070 gboolean found = FALSE;
2072 g_return_val_if_fail(iter != NULL, FALSE);
2078 gtk_text_iter_set_line_offset (&start, 0);
2079 gtk_text_iter_forward_to_newline (&end);
2081 paragraph = gtk_text_iter_get_text (&start, &end);
2082 char_len = g_utf8_strlen (paragraph, -1);
2083 byte_len = strlen (paragraph);
2085 offset = gtk_text_iter_get_line_offset (iter);
2087 if (char_len > 0 && offset < char_len)
2091 attrs = g_new (PangoLogAttr, char_len);
2093 lang = gtk_text_iter_get_language (iter);
2095 pango_get_log_attrs (paragraph, byte_len, -1,
2101 found = (* func) (attrs, offset, 0, char_len, &offset);
2112 if (gtk_text_iter_forward_line (iter))
2113 return find_by_log_attrs (iter, func, forward);
2119 if (gtk_text_iter_backward_line (iter))
2120 return find_by_log_attrs (iter, func, forward);
2127 gtk_text_iter_set_line_offset (iter, offset);
2130 !gtk_text_iter_equal(iter, &orig) &&
2131 !gtk_text_iter_is_last (iter);
2136 gtk_text_iter_forward_word_end(GtkTextIter *iter)
2138 return find_by_log_attrs (iter, find_word_end_func, TRUE);
2142 gtk_text_iter_backward_word_start(GtkTextIter *iter)
2144 return find_by_log_attrs (iter, find_word_start_func, FALSE);
2147 /* FIXME a loop around a truly slow function means
2148 * a truly spectacularly slow function.
2151 gtk_text_iter_forward_word_ends(GtkTextIter *iter,
2154 g_return_val_if_fail(iter != NULL, FALSE);
2155 g_return_val_if_fail(count > 0, FALSE);
2157 if (!gtk_text_iter_forward_word_end(iter))
2163 if (!gtk_text_iter_forward_word_end(iter))
2171 gtk_text_iter_backward_word_starts(GtkTextIter *iter,
2174 g_return_val_if_fail(iter != NULL, FALSE);
2175 g_return_val_if_fail(count > 0, FALSE);
2177 if (!gtk_text_iter_backward_word_start(iter))
2183 if (!gtk_text_iter_backward_word_start(iter))
2191 gtk_text_iter_set_line_offset(GtkTextIter *iter,
2194 GtkTextRealIter *real;
2196 g_return_if_fail(iter != NULL);
2198 real = gtk_text_iter_make_surreal(iter);
2203 check_invariants(iter);
2205 iter_set_from_char_offset(real, real->line, char_on_line);
2207 check_invariants(iter);
2211 gtk_text_iter_set_line(GtkTextIter *iter, gint line_number)
2215 GtkTextRealIter *real;
2217 g_return_if_fail(iter != NULL);
2219 real = gtk_text_iter_make_surreal(iter);
2224 check_invariants(iter);
2226 line = gtk_text_btree_get_line(real->tree, line_number, &real_line);
2228 iter_set_from_char_offset(real, line, 0);
2230 /* We might as well cache this, since we know it. */
2231 real->cached_line_number = real_line;
2233 check_invariants(iter);
2237 gtk_text_iter_set_offset(GtkTextIter *iter, gint char_index)
2240 GtkTextRealIter *real;
2242 gint real_char_index;
2244 g_return_if_fail(iter != NULL);
2246 real = gtk_text_iter_make_surreal(iter);
2251 check_invariants(iter);
2253 if (real->cached_char_index >= 0 &&
2254 real->cached_char_index == char_index)
2257 line = gtk_text_btree_get_line_at_char(real->tree,
2262 iter_set_from_char_offset(real, line, real_char_index - line_start);
2264 /* Go ahead and cache this since we have it. */
2265 real->cached_char_index = real_char_index;
2267 check_invariants(iter);
2271 gtk_text_iter_forward_to_end (GtkTextIter *iter)
2273 GtkTextBuffer *buffer;
2274 GtkTextRealIter *real;
2276 g_return_if_fail(iter != NULL);
2278 real = gtk_text_iter_make_surreal(iter);
2283 buffer = gtk_text_btree_get_buffer(real->tree);
2285 gtk_text_buffer_get_last_iter(buffer, iter);
2289 gtk_text_iter_forward_to_newline(GtkTextIter *iter)
2291 gint current_offset;
2294 g_return_val_if_fail(iter != NULL, FALSE);
2296 current_offset = gtk_text_iter_get_line_offset(iter);
2297 new_offset = gtk_text_iter_get_chars_in_line(iter) - 1;
2299 if (current_offset < new_offset)
2301 /* Move to end of this line. */
2302 gtk_text_iter_set_line_offset(iter, new_offset);
2307 /* Move to end of next line. */
2308 if (gtk_text_iter_forward_line(iter))
2310 gtk_text_iter_forward_to_newline(iter);
2319 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
2322 GtkTextLine *next_line;
2323 GtkTextLine *current_line;
2324 GtkTextRealIter *real;
2326 g_return_val_if_fail(iter != NULL, FALSE);
2328 real = gtk_text_iter_make_real(iter);
2333 check_invariants(iter);
2335 current_line = real->line;
2336 next_line = gtk_text_line_next_could_contain_tag(current_line,
2339 while (gtk_text_iter_forward_indexable_segment(iter))
2341 /* If we went forward to a line that couldn't contain a toggle
2342 for the tag, then skip forward to a line that could contain
2343 it. This potentially skips huge hunks of the tree, so we
2344 aren't a purely linear search. */
2345 if (real->line != current_line)
2347 if (next_line == NULL)
2349 /* End of search. Set to end of buffer. */
2350 gtk_text_btree_get_last_iter(real->tree, iter);
2354 if (real->line != next_line)
2355 iter_set_from_byte_offset(real, next_line, 0);
2357 current_line = real->line;
2358 next_line = gtk_text_line_next_could_contain_tag(current_line,
2363 if (gtk_text_iter_toggles_tag(iter, tag))
2365 /* If there's a toggle here, it isn't indexable so
2366 any_segment can't be the indexable segment. */
2367 g_assert(real->any_segment != real->segment);
2372 /* Check end iterator for tags */
2373 if (gtk_text_iter_toggles_tag(iter, tag))
2375 /* If there's a toggle here, it isn't indexable so
2376 any_segment can't be the indexable segment. */
2377 g_assert(real->any_segment != real->segment);
2381 /* Reached end of buffer */
2386 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
2394 matches_pred(GtkTextIter *iter,
2395 GtkTextCharPredicate pred,
2400 ch = gtk_text_iter_get_char(iter);
2402 return (*pred) (ch, user_data);
2406 gtk_text_iter_forward_find_char (GtkTextIter *iter,
2407 GtkTextCharPredicate pred,
2410 g_return_val_if_fail(iter != NULL, FALSE);
2411 g_return_val_if_fail(pred != NULL, FALSE);
2413 while (gtk_text_iter_next_char(iter))
2415 if (matches_pred(iter, pred, user_data))
2423 gtk_text_iter_backward_find_char (GtkTextIter *iter,
2424 GtkTextCharPredicate pred,
2427 g_return_val_if_fail(iter != NULL, FALSE);
2428 g_return_val_if_fail(pred != NULL, FALSE);
2430 while (gtk_text_iter_prev_char(iter))
2432 if (matches_pred(iter, pred, user_data))
2440 lines_match (const GtkTextIter *start,
2441 const gchar **lines,
2442 gboolean visible_only,
2444 GtkTextIter *match_start)
2451 if (*lines == NULL || **lines == '\0')
2455 gtk_text_iter_forward_line (&next);
2457 gtk_text_iter_spew (start, "start");
2458 gtk_text_iter_spew (&next, "next");
2460 /* No more text in buffer, but *lines is nonempty */
2461 if (gtk_text_iter_equal (start, &next))
2469 line_text = gtk_text_iter_get_visible_slice (start, &next);
2471 line_text = gtk_text_iter_get_slice (start, &next);
2476 g_warning ("Searching for non-slice text is currently broken (you must include 'unknown char' for pixmaps in order to match them)");
2478 line_text = gtk_text_iter_get_visible_text (start, &next);
2480 line_text = gtk_text_iter_get_text (start, &next);
2483 if (match_start) /* if this is the first line we're matching */
2484 found = strstr (line_text, *lines);
2487 /* If it's not the first line, we have to match from the
2488 * start of the line.
2490 if (strncmp (line_text, *lines, strlen (*lines)) == 0)
2502 /* Get offset to start of search string */
2503 offset = g_utf8_strlen (line_text, found - line_text);
2507 /* If match start needs to be returned, set it to the
2508 * start of the search string.
2512 *match_start = next;
2513 gtk_text_iter_forward_chars (match_start, offset);
2516 /* Go to end of search string */
2517 offset += g_utf8_strlen (*lines, -1);
2519 gtk_text_iter_forward_chars (&next, offset);
2525 /* pass NULL for match_start, since we don't need to find the
2528 return lines_match (&next, lines, visible_only, slice, NULL);
2531 /* strsplit() that retains the delimiter as part of the string. */
2533 strbreakup (const char *string,
2534 const char *delimiter,
2537 GSList *string_list = NULL, *slist;
2538 gchar **str_array, *s;
2541 g_return_val_if_fail (string != NULL, NULL);
2542 g_return_val_if_fail (delimiter != NULL, NULL);
2545 max_tokens = G_MAXINT;
2547 s = strstr (string, delimiter);
2550 guint delimiter_len = strlen (delimiter);
2557 len = s - string + delimiter_len;
2558 new_string = g_new (gchar, len + 1);
2559 strncpy (new_string, string, len);
2560 new_string[len] = 0;
2561 string_list = g_slist_prepend (string_list, new_string);
2563 string = s + delimiter_len;
2564 s = strstr (string, delimiter);
2566 while (--max_tokens && s);
2571 string_list = g_slist_prepend (string_list, g_strdup (string));
2574 str_array = g_new (gchar*, n);
2578 str_array[i--] = NULL;
2579 for (slist = string_list; slist; slist = slist->next)
2580 str_array[i--] = slist->data;
2582 g_slist_free (string_list);
2588 gtk_text_iter_forward_search (GtkTextIter *iter,
2590 gboolean visible_only,
2593 gchar **lines = NULL;
2595 gboolean retval = FALSE;
2598 g_return_val_if_fail (iter != NULL, FALSE);
2599 g_return_val_if_fail (str != NULL, FALSE);
2602 return TRUE; /* we found the empty string */
2604 /* locate all lines */
2606 lines = strbreakup (str, "\n", -1);
2612 /* This loop has an inefficient worst-case, where
2613 * gtk_text_iter_get_text() is called repeatedly on
2616 if (lines_match (&search, (const gchar**)lines, visible_only, slice, &match))
2625 while (gtk_text_iter_forward_line (&search));
2627 g_strfreev ((gchar**)lines);
2633 gtk_text_iter_backward_search (GtkTextIter *iter,
2635 gboolean visible_only,
2638 g_return_val_if_fail (iter != NULL, FALSE);
2639 g_return_val_if_fail (str != NULL, FALSE);
2650 gtk_text_iter_equal(const GtkTextIter *lhs, const GtkTextIter *rhs)
2652 GtkTextRealIter *real_lhs;
2653 GtkTextRealIter *real_rhs;
2655 real_lhs = (GtkTextRealIter*)lhs;
2656 real_rhs = (GtkTextRealIter*)rhs;
2658 check_invariants(lhs);
2659 check_invariants(rhs);
2661 if (real_lhs->line != real_rhs->line)
2663 else if (real_lhs->line_byte_offset >= 0 &&
2664 real_rhs->line_byte_offset >= 0)
2665 return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
2668 /* the ensure_char_offsets() calls do nothing if the char offsets
2669 are already up-to-date. */
2670 ensure_char_offsets(real_lhs);
2671 ensure_char_offsets(real_rhs);
2672 return real_lhs->line_char_offset == real_rhs->line_char_offset;
2677 gtk_text_iter_compare(const GtkTextIter *lhs, const GtkTextIter *rhs)
2679 GtkTextRealIter *real_lhs;
2680 GtkTextRealIter *real_rhs;
2682 real_lhs = gtk_text_iter_make_surreal(lhs);
2683 real_rhs = gtk_text_iter_make_surreal(rhs);
2685 check_invariants(lhs);
2686 check_invariants(rhs);
2688 if (real_lhs == NULL ||
2690 return -1; /* why not */
2692 if (real_lhs->line == real_rhs->line)
2694 gint left_index, right_index;
2696 if (real_lhs->line_byte_offset >= 0 &&
2697 real_rhs->line_byte_offset >= 0)
2699 left_index = real_lhs->line_byte_offset;
2700 right_index = real_rhs->line_byte_offset;
2704 /* the ensure_char_offsets() calls do nothing if
2705 the offsets are already up-to-date. */
2706 ensure_char_offsets(real_lhs);
2707 ensure_char_offsets(real_rhs);
2708 left_index = real_lhs->line_char_offset;
2709 right_index = real_rhs->line_char_offset;
2712 if (left_index < right_index)
2714 else if (left_index > right_index)
2723 line1 = gtk_text_iter_get_line(lhs);
2724 line2 = gtk_text_iter_get_line(rhs);
2727 else if (line1 > line2)
2735 gtk_text_iter_in_region (const GtkTextIter *iter,
2736 const GtkTextIter *start,
2737 const GtkTextIter *end)
2739 return gtk_text_iter_compare(iter, start) >= 0 &&
2740 gtk_text_iter_compare(iter, end) < 0;
2744 gtk_text_iter_reorder (GtkTextIter *first,
2745 GtkTextIter *second)
2747 g_return_if_fail(first != NULL);
2748 g_return_if_fail(second != NULL);
2750 if (gtk_text_iter_compare(first, second) > 0)
2761 * Init iterators from the BTree
2765 gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
2769 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2770 gint real_char_index;
2774 g_return_if_fail(iter != NULL);
2775 g_return_if_fail(tree != NULL);
2777 line = gtk_text_btree_get_line_at_char(tree, char_index,
2778 &line_start, &real_char_index);
2780 iter_init_from_char_offset(iter, tree, line, real_char_index - line_start);
2782 real->cached_char_index = real_char_index;
2784 check_invariants(iter);
2788 gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
2793 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2797 g_return_if_fail(iter != NULL);
2798 g_return_if_fail(tree != NULL);
2800 line = gtk_text_btree_get_line(tree, line_number, &real_line);
2802 iter_init_from_char_offset(iter, tree, line, char_on_line);
2804 /* We might as well cache this, since we know it. */
2805 real->cached_line_number = real_line;
2807 check_invariants(iter);
2811 gtk_text_btree_get_iter_at_line_byte (GtkTextBTree *tree,
2816 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2820 g_return_if_fail(iter != NULL);
2821 g_return_if_fail(tree != NULL);
2823 line = gtk_text_btree_get_line(tree, line_number, &real_line);
2825 iter_init_from_byte_offset(iter, tree, line, byte_index);
2827 /* We might as well cache this, since we know it. */
2828 real->cached_line_number = real_line;
2830 check_invariants(iter);
2834 gtk_text_btree_get_iter_at_line (GtkTextBTree *tree,
2839 g_return_if_fail(iter != NULL);
2840 g_return_if_fail(tree != NULL);
2841 g_return_if_fail(line != NULL);
2843 iter_init_from_byte_offset(iter, tree, line, byte_offset);
2845 check_invariants(iter);
2849 gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree,
2855 g_return_val_if_fail(iter != NULL, FALSE);
2856 g_return_val_if_fail(tree != NULL, FALSE);
2858 line = gtk_text_btree_first_could_contain_tag(tree, tag);
2862 /* Set iter to last in tree */
2863 gtk_text_btree_get_last_iter(tree, iter);
2864 check_invariants(iter);
2869 iter_init_from_byte_offset(iter, tree, line, 0);
2870 gtk_text_iter_forward_to_tag_toggle(iter, tag);
2871 check_invariants(iter);
2877 gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree,
2883 g_return_val_if_fail(iter != NULL, FALSE);
2884 g_return_val_if_fail(tree != NULL, FALSE);
2886 line = gtk_text_btree_last_could_contain_tag(tree, tag);
2890 /* Set iter to first in tree */
2891 gtk_text_btree_get_iter_at_line_char(tree, iter, 0, 0);
2892 check_invariants(iter);
2897 iter_init_from_byte_offset(iter, tree, line, -1);
2898 gtk_text_iter_backward_to_tag_toggle(iter, tag);
2899 check_invariants(iter);
2905 gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
2907 const gchar *mark_name)
2911 g_return_val_if_fail(iter != NULL, FALSE);
2912 g_return_val_if_fail(tree != NULL, FALSE);
2914 mark = gtk_text_btree_get_mark_by_name(tree, mark_name);
2920 gtk_text_btree_get_iter_at_mark(tree, iter, mark);
2921 check_invariants(iter);
2927 gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
2931 GtkTextLineSegment *seg = (GtkTextLineSegment*) mark;
2933 g_return_if_fail(iter != NULL);
2934 g_return_if_fail(tree != NULL);
2935 g_return_if_fail(GTK_IS_TEXT_MARK (mark));
2937 iter_init_from_segment(iter, tree,
2938 seg->body.mark.line, seg);
2939 g_assert(seg->body.mark.line == gtk_text_iter_get_text_line(iter));
2940 check_invariants(iter);
2944 gtk_text_btree_get_last_iter (GtkTextBTree *tree,
2947 g_return_if_fail(iter != NULL);
2948 g_return_if_fail(tree != NULL);
2950 gtk_text_btree_get_iter_at_char(tree,
2952 gtk_text_btree_char_count(tree));
2953 check_invariants(iter);
2957 gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
2959 GtkTextRealIter *real = (GtkTextRealIter*)iter;
2961 g_return_if_fail(iter != NULL);
2963 if (real->chars_changed_stamp != gtk_text_btree_get_chars_changed_stamp(real->tree))
2964 g_print(" %20s: <invalidated iterator>\n", desc);
2967 check_invariants(iter);
2968 g_print(" %20s: line %d / char %d / line char %d / line byte %d\n",
2970 gtk_text_iter_get_line(iter),
2971 gtk_text_iter_get_offset(iter),
2972 gtk_text_iter_get_line_offset(iter),
2973 gtk_text_iter_get_line_index(iter));
2974 check_invariants(iter);
2979 gtk_text_iter_check(const GtkTextIter *iter)
2981 const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
2982 gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
2983 GtkTextLineSegment *byte_segment;
2984 GtkTextLineSegment *byte_any_segment;
2985 GtkTextLineSegment *char_segment;
2986 GtkTextLineSegment *char_any_segment;
2987 gboolean segments_updated;
2989 /* We are going to check our class invariants for the Iter class. */
2991 if (real->chars_changed_stamp !=
2992 gtk_text_btree_get_chars_changed_stamp(real->tree))
2993 g_error("iterator check failed: invalid iterator");
2995 if (real->line_char_offset < 0 && real->line_byte_offset < 0)
2996 g_error("iterator check failed: both char and byte offsets are invalid");
2998 segments_updated = (real->segments_changed_stamp ==
2999 gtk_text_btree_get_segments_changed_stamp(real->tree));
3002 printf("checking iter, segments %s updated, byte %d char %d\n",
3003 segments_updated ? "are" : "aren't",
3004 real->line_byte_offset,
3005 real->line_char_offset);
3008 if (real->line_byte_offset == 97 &&
3009 real->line_char_offset == 95)
3012 if (segments_updated)
3014 if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
3015 g_error("iterator check failed: both char and byte segment offsets are invalid");
3017 if (real->segment->char_count == 0)
3018 g_error("iterator check failed: segment is not indexable.");
3020 if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
3021 g_error("segment char offset is not properly up-to-date");
3023 if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
3024 g_error("segment byte offset is not properly up-to-date");
3026 if (real->segment_byte_offset >= 0 &&
3027 real->segment_byte_offset >= real->segment->byte_count)
3028 g_error("segment byte offset is too large.");
3030 if (real->segment_char_offset >= 0 &&
3031 real->segment_char_offset >= real->segment->char_count)
3032 g_error("segment char offset is too large.");
3035 if (real->line_byte_offset >= 0)
3037 gtk_text_line_byte_locate(real->line, real->line_byte_offset,
3038 &byte_segment, &byte_any_segment,
3039 &seg_byte_offset, &line_byte_offset);
3041 if (line_byte_offset != real->line_byte_offset)
3042 g_error("wrong byte offset was stored in iterator");
3044 if (segments_updated)
3046 if (real->segment != byte_segment)
3047 g_error("wrong segment was stored in iterator");
3049 if (real->any_segment != byte_any_segment)
3050 g_error("wrong any_segment was stored in iterator");
3052 if (seg_byte_offset != real->segment_byte_offset)
3053 g_error("wrong segment byte offset was stored in iterator");
3057 if (real->line_char_offset >= 0)
3059 gtk_text_line_char_locate(real->line, real->line_char_offset,
3060 &char_segment, &char_any_segment,
3061 &seg_char_offset, &line_char_offset);
3063 if (line_char_offset != real->line_char_offset)
3064 g_error("wrong char offset was stored in iterator");
3066 if (segments_updated)
3068 if (real->segment != char_segment)
3069 g_error("wrong segment was stored in iterator");
3071 if (real->any_segment != char_any_segment)
3072 g_error("wrong any_segment was stored in iterator");
3074 if (seg_char_offset != real->segment_char_offset)
3075 g_error("wrong segment char offset was stored in iterator");
3079 if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
3081 if (byte_segment != char_segment)
3082 g_error("char and byte offsets did not point to the same segment");
3084 if (byte_any_segment != char_any_segment)
3085 g_error("char and byte offsets did not point to the same any segment");
3087 /* Make sure the segment offsets are equivalent, if it's a char
3089 if (char_segment->type == >k_text_char_type)
3091 gint byte_offset = 0;
3092 gint char_offset = 0;
3093 while (char_offset < seg_char_offset)
3095 const char * start = char_segment->body.chars + byte_offset;
3096 byte_offset += g_utf8_next_char (start) - start;
3100 if (byte_offset != seg_byte_offset)
3101 g_error("byte offset did not correspond to char offset");
3104 g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
3106 if (char_offset != seg_char_offset)
3107 g_error("char offset did not correspond to byte offset");
3111 if (real->cached_line_number >= 0)
3115 should_be = gtk_text_line_get_number(real->line);
3116 if (real->cached_line_number != should_be)
3117 g_error("wrong line number was cached");
3120 if (real->cached_char_index >= 0)
3122 if (real->line_char_offset >= 0) /* only way we can check it
3123 efficiently, not a real
3128 char_index = gtk_text_line_char_index(real->line);
3129 char_index += real->line_char_offset;
3131 if (real->cached_char_index != char_index)
3132 g_error("wrong char index was cached");