3 | module Text.ByteRange
6 | import Derive.Prelude
7 | import public Data.ByteString
8 | import public Text.ByteBounds
11 | %language ElabReflection
33 | {auto 0 prf : IsSucc bytes.size}
35 | %runElab derive "Chunk" [Show]
38 | lineCount : ByteString -> Nat
39 | lineCount = flip foldr Z $
\b,n => case b of {
0xa => S n;
_ => n}
43 | (.last) : Chunk -> BytePos
44 | b.last = incLen b.bytes.size b.first
48 | (.next) : Chunk -> BytePos
49 | b.next = BP (b.first.pos + b.bytes.size)
53 | (.linesIncluding) : Chunk -> Nat
54 | b.linesIncluding = b.linesBefore + b.lines
59 | nextChunk : Maybe Chunk -> (bs : ByteString) -> (0 p : IsSucc bs.size) => Chunk
60 | nextChunk Nothing bs = CH bs 0 0 (lineCount bs)
61 | nextChunk (Just c) bs = CH bs c.next c.linesIncluding (lineCount bs)
63 | dropPartialLine : Chunk -> SnocList Chunk
65 | let (pre, BS (S $
S k) pst) := break (0xa ==) c.bytes | _ => [<]
66 | p := BP $
c.first.pos + pre.size + 1
67 | in [<CH (BS (S k) $
tail pst) p (S c.linesBefore) (pred c.lines)]
72 | data ByteRange : Type where
73 | Prefix : SnocList Chunk -> ByteRange
74 | Start : SnocList Chunk -> ByteRange
75 | End : SnocList Chunk -> ByteRange
76 | Done : SnocList Chunk -> ByteRange
79 | %runElab derive "ByteRange" [Show]
82 | isDone : ByteRange -> Bool
83 | isDone (Done _) = True
86 | containsEnd : ByteRange -> Bool
87 | containsEnd (End _) = True
88 | containsEnd r = isDone r
91 | chunks : ByteRange -> SnocList Chunk
92 | chunks (Prefix sx) = sx
93 | chunks (Start sx) = sx
94 | chunks (End sx) = sx
95 | chunks (Done sx) = sx
98 | lastChunk : SnocList Chunk -> Maybe Chunk
99 | lastChunk [<] = Nothing
100 | lastChunk (_:<c) = Just c
102 | pre : List Chunk -> SnocList Chunk -> Nat -> ByteRange
103 | pre cs [<] _ = Prefix ([<] <>< cs)
105 | case n `minus` c.lines of
106 | 0 => Start (dropPartialLine c <>< cs)
107 | n => pre (c::cs) sc n
114 | appendChunk : (s,e : BytePos) -> ByteRange -> ByteString -> ByteRange
115 | appendChunk _ _ r@(Done _) _ = r
116 | appendChunk _ _ r (BS 0 _) = r
117 | appendChunk s e r bs@(BS (S _) _) =
119 | c := nextChunk (lastChunk cs) bs
122 | in case c.last >= e of
123 | True => if containsEnd r && c.lines > 0 then Done cs2 else End cs2
124 | False => case c.last >= s of
126 | False => pre [] cs2 MIN_LINES
141 | enclosingBytes : Foldable f => (s,e : BytePos) -> f ByteString -> ByteRange
142 | enclosingBytes s e = foldl (appendChunk s e) None
146 | record TextBounds where
160 | %runElab derive "TextBounds" [Show,Eq]
162 | bounds : (line : Nat) -> ByteBounds -> ByteString -> TextBounds
163 | bounds line bb bs =
164 | let ini := P line 0
165 | m := bytePositionMapFrom ini bs
167 | in TB (toString bs) abs (relativeTo abs ini)
174 | textBounds : (start, end : BytePos) -> ByteRange -> Maybe TextBounds
176 | case containsEnd r of
179 | let c::cs := chunks r <>> [] | _ => Nothing
180 | bs := fastConcat (map bytes $
c::cs)
182 | in Just $
bounds c.linesBefore (BB (offsetTo o s) (offsetTo o e)) bs
185 | toFCErr : ByteError e -> TextBounds -> FCErr e
186 | toFCErr (BE o _ _ x) (TB c a r) = PE o a r (Just c) x