Skip to content

Commit

Permalink
Adjust to change of annotations type in Base
Browse files Browse the repository at this point in the history
By popular demand, the type of an annotation is changing from a
Tuple{UnitRange{Int}, Pair{Symbol, Any}} to a
NamedTuple{(:region, :label, :value), Tuple{UnitRange{Int}, Symbol,
Any}}.

This necessitates some adjustments in the StyledStrings codebase.
  • Loading branch information
tecosaur committed Oct 2, 2024
1 parent d9d7472 commit 056e843
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 151 deletions.
6 changes: 3 additions & 3 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ When concatenating a [`AnnotatedString`](@ref Base.AnnotatedString), take care t
to keep the string annotations.

```jldoctest
julia> str = AnnotatedString("hello there", [(1:5, :word => :greeting), (7:11, :label => 1)])
julia> str = AnnotatedString("hello there", [(1:5, :word, :greeting), (7:11, :label, 1)])
"hello there"
julia> length(str)
Expand All @@ -80,7 +80,7 @@ julia> lpad(str, 14)
julia> typeof(lpad(str, 7))
AnnotatedString{String}
julia> str2 = AnnotatedString(" julia", [(2:6, :face => :magenta)])
julia> str2 = AnnotatedString(" julia", [(2:6, :face, :magenta)])
" julia"
julia> annotatedstring(str, str2)
Expand Down Expand Up @@ -206,7 +206,7 @@ them to the properties list afterwards, or use the convenient [Styled String
literals](@ref stdlib-styledstring-literals).

```@repl demo
str1 = AnnotatedString("blue text", [(1:9, :face => :blue)])
str1 = AnnotatedString("blue text", [(1:9, :face, :blue)])
str2 = styled"{blue:blue text}"
str1 == str2
sprint(print, str1, context = :color => true)
Expand Down
18 changes: 9 additions & 9 deletions src/faces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ function Base.show(io::IO, ::MIME"text/plain", color::SimpleColor)
skiptype || show(io, SimpleColor)
skiptype || print(io, '(')
if get(io, :color, false)::Bool
print(io, AnnotatedString("", [(1:1, :face => Face(foreground=color))]), ' ')
print(io, AnnotatedString("", [(region=1:1, label=:face, value=Face(foreground=color))]), ' ')
end
if color.value isa RGBTuple
(; r, g, b) = color.value
Expand Down Expand Up @@ -222,7 +222,7 @@ function Base.show(io::IO, ::MIME"text/plain", face::Face)
show(io, Face)
if get(io, :color, false)::Bool
# Could do styled"({$face:sample})", but S_str isn't defined yet
print(io, AnnotatedString("(sample)", [(2:7, :face => face)]))
print(io, AnnotatedString("(sample)", [(region=2:7, label=:face, value=face)]))
# elseif get(io, :limit, false)::Bool
# print(io, "(…)")
else
Expand All @@ -244,7 +244,7 @@ function Base.show(io::IO, ::MIME"text/plain", face::Face)
end
else
show(io, Face)
print(io, AnnotatedString(" (sample)", [(3:8, :face => face)]))
print(io, AnnotatedString(" (sample)", [(region=3:8, label=:face, value=face)]))
showcolor(io, color) = show(IOContext(io, :typeinfo => SimpleColor),
MIME("text/plain"), color)
setfields = Pair{Symbol, Any}[]
Expand Down Expand Up @@ -286,7 +286,7 @@ function Base.show(io::IO, ::MIME"text/plain", face::Face)
isfirst = true
for iface in face.inherit
if isfirst; isfirst = false else print(io, ", ") end
print(io, iface, '(', AnnotatedString("*", [(1:1, :face => iface)]), ')')
print(io, iface, '(', AnnotatedString("*", [(region=1:1, label=:face, value=iface)]), ')')
end
end
end
Expand Down Expand Up @@ -555,12 +555,12 @@ function getface(faces)
end

"""
getface(annotations::Vector{Pair{Symbol, Any}})
getface(annotations::Vector{@NamedTuple{label::Symbol, value::Any}})
Combine all of the `:face` annotations with `getfaces`.
"""
function getface(annotations::Vector{Pair{Symbol, Any}})
faces = (last(annot) for annot in annotations if first(annot) === :face)
function getface(annotations::Vector{@NamedTuple{label::Symbol, value::Any}})
faces = (ann.value for ann in annotations if ann.label === :face)
getface(faces)
end

Expand Down Expand Up @@ -599,11 +599,11 @@ Apply `face` to `str`, along `range` if specified or the whole of `str`.
"""
face!(s::Union{<:AnnotatedString, <:SubString{<:AnnotatedString}},
range::UnitRange{Int}, face::Union{Symbol, Face, <:Vector{<:Union{Symbol, Face}}}) =
annotate!(s, range, :face => face)
annotate!(s, range, :face, face)

face!(s::Union{<:AnnotatedString, <:SubString{<:AnnotatedString}},
face::Union{Symbol, Face, <:Vector{<:Union{Symbol, Face}}}) =
annotate!(s, firstindex(s):lastindex(s), :face => face)
annotate!(s, firstindex(s):lastindex(s), :face, face)

## Reading face definitions from a dictionary ##

Expand Down
5 changes: 4 additions & 1 deletion src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,10 @@ function Base.show(io::IO, c::AnnotatedChar)
if get(io, :color, false) == true
out = IOBuffer()
show(out, c.char)
print(io, ''', AnnotatedString(String(take!(out)[2:end-1]), map(a -> (1:ncodeunits(c), a), c.annotations)), ''')
cstr = AnnotatedString(
String(take!(out)[2:end-1]),
[(1:ncodeunits(c), a...) for a in c.annotations])
print(io, ''', cstr, ''')
else
show(io, c.char)
end
Expand Down
31 changes: 16 additions & 15 deletions src/regioniterator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
struct RegionIterator{S <: AbstractString}
str::S
regions::Vector{UnitRange{Int}}
annotations::Vector{Vector{Pair{Symbol, Any}}}
annotations::Vector{Vector{@NamedTuple{label::Symbol, value::Any}}}
end

Base.length(si::RegionIterator) = length(si.regions)
Expand All @@ -15,35 +15,36 @@ Base.@propagate_inbounds function Base.iterate(si::RegionIterator, i::Integer=1)
end

Base.eltype(::RegionIterator{S}) where { S <: AbstractString} =
Tuple{SubString{S}, Vector{Pair{Symbol, Any}}}
Tuple{SubString{S}, Vector{@NamedTuple{label::Symbol, value::Any}}}

"""
eachregion(s::AnnotatedString{S})
eachregion(s::SubString{AnnotatedString{S}})
Identify the contiguous substrings of `s` with a constant annotations, and return
an iterator which provides each substring and the applicable annotations as a
`Tuple{SubString{S}, Vector{Pair{Symbol, Any}}}`.
`Tuple{SubString{S}, Vector{@NamedTuple{label::Symbol, value::Any}}}`.
# Examples
```jldoctest
julia> collect(StyledStrings.eachregion(AnnotatedString(
"hey there", [(1:3, :face => :bold), (5:9, :face => :italic)])))
3-element Vector{Tuple{SubString{String}, Vector{Pair{Symbol, Any}}}}:
("hey", [:face => :bold])
"hey there", [(1:3, :face, :bold), (5:9, :face, :italic)])))
3-element Vector{Tuple{SubString{String}, Vector{@NamedTuple{label::Symbol, value}}}}:
("hey", [@NamedTuple{label::Symbol, value}((:face, :bold))])
(" ", [])
("there", [:face => :italic])
("there", [@NamedTuple{label::Symbol, value}((:face, :italic))])
```
"""
function eachregion(s::AnnotatedString, subregion::UnitRange{Int}=firstindex(s):lastindex(s))
isempty(s) || isempty(subregion) &&
return RegionIterator(s.string, UnitRange{Int}[], Vector{Pair{Symbol, Any}}[])
return RegionIterator(s.string, UnitRange{Int}[], Vector{@NamedTuple{label::Symbol, value::Any}}[])
events = annotation_events(s, subregion)
isempty(events) && return RegionIterator(s.string, [subregion], [Pair{Symbol, Any}[]])
annotvals = last.(annotations(s))
isempty(events) && return RegionIterator(s.string, [subregion], [@NamedTuple{label::Symbol, value::Any}[]])
annotvals = @NamedTuple{label::Symbol, value::Any}[
(; label, value) for (; label, value) in annotations(s)]
regions = Vector{UnitRange{Int}}()
annots = Vector{Vector{Pair{Symbol, Any}}}()
annots = Vector{Vector{@NamedTuple{label::Symbol, value::Any}}}()
pos = first(events).pos
if pos > first(subregion)
push!(regions, thisind(s, first(subregion)):prevind(s, pos))
Expand Down Expand Up @@ -71,14 +72,14 @@ end

function eachregion(s::SubString{<:AnnotatedString}, pos::UnitRange{Int}=firstindex(s):lastindex(s))
if isempty(s)
RegionIterator(s.string, Vector{UnitRange{Int}}(), Vector{Vector{Pair{Symbol, Any}}}())
RegionIterator(s.string, Vector{UnitRange{Int}}(), Vector{Vector{@NamedTuple{label::Symbol, value::Any}}}())
else
eachregion(s.string, first(pos)+s.offset:last(pos)+s.offset)
end
end

"""
annotation_events(string::AbstractString, annots::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, subregion::UnitRange{Int})
annotation_events(string::AbstractString, annots::Vector{@NamedTuple{region::UnitRange{Int}, label::Symbol, value::Any}}, subregion::UnitRange{Int})
annotation_events(string::AnnotatedString, subregion::UnitRange{Int})
Find all annotation "change events" that occur within a `subregion` of `annots`,
Expand All @@ -89,9 +90,9 @@ index::Int}` where `pos` is the position of the event, `active` is a boolean
indicating whether the annotation is being activated or deactivated, and `index`
is the index of the annotation in question.
"""
function annotation_events(s::AbstractString, annots::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, subregion::UnitRange{Int})
function annotation_events(s::AbstractString, annots::Vector{@NamedTuple{region::UnitRange{Int}, label::Symbol, value::Any}}, subregion::UnitRange{Int})
events = Vector{NamedTuple{(:pos, :active, :index), Tuple{Int, Bool, Int}}}() # Position, Active?, Annotation index
for (i, (region, _)) in enumerate(annots)
for (i, (; region)) in enumerate(annots)
if !isempty(intersect(subregion, region))
start, stop = max(first(subregion), first(region)), min(last(subregion), last(region))
start <= stop || continue # Currently can't handle empty regions
Expand Down
Loading

0 comments on commit 056e843

Please sign in to comment.