@@ -36,37 +36,71 @@ julia> collect(StyledStrings.eachregion(Base.AnnotatedString(
36
36
("there", [:face => :italic])
37
37
```
38
38
"""
39
- function eachregion (s:: AnnotatedString , region:: UnitRange{Int} = firstindex (s): lastindex (s))
40
- isempty (s) || isempty (region) &&
41
- return RegionIterator (s, Vector {UnitRange{Int}} (), Vector {Vector{Pair{Symbol, Any}}} ())
39
+ function eachregion (s:: AnnotatedString , subregion:: UnitRange{Int} = firstindex (s): lastindex (s))
40
+ isempty (s) || isempty (subregion) &&
41
+ return RegionIterator (s. string, UnitRange{Int}[], Vector{Pair{Symbol, Any}}[])
42
+ events = annotation_events (s, subregion)
43
+ isempty (events) && return RegionIterator (s. string, [subregion], [Pair{Symbol, Any}[]])
44
+ annotvals = last .(annotations (s))
42
45
regions = Vector {UnitRange{Int}} ()
43
46
annots = Vector {Vector{Pair{Symbol, Any}}} ()
44
- changepoints = filter (c -> c in region,
45
- Iterators. flatten ((first (region), nextind (s, last (region)))
46
- for region in first .(s. annotations)) |>
47
- unique |> sort)
48
- isempty (changepoints) &&
49
- return RegionIterator (s. string, UnitRange{Int}[region], Vector{Pair{Symbol, Any}}[map (last, annotations (s, first (region)))])
50
- function registerchange! (start, stop)
51
- push! (regions, start: stop)
52
- push! (annots, map (last, annotations (s, start)))
47
+ pos = first (events). pos
48
+ if pos > first (subregion)
49
+ push! (regions, first (subregion): pos- 1 )
50
+ push! (annots, [])
53
51
end
54
- if first (region) < first (changepoints)
55
- registerchange! (first (region), prevind (s, first (changepoints)))
52
+ activelist = Int[]
53
+ for event in events
54
+ if event. pos != pos
55
+ push! (regions, pos: prevind (s, event. pos))
56
+ push! (annots, annotvals[activelist])
57
+ pos = event. pos
58
+ end
59
+ if event. active
60
+ insert! (activelist, searchsortedfirst (activelist, event. index), event. index)
61
+ else
62
+ deleteat! (activelist, searchsortedfirst (activelist, event. index))
63
+ end
56
64
end
57
- for (start, stop) in zip (changepoints, changepoints[2 : end ])
58
- registerchange! (start, prevind (s, stop))
59
- end
60
- if last (changepoints) <= last (region)
61
- registerchange! (last (changepoints), last (region))
65
+ if last (events). pos < nextind (s, last (subregion))
66
+ push! (regions, last (events). pos: last (subregion))
67
+ push! (annots, [])
62
68
end
63
69
RegionIterator (s. string, regions, annots)
64
70
end
65
71
66
- function eachregion (s:: SubString{<:AnnotatedString} , region :: UnitRange{Int} = firstindex (s): lastindex (s))
72
+ function eachregion (s:: SubString{<:AnnotatedString} , pos :: UnitRange{Int} = firstindex (s): lastindex (s))
67
73
if isempty (s)
68
- RegionIterator (s, Vector {UnitRange{Int}} (), Vector {Vector{Pair{Symbol, Any}}} ())
74
+ RegionIterator (s. string , Vector {UnitRange{Int}} (), Vector {Vector{Pair{Symbol, Any}}} ())
69
75
else
70
- eachregion (s. string, first (region )+ s. offset: last (region )+ s. offset)
76
+ eachregion (s. string, first (pos )+ s. offset: last (pos )+ s. offset)
71
77
end
72
78
end
79
+
80
+ """
81
+ annotation_events(string::AbstractString, annots::Vector{Tuple{UnitRange{Int64}, Pair{Symbol, Any}}}, subregion::UnitRange{Int})
82
+ annotation_events(string::AnnotatedString, subregion::UnitRange{Int})
83
+
84
+ Find all annotation "change events" that occur within a `subregion` of `annots`,
85
+ with respect to `string`. When `string` is styled, `annots` is inferred.
86
+
87
+ Each change event is given in the form of a `@NamedTuple{pos::Int, active::Bool,
88
+ index::Int}` where `pos` is the position of the event, `active` is a boolean
89
+ indicating whether the annotation is being activated or deactivated, and `index`
90
+ is the index of the annotation in question.
91
+ """
92
+ function annotation_events (s:: AbstractString , annots:: Vector{Tuple{UnitRange{Int64}, Pair{Symbol, Any}}} , subregion:: UnitRange{Int} )
93
+ events = Vector {NamedTuple{(:pos, :active, :index), Tuple{Int, Bool, Int}}} () # Position, Active?, Annotation index
94
+ for (i, (region, _)) in enumerate (annots)
95
+ if ! isempty (intersect (subregion, region))
96
+ start, stop = max (first (subregion), first (region)), min (last (subregion), last (region))
97
+ start <= stop || continue # Currently can't handle empty regions
98
+ push! (events, (pos= start, active= true , index= i))
99
+ push! (events, (pos= nextind (s, stop), active= false , index= i))
100
+ end
101
+ end
102
+ sort (events, by= e -> e. pos)
103
+ end
104
+
105
+ annotation_events (s:: AnnotatedString , subregion:: UnitRange{Int} ) =
106
+ annotation_events (s. string, annotations (s), subregion)
0 commit comments