https://github.com/akkartik/mu/blob/main/shell/global.mu
1 type global-table {
2 data: (handle array global)
3 final-index: int
4 cursor-index: int
5 }
6
7 type global {
8 name: (handle array byte)
9 input: (handle gap-buffer)
10 value: (handle cell)
11 trace: (handle trace)
12 }
13
14 fn initialize-globals _self: (addr global-table) {
15 var self/esi: (addr global-table) <- copy _self
16 compare self, 0
17 {
18 break-if-!=
19 abort "initialize globals"
20 return
21 }
22 var data-ah/eax: (addr handle array global) <- get self, data
23 populate data-ah, 0x80
24 initialize-primitives self
25 }
26
27 fn load-globals in: (addr handle cell), self: (addr global-table) {
28 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading globals:", 3/fg, 0/bg
29 var remaining-ah/esi: (addr handle cell) <- copy in
30 {
31 var _remaining/eax: (addr cell) <- lookup *remaining-ah
32 var remaining/ebx: (addr cell) <- copy _remaining
33 var done?/eax: boolean <- nil? remaining
34 compare done?, 0/false
35 break-if-!=
36 var curr-ah/eax: (addr handle cell) <- get remaining, left
37 var _curr/eax: (addr cell) <- lookup *curr-ah
38 var curr/ecx: (addr cell) <- copy _curr
39 remaining-ah <- get remaining, right
40 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " ", 2/fg 0/bg
41 var name-ah/eax: (addr handle cell) <- get curr, left
42 var name/eax: (addr cell) <- lookup *name-ah
43 var name-data-ah/eax: (addr handle stream byte) <- get name, text-data
44 var _name-data/eax: (addr stream byte) <- lookup *name-data-ah
45 var name-data/edx: (addr stream byte) <- copy _name-data
46 rewind-stream name-data
47 draw-stream-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, name-data, 3/fg, 0/bg
48 var value-ah/eax: (addr handle cell) <- get curr, right
49 var value/eax: (addr cell) <- lookup *value-ah
50 var value-data-ah/eax: (addr handle stream byte) <- get value, text-data
51 var _value-data/eax: (addr stream byte) <- lookup *value-data-ah
52 var value-data/ecx: (addr stream byte) <- copy _value-data
53 var value-gap-buffer-storage: (handle gap-buffer)
54 var value-gap-buffer-ah/edi: (addr handle gap-buffer) <- address value-gap-buffer-storage
55 allocate value-gap-buffer-ah
56 var value-gap-buffer/eax: (addr gap-buffer) <- lookup *value-gap-buffer-ah
57 initialize-gap-buffer value-gap-buffer, 0x1000/4KB
58 load-gap-buffer-from-stream value-gap-buffer, value-data
59 load-lexical-scope value-gap-buffer-ah, self
60 loop
61 }
62 move-cursor-to-left-margin-of-next-line 0/screen
63 }
64
65 fn write-globals out: (addr stream byte), _self: (addr global-table) {
66 var self/esi: (addr global-table) <- copy _self
67 compare self, 0
68 {
69 break-if-!=
70 abort "write globals"
71 return
72 }
73 write out, " (globals . (\n"
74 var data-ah/eax: (addr handle array global) <- get self, data
75 var data/eax: (addr array global) <- lookup *data-ah
76 var final-index/edx: (addr int) <- get self, final-index
77 var curr-index/ecx: int <- copy 1/skip-0
78 {
79 compare curr-index, *final-index
80 break-if->
81 var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
82 var curr/ebx: (addr global) <- index data, curr-offset
83 var curr-value-ah/edx: (addr handle cell) <- get curr, value
84 var curr-value/eax: (addr cell) <- lookup *curr-value-ah
85 var curr-type/eax: (addr int) <- get curr-value, type
86 {
87 compare *curr-type, 4/primitive-function
88 break-if-=
89 compare *curr-type, 5/screen
90 break-if-=
91 compare *curr-type, 6/keyboard
92 break-if-=
93 compare *curr-type, 3/stream
94 break-if-=
95 write out, " ("
96 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
97 var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
98 write out, curr-name
99 write out, " . ["
100 var curr-input-ah/eax: (addr handle gap-buffer) <- get curr, input
101 var curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
102 {
103 compare curr-input, 0
104 break-if-!=
105 abort "null gap buffer"
106 }
107 append-gap-buffer curr-input, out
108 write out, "])\n"
109 }
110 curr-index <- increment
111 loop
112 }
113 write out, " ))\n"
114 }
115
116
117 fn render-globals screen: (addr screen), _self: (addr global-table), show-cursor?: boolean {
118 clear-rect screen, 0/xmin, 0/ymin, 0x55/xmax, 0x2f/ymax=screen-height-without-menu, 0xdc/bg=green-bg
119 var self/esi: (addr global-table) <- copy _self
120 compare self, 0
121 {
122 break-if-!=
123 abort "render globals"
124 return
125 }
126 var data-ah/eax: (addr handle array global) <- get self, data
127 var data/eax: (addr array global) <- lookup *data-ah
128 var curr-index/edx: int <- copy 1
129 {
130 var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
131 var curr/ebx: (addr global) <- index data, curr-offset
132 var continue?/eax: boolean <- primitive-global? curr
133 compare continue?, 0/false
134 break-if-=
135 curr-index <- increment
136 loop
137 }
138 var lowest-index/edi: int <- copy curr-index
139 var cursor-index/edx: (addr int) <- get self, cursor-index
140 var curr-index/edx: int <- copy *cursor-index
141 var y1: int
142 copy-to y1, 1/padding-top
143 var y2: int
144 copy-to y2, 1/padding-top
145 $render-globals:loop: {
146 compare curr-index, lowest-index
147 break-if-<
148 {
149 compare y1, 0x2f/ymax
150 break-if-<
151 compare y2, 0x2f/ymax
152 break-if-<
153 break $render-globals:loop
154 }
155 {
156 var cursor-in-current-line?: boolean
157 {
158 compare show-cursor?, 0/false
159 break-if-=
160 var cursor-index/eax: (addr int) <- get self, cursor-index
161 compare *cursor-index, curr-index
162 break-if-!=
163 copy-to cursor-in-current-line?, 1/true
164 }
165 var curr-offset/edx: (offset global) <- compute-offset data, curr-index
166 var curr/edx: (addr global) <- index data, curr-offset
167 var curr-input-ah/eax: (addr handle gap-buffer) <- get curr, input
168 var _curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
169 var curr-input/ebx: (addr gap-buffer) <- copy _curr-input
170 compare curr-input, 0
171 break-if-=
172 var curr-trace-ah/eax: (addr handle trace) <- get curr, trace
173 var _curr-trace/eax: (addr trace) <- lookup *curr-trace-ah
174 var curr-trace/edx: (addr trace) <- copy _curr-trace
175 $render-globals:render-global: {
176 var x/eax: int <- copy 0
177 var y/ecx: int <- copy y1
178 compare y, y2
179 {
180 break-if->=
181 x, y <- render-gap-buffer-wrapping-right-then-down screen, curr-input, 1/padding-left, y1, 0x2a/xmax, 0x2f/ymax, cursor-in-current-line?, 7/fg=definition, 0xc5/bg=blue-bg
182 y <- increment
183 y <- render-trace screen, curr-trace, 1/padding-left, y, 0x2a/xmax, 0x2f/ymax, 0/no-cursor
184 y <- increment
185 copy-to y1, y
186 break $render-globals:render-global
187 }
188 x, y <- render-gap-buffer-wrapping-right-then-down screen, curr-input, 0x2b/xmin, y2, 0x54/xmax, 0x2f/ymax, cursor-in-current-line?, 7/fg=definition, 0xc5/bg=blue-bg
189 y <- increment
190 y <- render-trace screen, curr-trace, 0x2b/xmin, y, 0x54/xmax, 0x2f/ymax, 0/no-cursor
191 y <- increment
192 copy-to y2, y
193 }
194 }
195 curr-index <- decrement
196 loop
197 }
198
199 render-primitives screen, 1/xmin=padding-left, 0x55/xmax, 0x2f/ymax
200 }
201
202 fn render-globals-menu screen: (addr screen), _self: (addr global-table) {
203 var _width/eax: int <- copy 0
204 var height/ecx: int <- copy 0
205 _width, height <- screen-size screen
206 var width/edx: int <- copy _width
207 var y/ecx: int <- copy height
208 y <- decrement
209 var height/ebx: int <- copy y
210 height <- increment
211 clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
212 set-cursor-position screen, 0/x, y
213 draw-text-rightward-from-cursor screen, " ^r ", width, 0/fg, 0x5c/bg=menu-highlight
214 draw-text-rightward-from-cursor screen, " run main ", width, 7/fg, 0xc5/bg=blue-bg
215 draw-text-rightward-from-cursor screen, " ^s ", width, 0/fg, 0x5c/bg=menu-highlight
216 draw-text-rightward-from-cursor screen, " run sandbox ", width, 7/fg, 0xc5/bg=blue-bg
217 draw-text-rightward-from-cursor screen, " ^g ", width, 0/fg, 0x5c/bg=menu-highlight
218 draw-text-rightward-from-cursor screen, " go to ", width, 7/fg, 0xc5/bg=blue-bg
219 draw-text-rightward-from-cursor screen, " ^a ", width, 0/fg, 0x5c/bg=menu-highlight
220 draw-text-rightward-from-cursor screen, " << ", width, 7/fg, 0xc5/bg=blue-bg
221 draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg, 0x5c/bg=menu-highlight
222 draw-text-rightward-from-cursor screen, " <word ", width, 7/fg, 0xc5/bg=blue-bg
223 draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg, 0x5c/bg=menu-highlight
224 draw-text-rightward-from-cursor screen, " word> ", width, 7/fg, 0xc5/bg=blue-bg
225 draw-text-rightward-from-cursor screen, " ^e ", width, 0/fg, 0x5c/bg=menu-highlight
226 draw-text-rightward-from-cursor screen, " >> ", width, 7/fg, 0xc5/bg=blue-bg
227 }
228
229 fn edit-globals _self: (addr global-table), key: grapheme {
230 var self/esi: (addr global-table) <- copy _self
231
232 {
233 compare key, 0x13/ctrl-s
234 break-if-!=
235
236 refresh-cursor-definition self
237 return
238 }
239 var cursor-index-addr/ecx: (addr int) <- get self, cursor-index
240 var cursor-index/ecx: int <- copy *cursor-index-addr
241 var data-ah/eax: (addr handle array global) <- get self, data
242 var data/eax: (addr array global) <- lookup *data-ah
243 var cursor-offset/ecx: (offset global) <- compute-offset data, cursor-index
244 var curr-global/eax: (addr global) <- index data, cursor-offset
245 var curr-editor-ah/eax: (addr handle gap-buffer) <- get curr-global, input
246 var curr-editor/eax: (addr gap-buffer) <- lookup *curr-editor-ah
247 edit-gap-buffer curr-editor, key
248 }
249
250 fn create-empty-global _self: (addr global-table), name-stream: (addr stream byte), capacity: int {
251 var self/esi: (addr global-table) <- copy _self
252 var final-index-addr/ecx: (addr int) <- get self, final-index
253 increment *final-index-addr
254 var curr-index/ecx: int <- copy *final-index-addr
255 var cursor-index-addr/eax: (addr int) <- get self, cursor-index
256 copy-to *cursor-index-addr, curr-index
257 var data-ah/eax: (addr handle array global) <- get self, data
258 var data/eax: (addr array global) <- lookup *data-ah
259 var curr-offset/ecx: (offset global) <- compute-offset data, curr-index
260 var curr/esi: (addr global) <- index data, curr-offset
261 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
262 stream-to-array name-stream, curr-name-ah
263 var curr-input-ah/eax: (addr handle gap-buffer) <- get curr, input
264 allocate curr-input-ah
265 var curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
266 initialize-gap-buffer curr-input, capacity
267 var trace-ah/eax: (addr handle trace) <- get curr, trace
268# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
if __name__ == '__main__': from __init__ import init; init()
from os.path import realpath, join, dirname
from ranger import fsobject
from ranger.fsobject.file import File
from ranger.fsobject.directory import Directory
from ranger.shared.settings import SettingsAware
SettingsAware._setup()
TESTDIR = realpath(join(dirname(__file__), 'testdir'))
TESTFILE = join(TESTDIR, 'testfile5234148')
NONEXISTANT_DIR = join(TESTDIR, 'nonexistant')
import unittest
class Test1(unittest.TestCase):
def test_initial_condition(self):
# Check for the expected initial condition
dir = Directory(TESTDIR)
self.assertEqual(dir.path, TESTDIR)
self.assertFalse(dir.content_loaded)
self.assertEqual(dir.filenames, None)
self.assertEqual(dir.files, None)
self.assertRaises(fsobject.NotLoadedYet, len, dir)
def test_after_content_loaded(self):
import os
# Check whether the directory has the correct list of filenames.
dir = Directory(TESTDIR)
dir.load_content()
self.assertTrue(dir.exists)
self.assertEqual(type(dir.filenames), list)
# Get the filenames you expect it to have and sort both before
# comparing. I don't expect any order after only loading the filenames.
assumed_filenames = os.listdir(TESTDIR)
assumed_filenames = list(map(lambda str: os.path.join(TESTDIR, str),
assumed_filenames))
assumed_filenames.sort()
dir.filenames.sort()
self.assertTrue(len(dir) > 0)
self.assertEqual(dir.filenames, assumed_filenames)
# build a file object for each file in the list assumed_filenames
# and find exactly one equivalent in dir.files
for name in assumed_filenames:
f = File(name)
f.load()
for dirfile in dir.files:
if (f.path == dirfile.path and f.stat == dirfile.stat):
break
else:
self.fail("couldn't find file {0}".format(name))
def test_nonexistant_dir(self):
dir = Directory(NONEXISTANT_DIR)
dir.load_content()
self.assertTrue(dir.content_loaded)
self.assertFalse(dir.exists)
self.assertFalse(dir.accessible)
self.assertEqual(dir.filenames, None)
self.assertRaises(fsobject.NotLoadedYet, len, dir)
def test_load_if_outdated(self):
import os
import time
# modify the directory. If the time between the last modification
# was within the filesystems resolution of mtime, we should have a reload
def modify_dir():
open(TESTFILE, 'w').close()
os.unlink(TESTFILE)
def mtime():
return os.stat(TESTDIR).st_mtime
dir = Directory(TESTDIR)
dir.load()
# If the modification happens to be in the same second as the
# last modification, it will result in mtime having the same
# integer value. So we wait until the resolution is exceeded
# and mtime differs.
old_mtime = mtime()
for i in range(50):
modify_dir()
if old_mtime != mtime(): break
time.sleep(0.1)
else:
# fail after 5 seconds of trying
self.fail(
"Cannot perform test: mtime of TESTDIR is not being updated.")
self.assertTrue(dir.load_if_outdated())
if __name__ == '__main__':
unittest.main()