@@ -459,202 +459,3 @@ function annotated_chartransform(f::Function, str::AnnotatedString, state=nothin
459459 end
460460 AnnotatedString (String (take! (outstr)), annots)
461461end
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