https://github.com/akkartik/mu/blob/main/baremetal/shell/line.mu
1 type line {
2 name: (handle array byte)
3 data: (handle word)
4 cursor: (handle word)
5 next: (handle line)
6 prev: (handle line)
7 }
8
9
10 fn initialize-line _line: (addr line) {
11 var line/esi: (addr line) <- copy _line
12 var word-ah/eax: (addr handle word) <- get line, data
13 allocate word-ah
14 var cursor-ah/ecx: (addr handle word) <- get line, cursor
15 copy-object word-ah, cursor-ah
16 var word/eax: (addr word) <- lookup *word-ah
17 initialize-word word
18 }
19
20 fn num-words-in-line _in: (addr line) -> _/eax: int {
21 var in/esi: (addr line) <- copy _in
22 var curr-ah/ecx: (addr handle word) <- get in, data
23 var result/edi: int <- copy 0
24 {
25 var curr/eax: (addr word) <- lookup *curr-ah
26 compare curr, 0
27 break-if-=
28 curr-ah <- get curr, next
29 result <- increment
30 loop
31 }
32 return result
33 }
34
35 fn line-list-length lines: (addr handle line) -> _/eax: int {
36 var curr-ah/esi: (addr handle line) <- copy lines
37 var result/edi: int <- copy 0
38 {
39 var curr/eax: (addr line) <- lookup *curr-ah
40 compare curr, 0
41 break-if-=
42 curr-ah <- get curr, next
43 result <- increment
44 loop
45 }
46 return result
47 }
48
49 fn render-line screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int {
50 var line/eax: (addr line) <- copy _line
51 var first-word-ah/esi: (addr handle word) <- get line, data
52
53 var cursor-word/edi: int <- copy 0
54 compare render-cursor?, 0/false
55 {
56 break-if-=
57 var cursor-word-ah/eax: (addr handle word) <- get line, cursor
58 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
59 cursor-word <- copy _cursor-word
60 }
61
62 var result/eax: int <- render-words screen, first-word-ah, x, y, cursor-word
63 return result
64 }
65
66 fn parse-line in: (addr array byte), _out: (addr line) {
67 var out/edi: (addr line) <- copy _out
68 initialize-line out
69 var dest/eax: (addr handle word) <- get out, data
70 parse-words in, dest
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 fn render-line-with-stack screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int, _/ecx: int {
90 var line/esi: (addr line) <- copy _line
91
92 var cursor-word/edi: int <- copy 0
93 compare render-cursor?, 0/false
94 {
95 break-if-=
96 var cursor-word-ah/eax: (addr handle word) <- get line, cursor
97 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
98 cursor-word <- copy _cursor-word
99 }
100
101 var curr-word-ah/eax: (addr handle word) <- get line, data
102 var _curr-word/eax: (addr word) <- lookup *curr-word-ah
103 var curr-word/edx: (addr word) <- copy _curr-word
104 var new-x/eax: int <- copy x
105 var new-y/ebx: int <- copy y
106 {
107 compare curr-word, 0
108 break-if-=
109 var curr-y/ecx: int <- copy 0
110 new-x, curr-y <- render-word-with-stack-and-cursor screen, line, curr-word, new-x, y, cursor-word
111 compare curr-y, new-y
112 {
113 break-if-<=
114 new-y <- copy curr-y
115 }
116 new-x <- add 1/inter-word-spacing
117
118 var next-word-ah/eax: (addr handle word) <- get curr-word, next
119 var next-word/eax: (addr word) <- lookup *next-word-ah
120 curr-word <- copy next-word
121 loop
122 }
123 return new-x, new-y
124 }
125
126 fn render-word-with-stack-and-cursor screen: (addr screen), line: (addr line), curr-word: (addr word), x: int, y: int, _cursor-word-addr: int -> _/eax: int, _/ecx: int {
127
128 var render-cursor?/eax: boolean <- copy 0/false
129 var cursor-word-addr/ecx: int <- copy _cursor-word-addr
130 {
131 compare cursor-word-addr, curr-word
132 break-if-!=
133 render-cursor? <- copy 1/true
134 }
135 var new-x/eax: int <- render-word screen, curr-word, x, y, render-cursor?
136 var new-x-saved/edx: int <- copy new-x
137 add-to y, 2/word-stack-spacing
138
139 var stack-storage: value-stack
140 var stack/edi: (addr value-stack) <- address stack-storage
141 evaluate line, curr-word, stack
142
143 var new-y/ecx: int <- copy 0
144 new-x, new-y <- render-value-stack screen, stack, x, y
145
146
147 compare new-x, new-x-saved
148 {
149 break-if->=
150 new-x <- copy new-x-saved
151 }
152
153 return new-x, new-y
154 }
155
156 fn test-render-line-with-stack-singleton {
157
158 var line-storage: line
159 var line/esi: (addr line) <- address line-storage
160 parse-line "1", line
161
162 var screen-on-stack: screen
163 var screen/edi: (addr screen) <- address screen-on-stack
164 initialize-screen screen, 0x20, 4
165
166 var new-x/eax: int <- copy 0
167 var new-y/ecx: int <- copy 0
168 new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
169 check-screen-row screen, 0/y, "1 ", "F - test-render-line-with-stack-singleton/0"
170 check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack-singleton/1"
171 check-screen-row screen, 2/y, " 1 ", "F - test-render-line-with-stack-singleton/2"
172
173 }
174
175 fn test-render-line-with-stack {
176
177 var line-storage: line
178 var line/esi: (addr line) <- address line-storage
179 parse-line "1 2", line
180
181 var screen-on-stack: screen
182 var screen/edi: (addr screen) <- address screen-on-stack
183 initialize-screen screen, 0x20, 4
184
185 var new-x/eax: int <- copy 0
186 var new-y/ecx: int <- copy 0
187 new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
188 check-screen-row screen, 0/y, "1 2 ", "F - test-render-line-with-stack/0"
189 check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack/1"
190
191 check-screen-row screen, 2/y, " 1 2 ", "F - test-render-line-with-stack/2"
192 check-screen-row screen, 3/y, " 1 ", "F - test-render-line-with-stack/3"
193
194 }
195
196 fn edit-line _self: (addr line), key: byte {
197 var self/esi: (addr line) <- copy _self
198 var cursor-word-ah/edx: (addr handle word) <- get self, cursor
199 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
200 var cursor-word/ecx: (addr word) <- copy _cursor-word
201 compare key, 0x20/space
202 $edit-line:space: {
203 break-if-!=
204 append-word cursor-word-ah
205 var next-word-ah/eax: (addr handle word) <- get cursor-word, next
206 copy-object next-word-ah, cursor-word-ah
207 return
208 }
209
210 var g/edx: grapheme <- copy key
211 add-grapheme-to-word cursor-word, g
212
213 }
214
215 fn main {
216 var line-storage: line
217 var line/esi: (addr line) <- address line-storage
218 initialize-line line
219 $main:loop: {
220 clear-screen 0/screen
221 var dummy1/eax: int <- copy 0
222 var dummy2/ecx: int <- copy 0
223 dummy1, dummy2 <- render-line-with-stack 0/screen, line, 2/x, 2/y, 1/show-cursor
224 {
225 var key/eax: byte <- read-key 0/keyboard
226 compare key, 0
227 loop-if-=
228 compare key, 0x71/q
229 break-if-= $main:loop
230 edit-line line, key
231 }
232 loop
233 }
234 }