gtktextiter.c 109 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* GTK - The GIMP Toolkit
 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
13
14
15
16
17
18
19
20
21
22
23
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
24
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25
26
 */

27
28
29
30
#include "gtktextiter.h"
#include "gtktextbtree.h"
#include "gtktextiterprivate.h"
#include "gtkdebug.h"
31
#include <string.h>
32
33
34
35
#include <ctype.h>

typedef struct _GtkTextRealIter GtkTextRealIter;

36
37
struct _GtkTextRealIter
{
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  /* Always-valid information */
  GtkTextBTree *tree;
  GtkTextLine *line;
  /* At least one of these is always valid;
     if invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint line_byte_offset;
  gint line_char_offset;
  /* These two are valid if >= 0 */
  gint cached_char_index;
  gint cached_line_number;
  /* Stamps to detect the buffer changing under us */
  gint chars_changed_stamp;
  gint segments_changed_stamp;
  /* Valid if the segments_changed_stamp is up-to-date */
  GtkTextLineSegment *segment;     /* indexable segment we index */
  GtkTextLineSegment *any_segment; /* first segment in our location,
57
                                      maybe same as "segment" */
58
59
60
61
62
63
64
65
66
67
68
69
70
  /* One of these will always be valid if segments_changed_stamp is
     up-to-date. If invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint segment_byte_offset;
  gint segment_char_offset;
};

/* These "set" functions should not assume any fields
   other than the char stamp and the tree are valid.
*/
static void
71
72
iter_set_common (GtkTextRealIter *iter,
                 GtkTextLine *line)
73
74
75
{
  /* Update segments stamp */
  iter->segments_changed_stamp =
76
    _gtk_text_btree_get_segments_changed_stamp (iter->tree);
77

78
79
80
81
82
83
84
85
86
87
88
  iter->line = line;

  iter->line_byte_offset = -1;
  iter->line_char_offset = -1;
  iter->segment_byte_offset = -1;
  iter->segment_char_offset = -1;
  iter->cached_char_index = -1;
  iter->cached_line_number = -1;
}

static void
89
90
91
iter_set_from_byte_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint byte_offset)
92
{
93
  iter_set_common (iter, line);
94

95
  _gtk_text_line_byte_locate (iter->line,
96
97
98
99
100
101
102
103
104
                             byte_offset,
                             &iter->segment,
                             &iter->any_segment,
                             &iter->segment_byte_offset,
                             &iter->line_byte_offset);

}

static void
105
106
107
iter_set_from_char_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint char_offset)
108
{
109
  iter_set_common (iter, line);
110

111
  _gtk_text_line_char_locate (iter->line,
112
113
114
115
116
117
118
119
                             char_offset,
                             &iter->segment,
                             &iter->any_segment,
                             &iter->segment_char_offset,
                             &iter->line_char_offset);
}

static void
120
121
122
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{
  GtkTextLineSegment *seg;
  gint byte_offset;

  /* This could theoretically be optimized by computing all the iter
     fields in this same loop, but I'm skipping it for now. */
  byte_offset = 0;
  seg = line->segments;
  while (seg != segment)
    {
      byte_offset += seg->byte_count;
      seg = seg->next;
    }

Havoc Pennington's avatar
Havoc Pennington committed
137
  iter_set_from_byte_offset (iter, line, byte_offset);
138
139
140
141
}

/* This function ensures that the segment-dependent information is
   truly computed lazily; often we don't need to do the full make_real
142
143
   work. This ensures the btree and line are valid, but doesn't
   update the segments. */
144
static GtkTextRealIter*
145
gtk_text_iter_make_surreal (const GtkTextIter *_iter)
146
147
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
148

149
  if (iter->chars_changed_stamp !=
150
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
151
152
153
154
155
156
157
158
159
160
161
    {
      g_warning ("Invalid text buffer iterator: either the iterator "
                 "is uninitialized, or the characters/pixbufs/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,\n"
                 "but any mutation that affects 'indexable' buffer contents "
                 "(contents that can be referred to by character offset)\n"
                 "will invalidate all outstanding iterators");
162
163
164
165
166
167
168
169
170
      return NULL;
    }

  /* We don't update the segments information since we are becoming
     only surreal. However we do invalidate the segments information
     if appropriate, to be sure we segfault if we try to use it and we
     should have used make_real. */

  if (iter->segments_changed_stamp !=
171
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
172
173
174
175
176
177
178
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
179

180
181
182
183
  return iter;
}

static GtkTextRealIter*
184
gtk_text_iter_make_real (const GtkTextIter *_iter)
185
186
{
  GtkTextRealIter *iter;
187
188
189

  iter = gtk_text_iter_make_surreal (_iter);

190
  if (iter->segments_changed_stamp !=
191
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
192
193
194
    {
      if (iter->line_byte_offset >= 0)
        {
195
196
197
          iter_set_from_byte_offset (iter,
                                     iter->line,
                                     iter->line_byte_offset);
198
199
200
        }
      else
        {
201
202
203
204
205
          g_assert (iter->line_char_offset >= 0);

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
206
207
208
        }
    }

209
210
211
212
  g_assert (iter->segment != NULL);
  g_assert (iter->any_segment != NULL);
  g_assert (iter->segment->char_count > 0);

213
214
215
216
  return iter;
}

static GtkTextRealIter*
217
218
iter_init_common (GtkTextIter *_iter,
                  GtkTextBTree *tree)
219
220
221
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;

222
223
  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (tree != NULL, NULL);
224
225
226
227

  iter->tree = tree;

  iter->chars_changed_stamp =
228
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
229

230
231
232
233
  return iter;
}

static GtkTextRealIter*
234
235
236
237
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
238
239
240
{
  GtkTextRealIter *real;

241
242
243
244
245
246
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

247
248
249
250
  return real;
}

static GtkTextRealIter*
251
252
253
254
iter_init_from_byte_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_byte_offset)
255
256
257
{
  GtkTextRealIter *real;

258
259
260
261
262
263
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

264
265
266
267
  return real;
}

static GtkTextRealIter*
268
269
270
271
iter_init_from_char_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_char_offset)
272
273
274
{
  GtkTextRealIter *real;

275
276
277
278
279
280
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

281
282
283
284
  return real;
}

static inline void
285
invalidate_segment (GtkTextRealIter *iter)
286
287
288
289
290
{
  iter->segments_changed_stamp -= 1;
}

static inline void
291
invalidate_char_index (GtkTextRealIter *iter)
292
293
294
295
296
{
  iter->cached_char_index = -1;
}

static inline void
297
invalidate_line_number (GtkTextRealIter *iter)
298
299
300
301
302
{
  iter->cached_line_number = -1;
}

static inline void
303
adjust_char_index (GtkTextRealIter *iter, gint count)
304
305
306
307
308
309
{
  if (iter->cached_char_index >= 0)
    iter->cached_char_index += count;
}

static inline void
310
adjust_line_number (GtkTextRealIter *iter, gint count)
311
312
313
314
315
316
{
  if (iter->cached_line_number >= 0)
    iter->cached_line_number += count;
}

static inline void
317
adjust_char_offsets (GtkTextRealIter *iter, gint count)
318
319
320
321
{
  if (iter->line_char_offset >= 0)
    {
      iter->line_char_offset += count;
322
      g_assert (iter->segment_char_offset >= 0);
323
324
325
326
327
      iter->segment_char_offset += count;
    }
}

static inline void
328
adjust_byte_offsets (GtkTextRealIter *iter, gint count)
329
330
331
332
{
  if (iter->line_byte_offset >= 0)
    {
      iter->line_byte_offset += count;
333
      g_assert (iter->segment_byte_offset >= 0);
334
335
336
337
338
      iter->segment_byte_offset += count;
    }
}

static inline void
339
ensure_char_offsets (GtkTextRealIter *iter)
340
341
342
{
  if (iter->line_char_offset < 0)
    {
343
      g_assert (iter->line_byte_offset >= 0);
344

345
      _gtk_text_line_byte_to_char_offsets (iter->line,
346
347
348
                                          iter->line_byte_offset,
                                          &iter->line_char_offset,
                                          &iter->segment_char_offset);
349
350
351
352
    }
}

static inline void
353
ensure_byte_offsets (GtkTextRealIter *iter)
354
355
356
{
  if (iter->line_byte_offset < 0)
    {
357
      g_assert (iter->line_char_offset >= 0);
358

359
      _gtk_text_line_char_to_byte_offsets (iter->line,
360
361
362
                                          iter->line_char_offset,
                                          &iter->line_byte_offset,
                                          &iter->segment_byte_offset);
363
364
365
    }
}

366
367
368
369
370
371
static inline gboolean
is_segment_start (GtkTextRealIter *real)
{
  return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
}

372
373
#if 1
static void
374
check_invariants (const GtkTextIter *iter)
375
376
{
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
377
    gtk_text_iter_check (iter);
378
379
}
#else
380
#define check_invariants (x)
381
382
#endif

383
384
385
/**
 * gtk_text_iter_get_buffer:
 * @iter: an iterator
386
 *
387
 * Return the #GtkTextBuffer this iterator is associated with
388
 *
389
390
 * Return value: the buffer
 **/
391
GtkTextBuffer*
392
gtk_text_iter_get_buffer (const GtkTextIter *iter)
393
394
395
{
  GtkTextRealIter *real;

396
397
398
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
399
400
401
402

  if (real == NULL)
    return NULL;

403
404
  check_invariants (iter);

405
  return _gtk_text_btree_get_buffer (real->tree);
406
407
}

408
409
410
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
411
 *
412
413
414
415
 * Create a dynamically-allocated copy of an iterator. This function
 * is not useful in applications, because iterators can be copied with a
 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
 * function is used by language bindings.
416
417
 *
 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
418
 **/
419
GtkTextIter*
420
gtk_text_iter_copy (const GtkTextIter *iter)
421
422
423
{
  GtkTextIter *new_iter;

424
425
426
  g_return_val_if_fail (iter != NULL, NULL);

  new_iter = g_new (GtkTextIter, 1);
427
428

  *new_iter = *iter;
429

430
431
432
  return new_iter;
}

433
434
435
436
437
438
439
440
/**
 * gtk_text_iter_free:
 * @iter: a dynamically-allocated iterator
 *
 * Free an iterator allocated on the heap. This function
 * is intended for use in language bindings, and is not
 * especially useful for applications, because iterators can
 * simply be allocated on the stack.
441
 *
442
 **/
443
void
444
gtk_text_iter_free (GtkTextIter *iter)
445
{
446
  g_return_if_fail (iter != NULL);
447

448
  g_free (iter);
449
450
451
}

GtkTextLineSegment*
452
gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
453
454
455
{
  GtkTextRealIter *real;

456
457
458
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
459
460
461
462

  if (real == NULL)
    return NULL;

463
464
465
466
  check_invariants (iter);

  g_assert (real->segment != NULL);

467
468
469
470
  return real->segment;
}

GtkTextLineSegment*
471
gtk_text_iter_get_any_segment (const GtkTextIter *iter)
472
473
474
{
  GtkTextRealIter *real;

475
476
477
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
478
479
480
481

  if (real == NULL)
    return NULL;

482
483
484
485
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

486
487
488
489
  return real->any_segment;
}

gint
490
gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
491
492
493
{
  GtkTextRealIter *real;

494
495
496
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
497
498
499
500

  if (real == NULL)
    return 0;

501
502
503
  ensure_byte_offsets (real);

  check_invariants (iter);
504
505
506
507
508

  return real->segment_byte_offset;
}

gint
509
gtk_text_iter_get_segment_char (const GtkTextIter *iter)
510
511
512
{
  GtkTextRealIter *real;

513
514
515
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
516
517
518
519

  if (real == NULL)
    return 0;

520
521
522
  ensure_char_offsets (real);

  check_invariants (iter);
523
524
525
526
527
528
529

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
530
gtk_text_iter_get_text_line (const GtkTextIter *iter)
531
532
533
{
  const GtkTextRealIter *real;

534
535
  g_return_val_if_fail (iter != NULL, 0);

536
537
538
539
540
541
542
543
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
544
gtk_text_iter_get_btree (const GtkTextIter *iter)
545
546
547
{
  const GtkTextRealIter *real;

548
549
  g_return_val_if_fail (iter != NULL, 0);

550
551
552
553
554
555
556
557
558
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

559
560
561
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
562
 *
563
564
565
 * Returns the character offset of an iterator.
 * Each character in a #GtkTextBuffer has an offset,
 * starting with 0 for the first character in the buffer.
566
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
567
 * offset back into an iterator.
568
 *
569
570
 * Return value: a character offset
 **/
571
gint
572
gtk_text_iter_get_offset (const GtkTextIter *iter)
573
574
575
{
  GtkTextRealIter *real;

576
577
578
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
579
580
581
582

  if (real == NULL)
    return 0;

583
584
  check_invariants (iter);
  
585
586
  if (real->cached_char_index < 0)
    {
587
588
      ensure_char_offsets (real);
      
589
      real->cached_char_index =
590
        _gtk_text_line_char_index (real->line);
591
592
593
      real->cached_char_index += real->line_char_offset;
    }

594
595
  check_invariants (iter);

596
597
598
  return real->cached_char_index;
}

599
600
601
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
602
 *
603
604
605
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
606
 *
607
608
 * Return value: a line number
 **/
609
gint
610
gtk_text_iter_get_line (const GtkTextIter *iter)
611
612
613
{
  GtkTextRealIter *real;

614
615
616
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
617
618
619
620
621
622

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
623
      _gtk_text_line_get_number (real->line);
624
625

  check_invariants (iter);
626
627
628
629

  return real->cached_line_number;
}

630
631
632
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
633
 *
634
635
636
 * Returns the character offset of the iterator,
 * counting from the start of a newline-terminated line.
 * The first character on the line has offset 0.
637
 *
638
639
 * Return value: offset from start of line
 **/
640
gint
641
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
642
643
644
645
{

  GtkTextRealIter *real;

646
647
648
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
649
650
651
652

  if (real == NULL)
    return 0;

653
654
655
  ensure_char_offsets (real);

  check_invariants (iter);
656
657
658
659

  return real->line_char_offset;
}

660
661
662
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
663
 *
664
665
666
667
668
 * Returns the byte index of the iterator, counting
 * from the start of a newline-terminated line.
 * Remember that #GtkTextBuffer encodes text in
 * UTF-8, and that characters can require a variable
 * number of bytes to represent.
669
 *
670
671
 * Return value: distance from start of line, in bytes
 **/
672
gint
Havoc Pennington's avatar
Havoc Pennington committed
673
gtk_text_iter_get_line_index (const GtkTextIter *iter)
674
675
676
{
  GtkTextRealIter *real;

677
678
679
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
680
681
682
683

  if (real == NULL)
    return 0;

684
685
686
  ensure_byte_offsets (real);

  check_invariants (iter);
687
688
689
690
691
692
693
694

  return real->line_byte_offset;
}

/*
 * Dereferencing
 */

695
696
697
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
698
 *
699
700
701
 * Returns the Unicode character at this iterator.  (Equivalent to
 * operator* on a C++ iterator.)  If the iterator points at a
 * non-character element, such as an image embedded in the buffer, the
Havoc Pennington's avatar
Havoc Pennington committed
702
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
703
 * the end iterator, zero is returned; zero is not a valid Unicode character.
704
 * So you can write a loop which ends when gtk_text_iter_get_char ()
705
 * returns 0.
706
 *
707
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
708
 **/
709
gunichar
710
gtk_text_iter_get_char (const GtkTextIter *iter)
711
712
713
{
  GtkTextRealIter *real;

714
715
716
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
717
718
719
720

  if (real == NULL)
    return 0;

721
  check_invariants (iter);
722
723
724
725

  if (gtk_text_iter_is_last (iter))
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
726
    {
727
      ensure_byte_offsets (real);
728
      
729
730
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
731
732
733
    }
  else
    {
Havoc Pennington's avatar
Havoc Pennington committed
734
735
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
736
737
738
    }
}

739
740
741
742
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
743
 *
744
745
 * Returns the text in the given range. A "slice" is an array of
 * characters encoded in UTF-8 format, including the Unicode "unknown"
Havoc Pennington's avatar
Havoc Pennington committed
746
 * character 0xFFFC for iterable non-character elements in the buffer,
747
748
 * such as images.  Because images are encoded in the slice, byte and
 * character offsets in the returned array will correspond to byte
Havoc Pennington's avatar
Havoc Pennington committed
749
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
750
751
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
752
 *
753
754
 * Return value: slice of text from the buffer
 **/
755
756
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
757
                               const GtkTextIter *end)
758
{
759
760
761
762
763
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
764

765
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
766
767
}

768
769
770
771
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
772
 *
773
774
775
776
 * Returns <emphasis>text</emphasis> in the given range.  If the range
 * contains non-text elements such as images, the character and byte
 * offsets in the returned string will not correspond to character and
 * byte offsets in the buffer. If you want offsets to correspond, see
777
778
 * gtk_text_iter_get_slice ().
 *
779
780
 * Return value: array of characters from the buffer
 **/
781
782
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
783
                              const GtkTextIter *end)
784
{
785
786
787
788
789
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
790

791
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
792
793
}

794
795
796
797
/**
 * gtk_text_iter_get_visible_slice:
 * @start: iterator at start of range
 * @end: iterator at end of range
798
799
 *
 * Like gtk_text_iter_get_slice (), but invisible text is not included.
800
801
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
802
 *
803
804
 * Return value: slice of text from the buffer
 **/
805
806
gchar*
gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
807
                                 const GtkTextIter  *end)
808
{
809
810
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);
811

812
813
814
  check_invariants (start);
  check_invariants (end);

815
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
816
817
}

818
819
820
821
/**
 * gtk_text_iter_get_visible_text:
 * @start: iterator at start of range
 * @end: iterator at end of range
822
823
 *
 * Like gtk_text_iter_get_text (), but invisible text is not included.
824
825
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
826
 *
827
828
 * Return value: string containing visible text in the range
 **/
829
830
gchar*
gtk_text_iter_get_visible_text (const GtkTextIter  *start,
831
                                const GtkTextIter  *end)
832
{
833
834
835
836
837
838
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);

839
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
840
841
}

842
/**
Havoc Pennington's avatar
Havoc Pennington committed
843
 * gtk_text_iter_get_pixbuf:
844
 * @iter: an iterator
845
 *
Havoc Pennington's avatar
Havoc Pennington committed
846
847
848
 * If the location pointed to by @iter contains a pixbuf, the pixbuf
 * is returned (with no new reference count added). Otherwise,
 * NULL is returned.
849
 *
Havoc Pennington's avatar
Havoc Pennington committed
850
 * Return value: the pixbuf at @iter
851
 **/
Havoc Pennington's avatar
Havoc Pennington committed
852
853
GdkPixbuf*
gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
854
855
856
{
  GtkTextRealIter *real;

857
  g_return_val_if_fail (iter != NULL, NULL);
858
859

  real = gtk_text_iter_make_real (iter);
860
861

  if (real == NULL)
862
    return NULL;
863
864
865

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
866
  if (real->segment->type != &gtk_text_pixbuf_type)
867
    return NULL;
868
  else
Havoc Pennington's avatar
Havoc Pennington committed
869
    return real->segment->body.pixbuf.pixbuf;
870
871
}

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
/**
 * gtk_text_iter_get_child_anchor:
 * @iter: an iterator
 *
 * If the location pointed to by @iter contains a child anchor, the
 * anchor is returned (with no new reference count added). Otherwise,
 * NULL is returned.
 *
 * Return value: the anchor at @iter
 **/
GtkTextChildAnchor*
gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
{
  GtkTextRealIter *real;

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return NULL;

  check_invariants (iter);

  if (real->segment->type != &gtk_text_child_type)
    return NULL;
  else
    return real->segment->body.child.obj;
}

902
903
904
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
905
 *
906
907
908
909
910
 * Returns a list of all #GtkTextMark at this location. Because marks
 * are not iterable (they don't take up any "space" in the buffer,
 * they are just marks in between iterable locations), multiple marks
 * can exist in the same place. The returned list is not in any
 * meaningful order.
911
 *
912
913
 * Return value: list of #GtkTextMark
 **/
914
915
916
917
918
919
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
920
921
922
923

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
924
925
926
927

  if (real == NULL)
    return NULL;

928
929
  check_invariants (iter);

930
931
932
933
934
935
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_left_mark_type ||
          seg->type == &gtk_text_right_mark_type)
Havoc Pennington's avatar
Havoc Pennington committed
936
        retval = g_slist_prepend (retval, seg->body.mark.obj);
937

938
939
940
941
942
943
944
945
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

946
947
948
949
/**
 * gtk_text_iter_get_toggled_tags:
 * @iter: an iterator
 * @toggled_on: TRUE to get toggled-on tags
950
 *
951
952
953
954
955
956
 * Returns a list of #GtkTextTag that are toggled on or off at this
 * point.  (If @toggled_on is TRUE, the list contains tags that are
 * toggled on.) If a tag is toggled on at @iter, then some non-empty
 * range of characters following @iter has that tag applied to it.  If
 * a tag is toggled off, then some non-empty range following @iter
 * does <emphasis>not</emphasis> have the tag applied to it.
957
 *
958
959
 * Return value: tags toggled at this point
 **/
960
961
GSList*
gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
962
                                 gboolean            toggled_on)
963
964
965
966
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
967
968
969
970

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
971
972
973
974

  if (real == NULL)
    return NULL;

975
976
  check_invariants (iter);

977
978
979
980
981
982
983
984
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (toggled_on)
        {
          if (seg->type == &gtk_text_toggle_on_type)
            {
985
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
986
987
988
989
990
991
            }
        }
      else
        {
          if (seg->type == &gtk_text_toggle_off_type)
            {
992
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
993
994
            }
        }
995

996
997
998
999
1000
1001
1002
1003
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

1004
1005
1006
1007
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag, or NULL
1008
 *
1009
1010
 * Returns TRUE if @tag is toggled on at exactly this point. If @tag
 * is NULL, returns TRUE if any tag is toggled on at this point. Note
1011
 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1012
 * <emphasis>start</emphasis> of the tagged range;
1013
 * gtk_text_iter_has_tag () tells you whether an iterator is
1014
 * <emphasis>within</emphasis> a tagged range.
1015
 *
1016
1017
 * Return value: whether @iter is the start of a range tagged with @tag
 **/
1018
1019
gboolean
gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1020
                             GtkTextTag         *tag)
1021
1022
1023
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1024
1025
1026
1027

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1028
1029
1030
1031

  if (real == NULL)
    return FALSE;

1032
1033
  check_invariants (iter);

1034
1035
1036
1037
1038
1039
1040
1041
1042
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_on_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1043

1044
1045
1046
1047
1048
1049
      seg = seg->next;
    }

  return FALSE;
}

1050
1051
1052
1053
1054
1055
1056
/**
 * gtk_text_iter_ends_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag, or NULL
 *
 * Returns TRUE if @tag is toggled off at exactly this point. If @tag
 * is NULL, returns TRUE if any tag is toggled off at this point. Note
1057
 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1058
 * <emphasis>end</emphasis> of the tagged range;
1059
 * gtk_text_iter_has_tag () tells you whether an iterator is
1060
 * <emphasis>within</emphasis> a tagged range.
1061
 *
1062
 * Return value: whether @iter is the end of a range tagged with @tag
1063
 *
1064
 **/
1065
1066
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1067
                          GtkTextTag         *tag)
1068
1069
1070
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1071
1072
1073
1074

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1075
1076
1077
1078

  if (real == NULL)
    return FALSE;

1079
1080
  check_invariants (iter);

1081
1082
1083
1084
1085
1086
1087
1088
1089
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_off_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1090

1091
1092
1093
1094
1095
1096
      seg = seg->next;
    }

  return FALSE;
}

1097
1098
1099
1100
/**
 * gtk_text_iter_toggles_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag, or NULL
1101
1102
1103
 *
 * This is equivalent to (gtk_text_iter_begins_tag () ||
 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1104
 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1105
 *
1106
1107
 * Return value: whether @tag is toggled on or off at @iter
 **/
1108
1109
gboolean
gtk_text_iter_toggles_tag       (const GtkTextIter  *iter,
1110
                                 GtkTextTag         *tag)
1111
1112
1113
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1114
1115
1116
1117

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1118
1119
1120
1121

  if (real == NULL)
    return FALSE;

1122
1123
  check_invariants (iter);

1124
1125
1126
1127
1128
1129
1130
1131
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if ( (seg->type == &gtk_text_toggle_off_type ||
            seg->type == &gtk_text_toggle_on_type) &&
           (tag == NULL ||
            seg->body.toggle.info->tag == tag) )
        return TRUE;
1132

1133
1134
1135
1136
1137
1138
      seg = seg->next;
    }

  return FALSE;
}

1139
1140
1141
1142
/**
 * gtk_text_iter_has_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag
1143
 *
1144
 * Returns TRUE if @iter is within a range tagged with @tag.
1145
 *
1146
1147
 * Return value: whether @iter is tagged with @tag
 **/
1148
1149
gboolean
gtk_text_iter_has_tag           (const GtkTextIter   *iter,
1150
                                 GtkTextTag          *tag)
1151
1152
{
  GtkTextRealIter *real;
1153
1154
1155
1156
1157

  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);

  real = gtk_text_iter_make_surreal (iter);
1158
1159

  if (real == NULL)
1160
1161
1162
    return FALSE;

  check_invariants (iter);
1163
1164
1165

  if (real->line_byte_offset >= 0)
    {
1166
      return _gtk_text_line_byte_has_tag (real->line, real->tree,
1167
1168
1169
1170
                                         real->line_byte_offset, tag);
    }
  else
    {
1171
      g_assert (real->line_char_offset >= 0);
1172
      return _gtk_text_line_char_has_tag (real->line, real->tree,
1173
1174
1175
1176
                                         real->line_char_offset, tag);
    }
}

1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194