gtktextiter.c 112 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
                              byte_offset,
                              &iter->segment,
                              &iter->any_segment,
                              &iter->segment_byte_offset,
                              &iter->line_byte_offset);
101
102
103
}

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

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

static void
119
120
121
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{
  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
136
  iter_set_from_byte_offset (iter, line, byte_offset);
137
138
139
140
}

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

148
  if (iter->chars_changed_stamp !=
149
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
150
151
152
153
154
155
156
157
158
159
160
    {
      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");
161
162
163
164
165
166
167
168
169
      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 !=
170
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
171
172
173
174
175
176
177
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
178

179
180
181
182
  return iter;
}

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

  iter = gtk_text_iter_make_surreal (_iter);

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

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

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

212
213
214
215
  return iter;
}

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

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

  iter->tree = tree;

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

229
230
231
232
  return iter;
}

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

246
247
248
249
  return real;
}

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

263
264
265
266
  return real;
}

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

280
281
282
283
  return real;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  real = gtk_text_iter_make_surreal (iter);
398
399
400
401

  if (real == NULL)
    return NULL;

402
403
  check_invariants (iter);

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

407
408
409
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
410
 *
411
412
413
414
 * 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.
415
416
 *
 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
417
 **/
418
GtkTextIter*
419
gtk_text_iter_copy (const GtkTextIter *iter)
420
421
422
{
  GtkTextIter *new_iter;

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

  new_iter = g_new (GtkTextIter, 1);
426
427

  *new_iter = *iter;
428

429
430
431
  return new_iter;
}

432
433
434
435
436
437
438
439
/**
 * 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.
440
 *
441
 **/
442
void
443
gtk_text_iter_free (GtkTextIter *iter)
444
{
445
  g_return_if_fail (iter != NULL);
446

447
  g_free (iter);
448
449
450
}

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

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

  real = gtk_text_iter_make_real (iter);
458
459
460
461

  if (real == NULL)
    return NULL;

462
463
464
465
  check_invariants (iter);

  g_assert (real->segment != NULL);

466
467
468
469
  return real->segment;
}

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

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

  real = gtk_text_iter_make_real (iter);
477
478
479
480

  if (real == NULL)
    return NULL;

481
482
483
484
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

485
486
487
488
  return real->any_segment;
}

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

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

  real = gtk_text_iter_make_real (iter);
496
497
498
499

  if (real == NULL)
    return 0;

500
501
502
  ensure_byte_offsets (real);

  check_invariants (iter);
503
504
505
506
507

  return real->segment_byte_offset;
}

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

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

  real = gtk_text_iter_make_real (iter);
515
516
517
518

  if (real == NULL)
    return 0;

519
520
521
  ensure_char_offsets (real);

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

  return real->segment_char_offset;
}

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

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

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

  return real->line;
}

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

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

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

  return real->tree;
}

/*
 * Conversions
 */

558
559
560
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
561
 *
562
563
564
 * 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.
565
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
566
 * offset back into an iterator.
567
 *
568
569
 * Return value: a character offset
 **/
570
gint
571
gtk_text_iter_get_offset (const GtkTextIter *iter)
572
573
574
{
  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_surreal (iter);
578
579
580
581

  if (real == NULL)
    return 0;

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

593
594
  check_invariants (iter);

595
596
597
  return real->cached_char_index;
}

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

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

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

  if (real == NULL)
    return 0;

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

  check_invariants (iter);
625
626
627
628

  return real->cached_line_number;
}

629
630
631
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
632
 *
633
634
635
 * 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.
636
 *
637
638
 * Return value: offset from start of line
 **/
639
gint
640
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
641
642
643
644
{

  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_surreal (iter);
648
649
650
651

  if (real == NULL)
    return 0;

652
653
654
  ensure_char_offsets (real);

  check_invariants (iter);
655
656
657
658

  return real->line_char_offset;
}

659
660
661
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
662
 *
663
664
665
666
667
 * 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.
668
 *
669
670
 * Return value: distance from start of line, in bytes
 **/
671
gint
Havoc Pennington's avatar
Havoc Pennington committed
672
gtk_text_iter_get_line_index (const GtkTextIter *iter)
673
674
675
{
  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_surreal (iter);
679
680
681
682

  if (real == NULL)
    return 0;

683
684
685
  ensure_byte_offsets (real);

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

  return real->line_byte_offset;
}

/*
 * Dereferencing
 */

694
695
696
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
697
 *
698
699
700
 * 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
701
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
702
 * the end iterator, zero is returned; zero is not a valid Unicode character.
703
 * So you can write a loop which ends when gtk_text_iter_get_char ()
704
 * returns 0.
705
 *
706
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
707
 **/
708
gunichar
709
gtk_text_iter_get_char (const GtkTextIter *iter)
710
711
712
{
  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_real (iter);
716
717
718
719

  if (real == NULL)
    return 0;

720
  check_invariants (iter);
721
722
723
724

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

738
739
740
741
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
742
 *
743
744
 * 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
745
 * character 0xFFFC for iterable non-character elements in the buffer,
746
747
 * 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
748
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
749
750
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
751
 *
752
753
 * Return value: slice of text from the buffer
 **/
754
755
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
756
                               const GtkTextIter *end)
757
{
758
759
760
761
762
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
763

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

767
768
769
770
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
771
 *
772
773
774
775
 * 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
776
777
 * gtk_text_iter_get_slice ().
 *
778
779
 * Return value: array of characters from the buffer
 **/
780
781
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
782
                              const GtkTextIter *end)
783
{
784
785
786
787
788
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
789

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

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

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

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

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

  check_invariants (start);
  check_invariants (end);

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

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

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

  real = gtk_text_iter_make_real (iter);
859
860

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

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
865
  if (real->segment->type != &gtk_text_pixbuf_type)
866
    return NULL;
867
  else
Havoc Pennington's avatar
Havoc Pennington committed
868
    return real->segment->body.pixbuf.pixbuf;
869
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
/**
 * 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;
}

901
902
903
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
904
 *
905
906
907
908
909
 * 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.
910
 *
911
912
 * Return value: list of #GtkTextMark
 **/
913
914
915
916
917
918
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
919
920
921
922

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
923
924
925
926

  if (real == NULL)
    return NULL;

927
928
  check_invariants (iter);

929
930
931
932
933
934
  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
935
        retval = g_slist_prepend (retval, seg->body.mark.obj);
936

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

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

945
946
947
948
/**
 * gtk_text_iter_get_toggled_tags:
 * @iter: an iterator
 * @toggled_on: TRUE to get toggled-on tags
949
 *
950
951
952
953
954
955
 * 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.
956
 *
957
958
 * Return value: tags toggled at this point
 **/
959
960
GSList*
gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
961
                                 gboolean            toggled_on)
962
963
964
965
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
966
967
968
969

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
970
971
972
973

  if (real == NULL)
    return NULL;

974
975
  check_invariants (iter);

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

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

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

1003
1004
1005
1006
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag, or NULL
1007
 *
1008
1009
 * 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
1010
 * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
1011
 * <emphasis>start</emphasis> of the tagged range;
1012
 * gtk_text_iter_has_tag () tells you whether an iterator is
1013
 * <emphasis>within</emphasis> a tagged range.
1014
 *
1015
1016
 * Return value: whether @iter is the start of a range tagged with @tag
 **/
1017
1018
gboolean
gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1019
                             GtkTextTag         *tag)
1020
1021
1022
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1023
1024
1025
1026

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1027
1028
1029
1030

  if (real == NULL)
    return FALSE;

1031
1032
  check_invariants (iter);

1033
1034
1035
1036
1037
1038
1039
1040
1041
  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;
        }
1042

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

  return FALSE;
}

1049
1050
1051
1052
1053
1054
1055
/**
 * 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
1056
 * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
1057
 * <emphasis>end</emphasis> of the tagged range;
1058
 * gtk_text_iter_has_tag () tells you whether an iterator is
1059
 * <emphasis>within</emphasis> a tagged range.
1060
 *
1061
 * Return value: whether @iter is the end of a range tagged with @tag
1062
 *
1063
 **/
1064
1065
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1066
                          GtkTextTag         *tag)
1067
1068
1069
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1070
1071
1072
1073

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1074
1075
1076
1077

  if (real == NULL)
    return FALSE;

1078
1079
  check_invariants (iter);

1080
1081
1082
1083
1084
1085
1086
1087
1088
  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;
        }
1089

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

  return FALSE;
}

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

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1117
1118
1119
1120

  if (real == NULL)
    return FALSE;

1121
1122
  check_invariants (iter);

1123
1124
1125
1126
1127
1128
1129
1130
  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;
1131

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

  return FALSE;
}

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

  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);
1157
1158

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

  check_invariants (iter);
1162
1163
1164

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

1176