@@ -459,202 +459,3 @@ function annotated_chartransform(f::Function, str::AnnotatedString, state=nothin
459
459
end
460
460
AnnotatedString (String (take! (outstr)), annots)
461
461
end
462
-
463
- # # AnnotatedIOBuffer
464
-
465
- struct AnnotatedIOBuffer <: AbstractPipe
466
- io:: IOBuffer
467
- annotations:: Vector{RegionAnnotation}
468
- end
469
-
470
- AnnotatedIOBuffer (io:: IOBuffer ) = AnnotatedIOBuffer (io, Vector {RegionAnnotation} ())
471
- AnnotatedIOBuffer () = AnnotatedIOBuffer (IOBuffer ())
472
-
473
- function show (io:: IO , aio:: AnnotatedIOBuffer )
474
- show (io, AnnotatedIOBuffer)
475
- size = filesize (aio. io)
476
- print (io, ' (' , size, " byte" , ifelse (size == 1 , " " , " s" ), " , " ,
477
- length (aio. annotations), " annotation" , ifelse (length (aio. annotations) == 1 , " " , " s" ), " )" )
478
- end
479
-
480
- pipe_reader (io:: AnnotatedIOBuffer ) = io. io
481
- pipe_writer (io:: AnnotatedIOBuffer ) = io. io
482
-
483
- # Useful `IOBuffer` methods that we don't get from `AbstractPipe`
484
- position (io:: AnnotatedIOBuffer ) = position (io. io)
485
- seek (io:: AnnotatedIOBuffer , n:: Integer ) = (seek (io. io, n); io)
486
- seekend (io:: AnnotatedIOBuffer ) = (seekend (io. io); io)
487
- skip (io:: AnnotatedIOBuffer , n:: Integer ) = (skip (io. io, n); io)
488
- copy (io:: AnnotatedIOBuffer ) = AnnotatedIOBuffer (copy (io. io), copy (io. annotations))
489
-
490
- annotations (io:: AnnotatedIOBuffer ) = io. annotations
491
-
492
- annotate! (io:: AnnotatedIOBuffer , range:: UnitRange{Int} , label:: Symbol , @nospecialize (val:: Any )) =
493
- (_annotate! (io. annotations, range, label, val); io)
494
-
495
- function write (io:: AnnotatedIOBuffer , astr:: Union{AnnotatedString, SubString{<:AnnotatedString}} )
496
- astr = AnnotatedString (astr)
497
- offset = position (io. io)
498
- eof (io) || _clear_annotations_in_region! (io. annotations, offset+ 1 : offset+ ncodeunits (astr))
499
- _insert_annotations! (io, astr. annotations)
500
- write (io. io, String (astr))
501
- end
502
-
503
- write (io:: AnnotatedIOBuffer , c:: AnnotatedChar ) =
504
- write (io, AnnotatedString (string (c), [(region= 1 : ncodeunits (c), a... ) for a in c. annotations]))
505
- write (io:: AnnotatedIOBuffer , x:: AbstractString ) = write (io. io, x)
506
- write (io:: AnnotatedIOBuffer , s:: Union{SubString{String}, String} ) = write (io. io, s)
507
- write (io:: AnnotatedIOBuffer , b:: UInt8 ) = write (io. io, b)
508
-
509
- function write (dest:: AnnotatedIOBuffer , src:: AnnotatedIOBuffer )
510
- destpos = position (dest)
511
- isappending = eof (dest)
512
- srcpos = position (src)
513
- nb = write (dest. io, src. io)
514
- isappending || _clear_annotations_in_region! (dest. annotations, destpos: destpos+ nb)
515
- srcannots = [setindex (annot, max (1 + srcpos, first (annot. region)): last (annot. region), :region )
516
- for annot in src. annotations if first (annot. region) >= srcpos]
517
- _insert_annotations! (dest, srcannots, destpos - srcpos)
518
- nb
519
- end
520
-
521
- # So that read/writes with `IOContext` (and any similar `AbstractPipe` wrappers)
522
- # work as expected.
523
- function write (io:: AbstractPipe , s:: Union{AnnotatedString, SubString{<:AnnotatedString}} )
524
- if pipe_writer (io) isa AnnotatedIOBuffer
525
- write (pipe_writer (io), s)
526
- else
527
- invoke (write, Tuple{IO, typeof (s)}, io, s)
528
- end :: Int
529
- end
530
- # Can't be part of the `Union` above because it introduces method ambiguities
531
- function write (io:: AbstractPipe , c:: AnnotatedChar )
532
- if pipe_writer (io) isa AnnotatedIOBuffer
533
- write (pipe_writer (io), c)
534
- else
535
- invoke (write, Tuple{IO, typeof (c)}, io, c)
536
- end :: Int
537
- end
538
-
539
- """
540
- _clear_annotations_in_region!(annotations::Vector{$RegionAnnotation }, span::UnitRange{Int})
541
-
542
- Erase the presence of `annotations` within a certain `span`.
543
-
544
- This operates by removing all elements of `annotations` that are entirely
545
- contained in `span`, truncating ranges that partially overlap, and splitting
546
- annotations that subsume `span` to just exist either side of `span`.
547
- """
548
- function _clear_annotations_in_region! (annotations:: Vector{RegionAnnotation} , span:: UnitRange{Int} )
549
- # Clear out any overlapping pre-existing annotations.
550
- filter! (ann -> first (ann. region) < first (span) || last (ann. region) > last (span), annotations)
551
- extras = Tuple{Int, RegionAnnotation}[]
552
- for i in eachindex (annotations)
553
- annot = annotations[i]
554
- region = annot. region
555
- # Test for partial overlap
556
- if first (region) <= first (span) <= last (region) || first (region) <= last (span) <= last (region)
557
- annotations[i] =
558
- setindex (annot,
559
- if first (region) < first (span)
560
- first (region): first (span)- 1
561
- else
562
- last (span)+ 1 : last (region)
563
- end ,
564
- :region )
565
- # If `span` fits exactly within `region`, then we've only copied over
566
- # the beginning overhang, but also need to conserve the end overhang.
567
- if first (region) < first (span) && last (span) < last (region)
568
- push! (extras, (i, setindex (annot, last (span)+ 1 : last (region), :region )))
569
- end
570
- end
571
- end
572
- # Insert any extra entries in the appropriate position
573
- for (offset, (i, entry)) in enumerate (extras)
574
- insert! (annotations, i + offset, entry)
575
- end
576
- annotations
577
- end
578
-
579
- """
580
- _insert_annotations!(io::AnnotatedIOBuffer, annotations::Vector{$RegionAnnotation }, offset::Int = position(io))
581
-
582
- Register new `annotations` in `io`, applying an `offset` to their regions.
583
-
584
- The largely consists of simply shifting the regions of `annotations` by `offset`
585
- and pushing them onto `io`'s annotations. However, when it is possible to merge
586
- the new annotations with recent annotations in accordance with the semantics
587
- outlined in [`AnnotatedString`](@ref), we do so. More specifically, when there
588
- is a run of the most recent annotations that are also present as the first
589
- `annotations`, with the same value and adjacent regions, the new annotations are
590
- merged into the existing recent annotations by simply extending their range.
591
-
592
- This is implemented so that one can say write an `AnnotatedString` to an
593
- `AnnotatedIOBuffer` one character at a time without needlessly producing a
594
- new annotation for each character.
595
- """
596
- function _insert_annotations! (io:: AnnotatedIOBuffer , annotations:: Vector{RegionAnnotation} , offset:: Int = position (io))
597
- run = 0
598
- if ! isempty (io. annotations) && last (last (io. annotations). region) == offset
599
- for i in reverse (axes (annotations, 1 ))
600
- annot = annotations[i]
601
- first (annot. region) == 1 || continue
602
- i <= length (io. annotations) || continue
603
- if annot. label == last (io. annotations). label && annot. value == last (io. annotations). value
604
- valid_run = true
605
- for runlen in 1 : i
606
- new = annotations[begin + runlen- 1 ]
607
- old = io. annotations[end - i+ runlen]
608
- if last (old. region) != offset || first (new. region) != 1 || old. label != new. label || old. value != new. value
609
- valid_run = false
610
- break
611
- end
612
- end
613
- if valid_run
614
- run = i
615
- break
616
- end
617
- end
618
- end
619
- end
620
- for runindex in 0 : run- 1
621
- old_index = lastindex (io. annotations) - run + 1 + runindex
622
- old = io. annotations[old_index]
623
- new = annotations[begin + runindex]
624
- io. annotations[old_index] = setindex (old, first (old. region): last (new. region)+ offset, :region )
625
- end
626
- for index in run+ 1 : lastindex (annotations)
627
- annot = annotations[index]
628
- start, stop = first (annot. region), last (annot. region)
629
- push! (io. annotations, setindex (annotations[index], start+ offset: stop+ offset, :region ))
630
- end
631
- end
632
-
633
- function read (io:: AnnotatedIOBuffer , :: Type{AnnotatedString{T}} ) where {T <: AbstractString }
634
- if (start = position (io)) == 0
635
- AnnotatedString (read (io. io, T), copy (io. annotations))
636
- else
637
- annots = [setindex (annot, UnitRange {Int} (max (1 , first (annot. region) - start), last (annot. region)- start), :region )
638
- for annot in io. annotations if last (annot. region) > start]
639
- AnnotatedString (read (io. io, T), annots)
640
- end
641
- end
642
- read (io:: AnnotatedIOBuffer , :: Type{AnnotatedString{AbstractString}} ) = read (io, AnnotatedString{String})
643
- read (io:: AnnotatedIOBuffer , :: Type{AnnotatedString} ) = read (io, AnnotatedString{String})
644
-
645
- function read (io:: AnnotatedIOBuffer , :: Type{AnnotatedChar{T}} ) where {T <: AbstractChar }
646
- pos = position (io)
647
- char = read (io. io, T)
648
- annots = [NamedTuple {(:label, :value)} (annot) for annot in io. annotations if pos+ 1 in annot. region]
649
- AnnotatedChar (char, annots)
650
- end
651
- read (io:: AnnotatedIOBuffer , :: Type{AnnotatedChar{AbstractChar}} ) = read (io, AnnotatedChar{Char})
652
- read (io:: AnnotatedIOBuffer , :: Type{AnnotatedChar} ) = read (io, AnnotatedChar{Char})
653
-
654
- function truncate (io:: AnnotatedIOBuffer , size:: Integer )
655
- truncate (io. io, size)
656
- filter! (ann -> first (ann. region) <= size, io. annotations)
657
- map! (ann -> setindex (ann, first (ann. region): min (size, last (ann. region)), :region ),
658
- io. annotations, io. annotations)
659
- io
660
- end
0 commit comments