1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
module TextViewport.Render.RenderState where
import Data.Hashable (Hashable)
import Data.Sequence (Seq)
import Data.Sequence qualified as Seq
import Data.Sequences (Index, Textual)
import TextViewport.Buffer.Buffer (Buffer(Buffer))
import TextViewport.Buffer.Buffer qualified as Buffer
import TextViewport.Buffer.Item
import TextViewport.Render.RenderBuffer (renderBuffer)
import TextViewport.Render.RenderCache (RenderCache(..), emptyRenderCacheFor, resizeCache)
import TextViewport.Render.RenderedBuffer (RenderedBuffer(RenderedBuffer))
import TextViewport.Render.RenderedBuffer qualified as RenderedBuffer
import TextViewport.Render.Segmentation (Segmenter)
data RenderState a seg = RenderState
{ rsBuffer :: Buffer a seg -- original items
, rsCache :: RenderCache a seg -- per-item cached renders
, rsRendered :: RenderedBuffer a -- fully segmented + hyphenated lines
, rsWidth :: Int -- segmenting width
, rsLineCount :: Int
} deriving (Eq, Show)
mkRenderState :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> Buffer a seg -> RenderState a seg
mkRenderState width buf =
let (cache1, rendered) = renderBuffer width buf (emptyRenderCacheFor buf)
in RenderState
{ rsBuffer = buf
, rsCache = cache1
, rsRendered = rendered
, rsWidth = width
, rsLineCount = length (RenderedBuffer.flatten rendered)
}
-- RenderState has to be rebuilt whenever the buffer or the width changes.
updateRenderState :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> Buffer a seg -> RenderState a seg -> RenderState a seg
updateRenderState width buf rs =
let (cache1, rendered) = renderBuffer width buf (rsCache rs)
in rs
{ rsBuffer = buf
, rsCache = cache1
, rsRendered = rendered
, rsWidth = width
, rsLineCount = length (RenderedBuffer.flatten rendered)
}
modifyItemRS :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> (Item a seg -> Item a seg) -> RenderState a seg -> RenderState a seg
modifyItemRS ix f st =
let buf' = Buffer.modifyItem ix f (rsBuffer st)
cache' = resizeCache buf' (rsCache st)
(cache1, rendered1) = renderBuffer (rsWidth st) buf' cache'
in st { rsBuffer = buf'
, rsCache = cache1
, rsRendered = rendered1
, rsLineCount = length (RenderedBuffer.flatten rendered1)
}
insertItem :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> Item a seg -> RenderState a seg -> RenderState a seg
insertItem i newItem st =
let Buffer items = rsBuffer st
items' = Seq.insertAt i newItem items
buf' = Buffer items'
cache' = resizeCache buf' (rsCache st)
(cache1, rendered1) = renderBuffer (rsWidth st) buf' cache'
in st { rsBuffer = buf'
, rsCache = cache1
, rsRendered = rendered1
, rsLineCount = length (RenderedBuffer.flatten rendered1)
}
deleteItem :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> RenderState a seg -> RenderState a seg
deleteItem i st =
let Buffer items = rsBuffer st
items' = Seq.deleteAt i items
buf' = Buffer items'
cache' = resizeCache buf' (rsCache st)
(cache1, rendered1) = renderBuffer (rsWidth st) buf' cache'
in st { rsBuffer = buf'
, rsCache = cache1
, rsRendered = rendered1
, rsLineCount = length (RenderedBuffer.flatten rendered1)
}
replaceItem :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> Item a seg -> RenderState a seg -> RenderState a seg
replaceItem i newItem st =
let Buffer items = rsBuffer st
items' = Seq.update i newItem items
buf' = Buffer items'
cache' = resizeCache buf' (rsCache st)
(cache1, rendered1) = renderBuffer (rsWidth st) buf' cache'
in st { rsBuffer = buf'
, rsCache = cache1
, rsRendered = rendered1
, rsLineCount = length (RenderedBuffer.flatten rendered1)
}
appendItem :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Item a seg -> RenderState a seg -> RenderState a seg
appendItem newItem st =
insertItem (Seq.length (let Buffer xs = rsBuffer st in xs)) newItem st
clearBuffer :: RenderState a seg -> RenderState a seg
clearBuffer st =
let buf' = Buffer Seq.empty
cache' = RenderCache Seq.empty
in st { rsBuffer = buf'
, rsCache = cache'
, rsRendered = RenderedBuffer Seq.empty
, rsLineCount = 0
}
fromList :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> [Item a seg] -> RenderState a seg
fromList width xs =
let buf = Buffer (Seq.fromList xs)
cache0 = RenderCache (Seq.replicate (length xs) Nothing)
(cache1, rendered) = renderBuffer width buf cache0
in RenderState
{ rsBuffer = buf
, rsCache = cache1
, rsRendered = rendered
, rsWidth = width
, rsLineCount = length (RenderedBuffer.flatten rendered)
}
fromSeq :: (Segmenter seg a, Hashable a, Textual a, Index a ~ Int) => Int -> Seq (Item a seg) -> RenderState a seg
fromSeq width items =
let buf = Buffer items
cache0 = RenderCache (Seq.replicate (Seq.length items) Nothing)
(cache1, rendered) = renderBuffer width buf cache0
in RenderState
{ rsBuffer = buf
, rsCache = cache1
, rsRendered = rendered
, rsWidth = width
, rsLineCount = length (RenderedBuffer.flatten rendered)
}
|