1 -- major tests for text editing flows
3 function test_initial_state()
4 io
.write('\ntest_initial_state')
5 App
.screen
.init
{width
=120, height
=60}
6 Editor_state
= edit
.initialize_test_state()
7 Editor_state
.lines
= load_array
{}
8 Text
.redraw_all(Editor_state
)
9 edit
.draw(Editor_state
)
10 check_eq(#Editor_state
.lines
, 1, 'F - test_initial_state/#lines')
11 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_initial_state/cursor:line')
12 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_initial_state/cursor:pos')
13 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_initial_state/screen_top:line')
14 check_eq(Editor_state
.screen_top1
.pos
, 1, 'F - test_initial_state/screen_top:pos')
17 function test_click_to_create_drawing()
18 io
.write('\ntest_click_to_create_drawing')
19 App
.screen
.init
{width
=120, height
=60}
20 Editor_state
= edit
.initialize_test_state()
21 Editor_state
.lines
= load_array
{}
22 Text
.redraw_all(Editor_state
)
23 edit
.draw(Editor_state
)
24 edit
.run_after_mouse_click(Editor_state
, 8,Editor_state
.top
+8, 1)
25 -- cursor skips drawing to always remain on text
26 check_eq(#Editor_state
.lines
, 2, 'F - test_click_to_create_drawing/#lines')
27 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_click_to_create_drawing/cursor')
30 function test_backspace_to_delete_drawing()
31 io
.write('\ntest_backspace_to_delete_drawing')
32 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
33 App
.screen
.init
{width
=120, height
=60}
34 Editor_state
= edit
.initialize_test_state()
35 Editor_state
.lines
= load_array
{'```lines', '```', ''}
36 Text
.redraw_all(Editor_state
)
37 -- cursor is on text as always (outside tests this will get initialized correctly)
38 Editor_state
.cursor1
.line
= 2
39 -- backspacing deletes the drawing
40 edit
.run_after_keychord(Editor_state
, 'backspace')
41 check_eq(#Editor_state
.lines
, 1, 'F - test_backspace_to_delete_drawing/#lines')
42 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_backspace_to_delete_drawing/cursor')
45 function test_backspace_from_start_of_final_line()
46 io
.write('\ntest_backspace_from_start_of_final_line')
47 -- display final line of text with cursor at start of it
48 App
.screen
.init
{width
=120, height
=60}
49 Editor_state
= edit
.initialize_test_state()
50 Editor_state
.lines
= load_array
{'abc', 'def'}
51 Editor_state
.screen_top1
= {line
=2, pos
=1}
52 Editor_state
.cursor1
= {line
=2, pos
=1}
53 Text
.redraw_all(Editor_state
)
54 -- backspace scrolls up
55 edit
.run_after_keychord(Editor_state
, 'backspace')
56 check_eq(#Editor_state
.lines
, 1, 'F - test_backspace_from_start_of_final_line/#lines')
57 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_backspace_from_start_of_final_line/cursor')
58 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_backspace_from_start_of_final_line/screen_top')
61 function test_insert_first_character()
62 io
.write('\ntest_insert_first_character')
63 App
.screen
.init
{width
=120, height
=60}
64 Editor_state
= edit
.initialize_test_state()
65 Editor_state
.lines
= load_array
{}
66 Text
.redraw_all(Editor_state
)
67 edit
.draw(Editor_state
)
68 edit
.run_after_text_input(Editor_state
, 'a')
69 local y
= Editor_state
.top
70 App
.screen
.check(y
, 'a', 'F - test_insert_first_character/screen:1')
73 function test_press_ctrl()
74 io
.write('\ntest_press_ctrl')
75 -- press ctrl while the cursor is on text
76 App
.screen
.init
{width
=50, height
=80}
77 Editor_state
= edit
.initialize_test_state()
78 Editor_state
.lines
= load_array
{''}
79 Text
.redraw_all(Editor_state
)
80 Editor_state
.cursor1
= {line
=1, pos
=1}
81 Editor_state
.screen_top1
= {line
=1, pos
=1}
82 Editor_state
.screen_bottom1
= {}
83 edit
.run_after_keychord(Editor_state
, 'C-m')
86 function test_move_left()
87 io
.write('\ntest_move_left')
88 App
.screen
.init
{width
=120, height
=60}
89 Editor_state
= edit
.initialize_test_state()
90 Editor_state
.lines
= load_array
{'a'}
91 Text
.redraw_all(Editor_state
)
92 Editor_state
.cursor1
= {line
=1, pos
=2}
93 edit
.draw(Editor_state
)
94 edit
.run_after_keychord(Editor_state
, 'left')
95 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_move_left')
98 function test_move_right()
99 io
.write('\ntest_move_right')
100 App
.screen
.init
{width
=120, height
=60}
101 Editor_state
= edit
.initialize_test_state()
102 Editor_state
.lines
= load_array
{'a'}
103 Text
.redraw_all(Editor_state
)
104 Editor_state
.cursor1
= {line
=1, pos
=1}
105 edit
.draw(Editor_state
)
106 edit
.run_after_keychord(Editor_state
, 'right')
107 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_move_right')
110 function test_move_left_to_previous_line()
111 io
.write('\ntest_move_left_to_previous_line')
112 App
.screen
.init
{width
=120, height
=60}
113 Editor_state
= edit
.initialize_test_state()
114 Editor_state
.lines
= load_array
{'abc', 'def'}
115 Text
.redraw_all(Editor_state
)
116 Editor_state
.cursor1
= {line
=2, pos
=1}
117 edit
.draw(Editor_state
)
118 edit
.run_after_keychord(Editor_state
, 'left')
119 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_move_left_to_previous_line/line')
120 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_move_left_to_previous_line/pos') -- past end of line
123 function test_move_right_to_next_line()
124 io
.write('\ntest_move_right_to_next_line')
125 App
.screen
.init
{width
=120, height
=60}
126 Editor_state
= edit
.initialize_test_state()
127 Editor_state
.lines
= load_array
{'abc', 'def'}
128 Text
.redraw_all(Editor_state
)
129 Editor_state
.cursor1
= {line
=1, pos
=4} -- past end of line
130 edit
.draw(Editor_state
)
131 edit
.run_after_keychord(Editor_state
, 'right')
132 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_move_right_to_next_line/line')
133 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_move_right_to_next_line/pos')
136 function test_move_to_start_of_word()
137 io
.write('\ntest_move_to_start_of_word')
138 App
.screen
.init
{width
=120, height
=60}
139 Editor_state
= edit
.initialize_test_state()
140 Editor_state
.lines
= load_array
{'abc'}
141 Text
.redraw_all(Editor_state
)
142 Editor_state
.cursor1
= {line
=1, pos
=3}
143 edit
.draw(Editor_state
)
144 edit
.run_after_keychord(Editor_state
, 'M-left')
145 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_move_to_start_of_word')
148 function test_move_to_start_of_previous_word()
149 io
.write('\ntest_move_to_start_of_previous_word')
150 App
.screen
.init
{width
=120, height
=60}
151 Editor_state
= edit
.initialize_test_state()
152 Editor_state
.lines
= load_array
{'abc def'}
153 Text
.redraw_all(Editor_state
)
154 Editor_state
.cursor1
= {line
=1, pos
=4} -- at the space between words
155 edit
.draw(Editor_state
)
156 edit
.run_after_keychord(Editor_state
, 'M-left')
157 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_move_to_start_of_previous_word')
160 function test_skip_to_previous_word()
161 io
.write('\ntest_skip_to_previous_word')
162 App
.screen
.init
{width
=120, height
=60}
163 Editor_state
= edit
.initialize_test_state()
164 Editor_state
.lines
= load_array
{'abc def'}
165 Text
.redraw_all(Editor_state
)
166 Editor_state
.cursor1
= {line
=1, pos
=5} -- at the start of second word
167 edit
.draw(Editor_state
)
168 edit
.run_after_keychord(Editor_state
, 'M-left')
169 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_skip_to_previous_word')
172 function test_skip_past_tab_to_previous_word()
173 io
.write('\ntest_skip_past_tab_to_previous_word')
174 App
.screen
.init
{width
=120, height
=60}
175 Editor_state
= edit
.initialize_test_state()
176 Editor_state
.lines
= load_array
{'abc def\tghi'}
177 Text
.redraw_all(Editor_state
)
178 Editor_state
.cursor1
= {line
=1, pos
=10} -- within third word
179 edit
.draw(Editor_state
)
180 edit
.run_after_keychord(Editor_state
, 'M-left')
181 check_eq(Editor_state
.cursor1
.pos
, 9, 'F - test_skip_past_tab_to_previous_word')
184 function test_skip_multiple_spaces_to_previous_word()
185 io
.write('\ntest_skip_multiple_spaces_to_previous_word')
186 App
.screen
.init
{width
=120, height
=60}
187 Editor_state
= edit
.initialize_test_state()
188 Editor_state
.lines
= load_array
{'abc def'}
189 Text
.redraw_all(Editor_state
)
190 Editor_state
.cursor1
= {line
=1, pos
=6} -- at the start of second word
191 edit
.draw(Editor_state
)
192 edit
.run_after_keychord(Editor_state
, 'M-left')
193 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_skip_multiple_spaces_to_previous_word')
196 function test_move_to_start_of_word_on_previous_line()
197 io
.write('\ntest_move_to_start_of_word_on_previous_line')
198 App
.screen
.init
{width
=120, height
=60}
199 Editor_state
= edit
.initialize_test_state()
200 Editor_state
.lines
= load_array
{'abc def', 'ghi'}
201 Text
.redraw_all(Editor_state
)
202 Editor_state
.cursor1
= {line
=2, pos
=1}
203 edit
.draw(Editor_state
)
204 edit
.run_after_keychord(Editor_state
, 'M-left')
205 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_move_to_start_of_word_on_previous_line/line')
206 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_move_to_start_of_word_on_previous_line/pos')
209 function test_move_past_end_of_word()
210 io
.write('\ntest_move_past_end_of_word')
211 App
.screen
.init
{width
=120, height
=60}
212 Editor_state
= edit
.initialize_test_state()
213 Editor_state
.lines
= load_array
{'abc def'}
214 Text
.redraw_all(Editor_state
)
215 Editor_state
.cursor1
= {line
=1, pos
=1}
216 edit
.draw(Editor_state
)
217 edit
.run_after_keychord(Editor_state
, 'M-right')
218 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_move_past_end_of_word')
221 function test_skip_to_next_word()
222 io
.write('\ntest_skip_to_next_word')
223 App
.screen
.init
{width
=120, height
=60}
224 Editor_state
= edit
.initialize_test_state()
225 Editor_state
.lines
= load_array
{'abc def'}
226 Text
.redraw_all(Editor_state
)
227 Editor_state
.cursor1
= {line
=1, pos
=4} -- at the space between words
228 edit
.draw(Editor_state
)
229 edit
.run_after_keychord(Editor_state
, 'M-right')
230 check_eq(Editor_state
.cursor1
.pos
, 8, 'F - test_skip_to_next_word')
233 function test_skip_past_tab_to_next_word()
234 io
.write('\ntest_skip_past_tab_to_next_word')
235 App
.screen
.init
{width
=120, height
=60}
236 Editor_state
= edit
.initialize_test_state()
237 Editor_state
.lines
= load_array
{'abc\tdef'}
238 Text
.redraw_all(Editor_state
)
239 Editor_state
.cursor1
= {line
=1, pos
=1} -- at the space between words
240 edit
.draw(Editor_state
)
241 edit
.run_after_keychord(Editor_state
, 'M-right')
242 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_skip_past_tab_to_next_word')
245 function test_skip_multiple_spaces_to_next_word()
246 io
.write('\ntest_skip_multiple_spaces_to_next_word')
247 App
.screen
.init
{width
=120, height
=60}
248 Editor_state
= edit
.initialize_test_state()
249 Editor_state
.lines
= load_array
{'abc def'}
250 Text
.redraw_all(Editor_state
)
251 Editor_state
.cursor1
= {line
=1, pos
=4} -- at the start of second word
252 edit
.draw(Editor_state
)
253 edit
.run_after_keychord(Editor_state
, 'M-right')
254 check_eq(Editor_state
.cursor1
.pos
, 9, 'F - test_skip_multiple_spaces_to_next_word')
257 function test_move_past_end_of_word_on_next_line()
258 io
.write('\ntest_move_past_end_of_word_on_next_line')
259 App
.screen
.init
{width
=120, height
=60}
260 Editor_state
= edit
.initialize_test_state()
261 Editor_state
.lines
= load_array
{'abc def', 'ghi'}
262 Text
.redraw_all(Editor_state
)
263 Editor_state
.cursor1
= {line
=1, pos
=8}
264 edit
.draw(Editor_state
)
265 edit
.run_after_keychord(Editor_state
, 'M-right')
266 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_move_past_end_of_word_on_next_line/line')
267 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_move_past_end_of_word_on_next_line/pos')
270 function test_click_moves_cursor()
271 io
.write('\ntest_click_moves_cursor')
272 App
.screen
.init
{width
=50, height
=60}
273 Editor_state
= edit
.initialize_test_state()
274 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
275 Text
.redraw_all(Editor_state
)
276 Editor_state
.cursor1
= {line
=1, pos
=1}
277 Editor_state
.screen_top1
= {line
=1, pos
=1}
278 Editor_state
.screen_bottom1
= {}
279 Editor_state
.selection1
= {}
280 edit
.draw(Editor_state
) -- populate line_cache.starty for each line Editor_state.line_cache
281 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
282 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_moves_cursor/cursor:line')
283 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_click_moves_cursor/cursor:pos')
284 -- selection is empty to avoid perturbing future edits
285 check_nil(Editor_state
.selection1
.line
, 'F - test_click_moves_cursor/selection:line')
286 check_nil(Editor_state
.selection1
.pos
, 'F - test_click_moves_cursor/selection:pos')
289 function test_click_to_left_of_line()
290 io
.write('\ntest_click_to_left_of_line')
291 -- display a line with the cursor in the middle
292 App
.screen
.init
{width
=50, height
=80}
293 Editor_state
= edit
.initialize_test_state()
294 Editor_state
.lines
= load_array
{'abc'}
295 Text
.redraw_all(Editor_state
)
296 Editor_state
.cursor1
= {line
=1, pos
=3}
297 Editor_state
.screen_top1
= {line
=1, pos
=1}
298 Editor_state
.screen_bottom1
= {}
299 -- click to the left of the line
300 edit
.draw(Editor_state
)
301 edit
.run_after_mouse_click(Editor_state
, Editor_state
.left
-4,Editor_state
.top
+5, 1)
302 -- cursor moves to start of line
303 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_to_left_of_line/cursor:line')
304 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_click_to_left_of_line/cursor:pos')
305 check_nil(Editor_state
.selection1
.line
, 'F - test_click_to_left_of_line/selection is empty to avoid perturbing future edits')
308 function test_click_takes_margins_into_account()
309 io
.write('\ntest_click_takes_margins_into_account')
310 -- display two lines with cursor on one of them
311 App
.screen
.init
{width
=100, height
=80}
312 Editor_state
= edit
.initialize_test_state()
313 Editor_state
.left
= 50 -- occupy only right side of screen
314 Editor_state
.lines
= load_array
{'abc', 'def'}
315 Text
.redraw_all(Editor_state
)
316 Editor_state
.cursor1
= {line
=2, pos
=1}
317 Editor_state
.screen_top1
= {line
=1, pos
=1}
318 Editor_state
.screen_bottom1
= {}
319 -- click on the other line
320 edit
.draw(Editor_state
)
321 edit
.run_after_mouse_click(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
323 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_takes_margins_into_account/cursor:line')
324 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_click_takes_margins_into_account/cursor:pos')
325 check_nil(Editor_state
.selection1
.line
, 'F - test_click_takes_margins_into_account/selection is empty to avoid perturbing future edits')
328 function test_click_on_empty_line()
329 io
.write('\ntest_click_on_empty_line')
330 -- display two lines with the first one empty
331 App
.screen
.init
{width
=50, height
=80}
332 Editor_state
= edit
.initialize_test_state()
333 Editor_state
.lines
= load_array
{'', 'def'}
334 Text
.redraw_all(Editor_state
)
335 Editor_state
.cursor1
= {line
=2, pos
=1}
336 Editor_state
.screen_top1
= {line
=1, pos
=1}
337 Editor_state
.screen_bottom1
= {}
338 -- click on the empty line
339 edit
.draw(Editor_state
)
340 edit
.run_after_mouse_click(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
342 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_on_empty_line/cursor')
345 function test_draw_text()
346 io
.write('\ntest_draw_text')
347 App
.screen
.init
{width
=120, height
=60}
348 Editor_state
= edit
.initialize_test_state()
349 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi'}
350 Text
.redraw_all(Editor_state
)
351 Editor_state
.cursor1
= {line
=1, pos
=1}
352 Editor_state
.screen_top1
= {line
=1, pos
=1}
353 Editor_state
.screen_bottom1
= {}
354 edit
.draw(Editor_state
)
355 local y
= Editor_state
.top
356 App
.screen
.check(y
, 'abc', 'F - test_draw_text/screen:1')
357 y
= y
+ Editor_state
.line_height
358 App
.screen
.check(y
, 'def', 'F - test_draw_text/screen:2')
359 y
= y
+ Editor_state
.line_height
360 App
.screen
.check(y
, 'ghi', 'F - test_draw_text/screen:3')
363 function test_draw_wrapping_text()
364 io
.write('\ntest_draw_wrapping_text')
365 App
.screen
.init
{width
=50, height
=60}
366 Editor_state
= edit
.initialize_test_state()
367 Editor_state
.lines
= load_array
{'abc', 'defgh', 'xyz'}
368 Text
.redraw_all(Editor_state
)
369 Editor_state
.cursor1
= {line
=1, pos
=1}
370 Editor_state
.screen_top1
= {line
=1, pos
=1}
371 Editor_state
.screen_bottom1
= {}
372 edit
.draw(Editor_state
)
373 local y
= Editor_state
.top
374 App
.screen
.check(y
, 'abc', 'F - test_draw_wrapping_text/screen:1')
375 y
= y
+ Editor_state
.line_height
376 App
.screen
.check(y
, 'de', 'F - test_draw_wrapping_text/screen:2')
377 y
= y
+ Editor_state
.line_height
378 App
.screen
.check(y
, 'fgh', 'F - test_draw_wrapping_text/screen:3')
381 function test_draw_word_wrapping_text()
382 io
.write('\ntest_draw_word_wrapping_text')
383 App
.screen
.init
{width
=60, height
=60}
384 Editor_state
= edit
.initialize_test_state()
385 Editor_state
.lines
= load_array
{'abc def ghi', 'jkl'}
386 Text
.redraw_all(Editor_state
)
387 Editor_state
.cursor1
= {line
=1, pos
=1}
388 Editor_state
.screen_top1
= {line
=1, pos
=1}
389 Editor_state
.screen_bottom1
= {}
390 edit
.draw(Editor_state
)
391 local y
= Editor_state
.top
392 App
.screen
.check(y
, 'abc ', 'F - test_draw_word_wrapping_text/screen:1')
393 y
= y
+ Editor_state
.line_height
394 App
.screen
.check(y
, 'def ', 'F - test_draw_word_wrapping_text/screen:2')
395 y
= y
+ Editor_state
.line_height
396 App
.screen
.check(y
, 'ghi', 'F - test_draw_word_wrapping_text/screen:3')
399 function test_click_on_wrapping_line()
400 io
.write('\ntest_click_on_wrapping_line')
401 -- display two lines with cursor on one of them
402 App
.screen
.init
{width
=50, height
=80}
403 Editor_state
= edit
.initialize_test_state()
404 Editor_state
.lines
= load_array
{'abc def ghi jkl mno pqr stu'}
405 Text
.redraw_all(Editor_state
)
406 Editor_state
.cursor1
= {line
=1, pos
=20}
407 Editor_state
.screen_top1
= {line
=1, pos
=1}
408 Editor_state
.screen_bottom1
= {}
409 -- click on the other line
410 edit
.draw(Editor_state
)
411 edit
.run_after_mouse_click(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
413 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_on_wrapping_line/cursor:line')
414 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_click_on_wrapping_line/cursor:pos')
415 check_nil(Editor_state
.selection1
.line
, 'F - test_click_on_wrapping_line/selection is empty to avoid perturbing future edits')
418 function test_click_on_wrapping_line_takes_margins_into_account()
419 io
.write('\ntest_click_on_wrapping_line_takes_margins_into_account')
420 -- display two lines with cursor on one of them
421 App
.screen
.init
{width
=100, height
=80}
422 Editor_state
= edit
.initialize_test_state()
423 Editor_state
.left
= 50 -- occupy only right side of screen
424 Editor_state
.lines
= load_array
{'abc def ghi jkl mno pqr stu'}
425 Text
.redraw_all(Editor_state
)
426 Editor_state
.cursor1
= {line
=1, pos
=20}
427 Editor_state
.screen_top1
= {line
=1, pos
=1}
428 Editor_state
.screen_bottom1
= {}
429 -- click on the other line
430 edit
.draw(Editor_state
)
431 edit
.run_after_mouse_click(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
433 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_on_wrapping_line_takes_margins_into_account/cursor:line')
434 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_click_on_wrapping_line_takes_margins_into_account/cursor:pos')
435 check_nil(Editor_state
.selection1
.line
, 'F - test_click_on_wrapping_line_takes_margins_into_account/selection is empty to avoid perturbing future edits')
438 function test_draw_text_wrapping_within_word()
439 -- arrange a screen line that needs to be split within a word
440 io
.write('\ntest_draw_text_wrapping_within_word')
441 App
.screen
.init
{width
=60, height
=60}
442 Editor_state
= edit
.initialize_test_state()
443 Editor_state
.lines
= load_array
{'abcd e fghijk', 'xyz'}
444 Text
.redraw_all(Editor_state
)
445 Editor_state
.cursor1
= {line
=1, pos
=1}
446 Editor_state
.screen_top1
= {line
=1, pos
=1}
447 Editor_state
.screen_bottom1
= {}
448 edit
.draw(Editor_state
)
449 local y
= Editor_state
.top
450 App
.screen
.check(y
, 'abcd ', 'F - test_draw_text_wrapping_within_word/screen:1')
451 y
= y
+ Editor_state
.line_height
452 App
.screen
.check(y
, 'e fgh', 'F - test_draw_text_wrapping_within_word/screen:2')
453 y
= y
+ Editor_state
.line_height
454 App
.screen
.check(y
, 'ijk', 'F - test_draw_text_wrapping_within_word/screen:3')
457 function test_draw_wrapping_text_containing_non_ascii()
458 -- draw a long line containing non-ASCII
459 io
.write('\ntest_draw_wrapping_text_containing_non_ascii')
460 App
.screen
.init
{width
=60, height
=60}
461 Editor_state
= edit
.initialize_test_state()
462 Editor_state
.lines
= load_array
{'madam I’m adam', 'xyz'} -- notice the non-ASCII apostrophe
463 Text
.redraw_all(Editor_state
)
464 Editor_state
.cursor1
= {line
=1, pos
=1}
465 Editor_state
.screen_top1
= {line
=1, pos
=1}
466 Editor_state
.screen_bottom1
= {}
467 edit
.draw(Editor_state
)
468 local y
= Editor_state
.top
469 App
.screen
.check(y
, 'mad', 'F - test_draw_wrapping_text_containing_non_ascii/screen:1')
470 y
= y
+ Editor_state
.line_height
471 App
.screen
.check(y
, 'am I', 'F - test_draw_wrapping_text_containing_non_ascii/screen:2')
472 y
= y
+ Editor_state
.line_height
473 App
.screen
.check(y
, '’m a', 'F - test_draw_wrapping_text_containing_non_ascii/screen:3')
476 function test_click_on_wrapping_line()
477 io
.write('\ntest_click_on_wrapping_line')
478 -- display a wrapping line
479 App
.screen
.init
{width
=75, height
=80}
480 Editor_state
= edit
.initialize_test_state()
482 Editor_state
.lines
= load_array
{"madam I'm adam"}
483 Text
.redraw_all(Editor_state
)
484 Editor_state
.cursor1
= {line
=1, pos
=1}
485 Editor_state
.screen_top1
= {line
=1, pos
=1}
486 Editor_state
.screen_bottom1
= {}
487 edit
.draw(Editor_state
)
488 local y
= Editor_state
.top
489 App
.screen
.check(y
, 'madam ', 'F - test_click_on_wrapping_line/baseline/screen:1')
490 y
= y
+ Editor_state
.line_height
491 App
.screen
.check(y
, "I'm ad", 'F - test_click_on_wrapping_line/baseline/screen:2')
492 y
= y
+ Editor_state
.line_height
493 -- click past end of second screen line
494 edit
.run_after_mouse_click(Editor_state
, App
.screen
.width
-2,y
-2, 1)
495 -- cursor moves to end of screen line
496 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_on_wrapping_line/cursor:line')
497 check_eq(Editor_state
.cursor1
.pos
, 12, 'F - test_click_on_wrapping_line/cursor:pos')
500 function test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen()
501 io
.write('\ntest_click_on_wrapping_line_rendered_from_partway_at_top_of_screen')
502 -- display a wrapping line from its second screen line
503 App
.screen
.init
{width
=75, height
=80}
504 Editor_state
= edit
.initialize_test_state()
506 Editor_state
.lines
= load_array
{"madam I'm adam"}
507 Text
.redraw_all(Editor_state
)
508 Editor_state
.cursor1
= {line
=1, pos
=8}
509 Editor_state
.screen_top1
= {line
=1, pos
=7}
510 Editor_state
.screen_bottom1
= {}
511 edit
.draw(Editor_state
)
512 local y
= Editor_state
.top
513 App
.screen
.check(y
, "I'm ad", 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/baseline/screen:2')
514 y
= y
+ Editor_state
.line_height
515 -- click past end of second screen line
516 edit
.run_after_mouse_click(Editor_state
, App
.screen
.width
-2,y
-2, 1)
517 -- cursor moves to end of screen line
518 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:line')
519 check_eq(Editor_state
.cursor1
.pos
, 12, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:pos')
522 function test_click_past_end_of_wrapping_line()
523 io
.write('\ntest_click_past_end_of_wrapping_line')
524 -- display a wrapping line
525 App
.screen
.init
{width
=75, height
=80}
526 Editor_state
= edit
.initialize_test_state()
528 Editor_state
.lines
= load_array
{"madam I'm adam"}
529 Text
.redraw_all(Editor_state
)
530 Editor_state
.cursor1
= {line
=1, pos
=1}
531 Editor_state
.screen_top1
= {line
=1, pos
=1}
532 Editor_state
.screen_bottom1
= {}
533 edit
.draw(Editor_state
)
534 local y
= Editor_state
.top
535 App
.screen
.check(y
, 'madam ', 'F - test_click_past_end_of_wrapping_line/baseline/screen:1')
536 y
= y
+ Editor_state
.line_height
537 App
.screen
.check(y
, "I'm ad", 'F - test_click_past_end_of_wrapping_line/baseline/screen:2')
538 y
= y
+ Editor_state
.line_height
539 App
.screen
.check(y
, 'am', 'F - test_click_past_end_of_wrapping_line/baseline/screen:3')
540 y
= y
+ Editor_state
.line_height
541 -- click past the end of it
542 edit
.run_after_mouse_click(Editor_state
, App
.screen
.width
-2,y
-2, 1)
543 -- cursor moves to end of line
544 check_eq(Editor_state
.cursor1
.pos
, 15, 'F - test_click_past_end_of_wrapping_line/cursor') -- one more than the number of UTF-8 code-points
547 function test_click_past_end_of_wrapping_line_containing_non_ascii()
548 io
.write('\ntest_click_past_end_of_wrapping_line_containing_non_ascii')
549 -- display a wrapping line containing non-ASCII
550 App
.screen
.init
{width
=75, height
=80}
551 Editor_state
= edit
.initialize_test_state()
553 Editor_state
.lines
= load_array
{'madam I’m adam'} -- notice the non-ASCII apostrophe
554 Text
.redraw_all(Editor_state
)
555 Editor_state
.cursor1
= {line
=1, pos
=1}
556 Editor_state
.screen_top1
= {line
=1, pos
=1}
557 Editor_state
.screen_bottom1
= {}
558 edit
.draw(Editor_state
)
559 local y
= Editor_state
.top
560 App
.screen
.check(y
, 'madam ', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:1')
561 y
= y
+ Editor_state
.line_height
562 App
.screen
.check(y
, 'I’m ad', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:2')
563 y
= y
+ Editor_state
.line_height
564 App
.screen
.check(y
, 'am', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:3')
565 y
= y
+ Editor_state
.line_height
566 -- click past the end of it
567 edit
.run_after_mouse_click(Editor_state
, App
.screen
.width
-2,y
-2, 1)
568 -- cursor moves to end of line
569 check_eq(Editor_state
.cursor1
.pos
, 15, 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/cursor') -- one more than the number of UTF-8 code-points
572 function test_click_past_end_of_word_wrapping_line()
573 io
.write('\ntest_click_past_end_of_word_wrapping_line')
574 -- display a long line wrapping at a word boundary on a screen of more realistic length
575 App
.screen
.init
{width
=160, height
=80}
576 Editor_state
= edit
.initialize_test_state()
578 -- 123456789012345678901
579 Editor_state
.lines
= load_array
{'the quick brown fox jumped over the lazy dog'}
580 Text
.redraw_all(Editor_state
)
581 Editor_state
.cursor1
= {line
=1, pos
=1}
582 Editor_state
.screen_top1
= {line
=1, pos
=1}
583 Editor_state
.screen_bottom1
= {}
584 edit
.draw(Editor_state
)
585 local y
= Editor_state
.top
586 App
.screen
.check(y
, 'the quick brown fox ', 'F - test_click_past_end_of_word_wrapping_line/baseline/screen:1')
587 y
= y
+ Editor_state
.line_height
588 -- click past the end of the screen line
589 edit
.run_after_mouse_click(Editor_state
, App
.screen
.width
-2,y
-2, 1)
590 -- cursor moves to end of screen line
591 check_eq(Editor_state
.cursor1
.pos
, 20, 'F - test_click_past_end_of_word_wrapping_line/cursor')
594 function test_select_text()
595 io
.write('\ntest_select_text')
596 -- display a line of text
597 App
.screen
.init
{width
=75, height
=80}
598 Editor_state
= edit
.initialize_test_state()
599 Editor_state
.lines
= load_array
{'abc def'}
600 Text
.redraw_all(Editor_state
)
601 Editor_state
.cursor1
= {line
=1, pos
=1}
602 Editor_state
.screen_top1
= {line
=1, pos
=1}
603 Editor_state
.screen_bottom1
= {}
604 edit
.draw(Editor_state
)
606 App
.fake_key_press('lshift')
607 edit
.run_after_keychord(Editor_state
, 'S-right')
608 App
.fake_key_release('lshift')
609 edit
.key_release(Editor_state
, 'lshift')
610 -- selection persists even after shift is released
611 check_eq(Editor_state
.selection1
.line
, 1, 'F - test_select_text/selection:line')
612 check_eq(Editor_state
.selection1
.pos
, 1, 'F - test_select_text/selection:pos')
613 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_select_text/cursor:line')
614 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_select_text/cursor:pos')
617 function test_cursor_movement_without_shift_resets_selection()
618 io
.write('\ntest_cursor_movement_without_shift_resets_selection')
619 -- display a line of text with some part selected
620 App
.screen
.init
{width
=75, height
=80}
621 Editor_state
= edit
.initialize_test_state()
622 Editor_state
.lines
= load_array
{'abc'}
623 Text
.redraw_all(Editor_state
)
624 Editor_state
.cursor1
= {line
=1, pos
=1}
625 Editor_state
.selection1
= {line
=1, pos
=2}
626 Editor_state
.screen_top1
= {line
=1, pos
=1}
627 Editor_state
.screen_bottom1
= {}
628 edit
.draw(Editor_state
)
629 -- press an arrow key without shift
630 edit
.run_after_keychord(Editor_state
, 'right')
631 -- no change to data, selection is reset
632 check_nil(Editor_state
.selection1
.line
, 'F - test_cursor_movement_without_shift_resets_selection')
633 check_eq(Editor_state
.lines
[1].data
, 'abc', 'F - test_cursor_movement_without_shift_resets_selection/data')
636 function test_edit_deletes_selection()
637 io
.write('\ntest_edit_deletes_selection')
638 -- display a line of text with some part selected
639 App
.screen
.init
{width
=75, height
=80}
640 Editor_state
= edit
.initialize_test_state()
641 Editor_state
.lines
= load_array
{'abc'}
642 Text
.redraw_all(Editor_state
)
643 Editor_state
.cursor1
= {line
=1, pos
=1}
644 Editor_state
.selection1
= {line
=1, pos
=2}
645 Editor_state
.screen_top1
= {line
=1, pos
=1}
646 Editor_state
.screen_bottom1
= {}
647 edit
.draw(Editor_state
)
649 edit
.run_after_text_input(Editor_state
, 'x')
650 -- selected text is deleted and replaced with the key
651 check_eq(Editor_state
.lines
[1].data
, 'xbc', 'F - test_edit_deletes_selection')
654 function test_edit_with_shift_key_deletes_selection()
655 io
.write('\ntest_edit_with_shift_key_deletes_selection')
656 -- display a line of text with some part selected
657 App
.screen
.init
{width
=75, height
=80}
658 Editor_state
= edit
.initialize_test_state()
659 Editor_state
.lines
= load_array
{'abc'}
660 Text
.redraw_all(Editor_state
)
661 Editor_state
.cursor1
= {line
=1, pos
=1}
662 Editor_state
.selection1
= {line
=1, pos
=2}
663 Editor_state
.screen_top1
= {line
=1, pos
=1}
664 Editor_state
.screen_bottom1
= {}
665 edit
.draw(Editor_state
)
666 -- mimic precise keypresses for a capital letter
667 App
.fake_key_press('lshift')
668 edit
.keychord_press(Editor_state
, 'd', 'd')
669 edit
.text_input(Editor_state
, 'D')
670 edit
.key_release(Editor_state
, 'd')
671 App
.fake_key_release('lshift')
672 -- selected text is deleted and replaced with the key
673 check_nil(Editor_state
.selection1
.line
, 'F - test_edit_with_shift_key_deletes_selection')
674 check_eq(Editor_state
.lines
[1].data
, 'Dbc', 'F - test_edit_with_shift_key_deletes_selection/data')
677 function test_copy_does_not_reset_selection()
678 io
.write('\ntest_copy_does_not_reset_selection')
679 -- display a line of text with a selection
680 App
.screen
.init
{width
=75, height
=80}
681 Editor_state
= edit
.initialize_test_state()
682 Editor_state
.lines
= load_array
{'abc'}
683 Text
.redraw_all(Editor_state
)
684 Editor_state
.cursor1
= {line
=1, pos
=1}
685 Editor_state
.selection1
= {line
=1, pos
=2}
686 Editor_state
.screen_top1
= {line
=1, pos
=1}
687 Editor_state
.screen_bottom1
= {}
688 edit
.draw(Editor_state
)
690 edit
.run_after_keychord(Editor_state
, 'C-c')
691 check_eq(App
.clipboard
, 'a', 'F - test_copy_does_not_reset_selection/clipboard')
692 -- selection is reset since shift key is not pressed
693 check(Editor_state
.selection1
.line
, 'F - test_copy_does_not_reset_selection')
697 io
.write('\ntest_cut')
698 -- display a line of text with some part selected
699 App
.screen
.init
{width
=75, height
=80}
700 Editor_state
= edit
.initialize_test_state()
701 Editor_state
.lines
= load_array
{'abc'}
702 Text
.redraw_all(Editor_state
)
703 Editor_state
.cursor1
= {line
=1, pos
=1}
704 Editor_state
.selection1
= {line
=1, pos
=2}
705 Editor_state
.screen_top1
= {line
=1, pos
=1}
706 Editor_state
.screen_bottom1
= {}
707 edit
.draw(Editor_state
)
709 edit
.run_after_keychord(Editor_state
, 'C-x')
710 check_eq(App
.clipboard
, 'a', 'F - test_cut/clipboard')
711 -- selected text is deleted
712 check_eq(Editor_state
.lines
[1].data
, 'bc', 'F - test_cut/data')
715 function test_paste_replaces_selection()
716 io
.write('\ntest_paste_replaces_selection')
717 -- display a line of text with a selection
718 App
.screen
.init
{width
=75, height
=80}
719 Editor_state
= edit
.initialize_test_state()
720 Editor_state
.lines
= load_array
{'abc', 'def'}
721 Text
.redraw_all(Editor_state
)
722 Editor_state
.cursor1
= {line
=2, pos
=1}
723 Editor_state
.selection1
= {line
=1, pos
=1}
724 Editor_state
.screen_top1
= {line
=1, pos
=1}
725 Editor_state
.screen_bottom1
= {}
726 edit
.draw(Editor_state
)
728 App
.clipboard
= 'xyz'
730 edit
.run_after_keychord(Editor_state
, 'C-v')
731 -- selection is reset since shift key is not pressed
732 -- selection includes the newline, so it's also deleted
733 check_eq(Editor_state
.lines
[1].data
, 'xyzdef', 'F - test_paste_replaces_selection')
736 function test_deleting_selection_may_scroll()
737 io
.write('\ntest_deleting_selection_may_scroll')
738 -- display lines 2/3/4
739 App
.screen
.init
{width
=120, height
=60}
740 Editor_state
= edit
.initialize_test_state()
741 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
742 Text
.redraw_all(Editor_state
)
743 Editor_state
.cursor1
= {line
=3, pos
=2}
744 Editor_state
.screen_top1
= {line
=2, pos
=1}
745 Editor_state
.screen_bottom1
= {}
746 edit
.draw(Editor_state
)
747 local y
= Editor_state
.top
748 App
.screen
.check(y
, 'def', 'F - test_deleting_selection_may_scroll/baseline/screen:1')
749 y
= y
+ Editor_state
.line_height
750 App
.screen
.check(y
, 'ghi', 'F - test_deleting_selection_may_scroll/baseline/screen:2')
751 y
= y
+ Editor_state
.line_height
752 App
.screen
.check(y
, 'jkl', 'F - test_deleting_selection_may_scroll/baseline/screen:3')
753 -- set up a selection starting above the currently displayed page
754 Editor_state
.selection1
= {line
=1, pos
=2}
756 edit
.run_after_keychord(Editor_state
, 'backspace')
758 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_deleting_selection_may_scroll')
759 check_eq(Editor_state
.lines
[1].data
, 'ahi', 'F - test_deleting_selection_may_scroll/data')
762 function test_edit_wrapping_text()
763 io
.write('\ntest_edit_wrapping_text')
764 App
.screen
.init
{width
=50, height
=60}
765 Editor_state
= edit
.initialize_test_state()
766 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
767 Text
.redraw_all(Editor_state
)
768 Editor_state
.cursor1
= {line
=2, pos
=4}
769 Editor_state
.screen_top1
= {line
=1, pos
=1}
770 Editor_state
.screen_bottom1
= {}
771 edit
.draw(Editor_state
)
772 edit
.run_after_text_input(Editor_state
, 'g')
773 local y
= Editor_state
.top
774 App
.screen
.check(y
, 'abc', 'F - test_edit_wrapping_text/screen:1')
775 y
= y
+ Editor_state
.line_height
776 App
.screen
.check(y
, 'de', 'F - test_edit_wrapping_text/screen:2')
777 y
= y
+ Editor_state
.line_height
778 App
.screen
.check(y
, 'fg', 'F - test_edit_wrapping_text/screen:3')
781 function test_insert_newline()
782 io
.write('\ntest_insert_newline')
783 -- display a few lines
784 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
785 Editor_state
= edit
.initialize_test_state()
786 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
787 Text
.redraw_all(Editor_state
)
788 Editor_state
.cursor1
= {line
=1, pos
=2}
789 Editor_state
.screen_top1
= {line
=1, pos
=1}
790 Editor_state
.screen_bottom1
= {}
791 edit
.draw(Editor_state
)
792 local y
= Editor_state
.top
793 App
.screen
.check(y
, 'abc', 'F - test_insert_newline/baseline/screen:1')
794 y
= y
+ Editor_state
.line_height
795 App
.screen
.check(y
, 'def', 'F - test_insert_newline/baseline/screen:2')
796 y
= y
+ Editor_state
.line_height
797 App
.screen
.check(y
, 'ghi', 'F - test_insert_newline/baseline/screen:3')
798 -- hitting the enter key splits the line
799 edit
.run_after_keychord(Editor_state
, 'return')
800 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_insert_newline/screen_top')
801 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_insert_newline/cursor:line')
802 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_insert_newline/cursor:pos')
804 App
.screen
.check(y
, 'a', 'F - test_insert_newline/screen:1')
805 y
= y
+ Editor_state
.line_height
806 App
.screen
.check(y
, 'bc', 'F - test_insert_newline/screen:2')
807 y
= y
+ Editor_state
.line_height
808 App
.screen
.check(y
, 'def', 'F - test_insert_newline/screen:3')
811 function test_insert_newline_at_start_of_line()
812 io
.write('\ntest_insert_newline_at_start_of_line')
814 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
815 Editor_state
= edit
.initialize_test_state()
816 Editor_state
.lines
= load_array
{'abc'}
817 Text
.redraw_all(Editor_state
)
818 Editor_state
.cursor1
= {line
=1, pos
=1}
819 Editor_state
.screen_top1
= {line
=1, pos
=1}
820 Editor_state
.screen_bottom1
= {}
821 -- hitting the enter key splits the line
822 edit
.run_after_keychord(Editor_state
, 'return')
823 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_insert_newline_at_start_of_line/cursor:line')
824 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_insert_newline_at_start_of_line/cursor:pos')
825 check_eq(Editor_state
.lines
[1].data
, '', 'F - test_insert_newline_at_start_of_line/data:1')
826 check_eq(Editor_state
.lines
[2].data
, 'abc', 'F - test_insert_newline_at_start_of_line/data:2')
829 function test_insert_from_clipboard()
830 io
.write('\ntest_insert_from_clipboard')
831 -- display a few lines
832 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
833 Editor_state
= edit
.initialize_test_state()
834 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
835 Text
.redraw_all(Editor_state
)
836 Editor_state
.cursor1
= {line
=1, pos
=2}
837 Editor_state
.screen_top1
= {line
=1, pos
=1}
838 Editor_state
.screen_bottom1
= {}
839 edit
.draw(Editor_state
)
840 local y
= Editor_state
.top
841 App
.screen
.check(y
, 'abc', 'F - test_insert_from_clipboard/baseline/screen:1')
842 y
= y
+ Editor_state
.line_height
843 App
.screen
.check(y
, 'def', 'F - test_insert_from_clipboard/baseline/screen:2')
844 y
= y
+ Editor_state
.line_height
845 App
.screen
.check(y
, 'ghi', 'F - test_insert_from_clipboard/baseline/screen:3')
846 -- paste some text including a newline, check that new line is created
847 App
.clipboard
= 'xy\nz'
848 edit
.run_after_keychord(Editor_state
, 'C-v')
849 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_insert_from_clipboard/screen_top')
850 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_insert_from_clipboard/cursor:line')
851 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_insert_from_clipboard/cursor:pos')
853 App
.screen
.check(y
, 'axy', 'F - test_insert_from_clipboard/screen:1')
854 y
= y
+ Editor_state
.line_height
855 App
.screen
.check(y
, 'zbc', 'F - test_insert_from_clipboard/screen:2')
856 y
= y
+ Editor_state
.line_height
857 App
.screen
.check(y
, 'def', 'F - test_insert_from_clipboard/screen:3')
860 function test_select_text_using_mouse()
861 io
.write('\ntest_select_text_using_mouse')
862 App
.screen
.init
{width
=50, height
=60}
863 Editor_state
= edit
.initialize_test_state()
864 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
865 Text
.redraw_all(Editor_state
)
866 Editor_state
.cursor1
= {line
=1, pos
=1}
867 Editor_state
.screen_top1
= {line
=1, pos
=1}
868 Editor_state
.screen_bottom1
= {}
869 Editor_state
.selection1
= {}
870 edit
.draw(Editor_state
) -- populate line_cache.starty for each line Editor_state.line_cache
871 -- press and hold on first location
872 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
873 -- drag and release somewhere else
874 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+Editor_state
.line_height
+5, 1)
875 check_eq(Editor_state
.selection1
.line
, 1, 'F - test_select_text_using_mouse/selection:line')
876 check_eq(Editor_state
.selection1
.pos
, 2, 'F - test_select_text_using_mouse/selection:pos')
877 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_select_text_using_mouse/cursor:line')
878 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_select_text_using_mouse/cursor:pos')
881 function test_select_text_using_mouse_and_shift()
882 io
.write('\ntest_select_text_using_mouse_and_shift')
883 App
.screen
.init
{width
=50, height
=60}
884 Editor_state
= edit
.initialize_test_state()
885 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
886 Text
.redraw_all(Editor_state
)
887 Editor_state
.cursor1
= {line
=1, pos
=1}
888 Editor_state
.screen_top1
= {line
=1, pos
=1}
889 Editor_state
.screen_bottom1
= {}
890 Editor_state
.selection1
= {}
891 edit
.draw(Editor_state
) -- populate line_cache.starty for each line Editor_state.line_cache
892 -- click on first location
893 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
894 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
895 -- hold down shift and click somewhere else
896 App
.fake_key_press('lshift')
897 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+5, 1)
898 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+Editor_state
.line_height
+5, 1)
899 App
.fake_key_release('lshift')
900 check_eq(Editor_state
.selection1
.line
, 1, 'F - test_select_text_using_mouse_and_shift/selection:line')
901 check_eq(Editor_state
.selection1
.pos
, 2, 'F - test_select_text_using_mouse_and_shift/selection:pos')
902 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_select_text_using_mouse_and_shift/cursor:line')
903 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_select_text_using_mouse_and_shift/cursor:pos')
906 function test_select_text_repeatedly_using_mouse_and_shift()
907 io
.write('\ntest_select_text_repeatedly_using_mouse_and_shift')
908 App
.screen
.init
{width
=50, height
=60}
909 Editor_state
= edit
.initialize_test_state()
910 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
911 Text
.redraw_all(Editor_state
)
912 Text
.redraw_all(Editor_state
)
913 Editor_state
.cursor1
= {line
=1, pos
=1}
914 Editor_state
.screen_top1
= {line
=1, pos
=1}
915 Editor_state
.screen_bottom1
= {}
916 Editor_state
.selection1
= {}
917 edit
.draw(Editor_state
) -- populate line_cache.starty for each line Editor_state.line_cache
918 -- click on first location
919 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
920 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+5, 1)
921 -- hold down shift and click on a second location
922 App
.fake_key_press('lshift')
923 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+5, 1)
924 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+Editor_state
.line_height
+5, 1)
925 -- hold down shift and click at a third location
926 App
.fake_key_press('lshift')
927 edit
.run_after_mouse_press(Editor_state
, Editor_state
.left
+20,Editor_state
.top
+5, 1)
928 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+Editor_state
.line_height
+5, 1)
929 App
.fake_key_release('lshift')
930 -- selection is between first and third location. forget the second location, not the first.
931 check_eq(Editor_state
.selection1
.line
, 1, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:line')
932 check_eq(Editor_state
.selection1
.pos
, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:pos')
933 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:line')
934 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:pos')
937 function test_cut_without_selection()
938 io
.write('\ntest_cut_without_selection')
939 -- display a few lines
940 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
941 Editor_state
= edit
.initialize_test_state()
942 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
943 Text
.redraw_all(Editor_state
)
944 Editor_state
.cursor1
= {line
=1, pos
=2}
945 Editor_state
.screen_top1
= {line
=1, pos
=1}
946 Editor_state
.screen_bottom1
= {}
947 Editor_state
.selection1
= {}
948 edit
.draw(Editor_state
)
949 -- try to cut without selecting text
950 edit
.run_after_keychord(Editor_state
, 'C-x')
952 check_nil(Editor_state
.selection1
.line
, 'F - test_cut_without_selection')
955 function test_pagedown()
956 io
.write('\ntest_pagedown')
957 App
.screen
.init
{width
=120, height
=45}
958 Editor_state
= edit
.initialize_test_state()
959 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi'}
960 Text
.redraw_all(Editor_state
)
961 Editor_state
.cursor1
= {line
=1, pos
=1}
962 Editor_state
.screen_top1
= {line
=1, pos
=1}
963 Editor_state
.screen_bottom1
= {}
964 -- initially the first two lines are displayed
965 edit
.draw(Editor_state
)
966 local y
= Editor_state
.top
967 App
.screen
.check(y
, 'abc', 'F - test_pagedown/baseline/screen:1')
968 y
= y
+ Editor_state
.line_height
969 App
.screen
.check(y
, 'def', 'F - test_pagedown/baseline/screen:2')
970 -- after pagedown the bottom line becomes the top
971 edit
.run_after_keychord(Editor_state
, 'pagedown')
972 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_pagedown/screen_top')
973 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_pagedown/cursor')
975 App
.screen
.check(y
, 'def', 'F - test_pagedown/screen:1')
976 y
= y
+ Editor_state
.line_height
977 App
.screen
.check(y
, 'ghi', 'F - test_pagedown/screen:2')
980 function test_pagedown_skips_drawings()
981 io
.write('\ntest_pagedown_skips_drawings')
982 -- some lines of text with a drawing intermixed
983 local drawing_width
= 50
984 App
.screen
.init
{width
=Editor_state
.left
+drawing_width
, height
=80}
985 Editor_state
= edit
.initialize_test_state()
986 Editor_state
.lines
= load_array
{'abc', -- height 15
987 '```lines', '```', -- height 25
990 Text
.redraw_all(Editor_state
)
991 check_eq(Editor_state
.lines
[2].mode
, 'drawing', 'F - test_pagedown_skips_drawings/baseline/lines')
992 Editor_state
.cursor1
= {line
=1, pos
=1}
993 Editor_state
.screen_top1
= {line
=1, pos
=1}
994 Editor_state
.screen_bottom1
= {}
995 local drawing_height
= Drawing_padding_height
+ drawing_width
/2 -- default
996 -- initially the screen displays the first line and the drawing
997 -- 15px margin + 15px line1 + 10px margin + 25px drawing + 10px margin = 75px < screen height 80px
998 edit
.draw(Editor_state
)
999 local y
= Editor_state
.top
1000 App
.screen
.check(y
, 'abc', 'F - test_pagedown_skips_drawings/baseline/screen:1')
1001 -- after pagedown the screen draws the drawing up top
1002 -- 15px margin + 10px margin + 25px drawing + 10px margin + 15px line3 = 75px < screen height 80px
1003 edit
.run_after_keychord(Editor_state
, 'pagedown')
1004 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_pagedown_skips_drawings/screen_top')
1005 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_pagedown_skips_drawings/cursor')
1006 y
= Editor_state
.top
+ drawing_height
1007 App
.screen
.check(y
, 'def', 'F - test_pagedown_skips_drawings/screen:1')
1010 function test_pagedown_can_start_from_middle_of_long_wrapping_line()
1011 io
.write('\ntest_pagedown_can_start_from_middle_of_long_wrapping_line')
1012 -- draw a few lines starting from a very long wrapping line
1013 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1014 Editor_state
= edit
.initialize_test_state()
1015 Editor_state
.lines
= load_array
{'abc def ghi jkl mno pqr stu vwx yza bcd efg hij', 'XYZ'}
1016 Text
.redraw_all(Editor_state
)
1017 Editor_state
.cursor1
= {line
=1, pos
=2}
1018 Editor_state
.screen_top1
= {line
=1, pos
=1}
1019 Editor_state
.screen_bottom1
= {}
1020 edit
.draw(Editor_state
)
1021 local y
= Editor_state
.top
1022 App
.screen
.check(y
, 'abc ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/baseline/screen:1')
1023 y
= y
+ Editor_state
.line_height
1024 App
.screen
.check(y
, 'def ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/baseline/screen:2')
1025 y
= y
+ Editor_state
.line_height
1026 App
.screen
.check(y
, 'ghi ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/baseline/screen:3')
1027 -- after pagedown we scroll down the very long wrapping line
1028 edit
.run_after_keychord(Editor_state
, 'pagedown')
1029 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/screen_top:line')
1030 check_eq(Editor_state
.screen_top1
.pos
, 9, 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/screen_top:pos')
1031 y
= Editor_state
.top
1032 App
.screen
.check(y
, 'ghi ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/screen:1')
1033 y
= y
+ Editor_state
.line_height
1034 App
.screen
.check(y
, 'jkl ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/screen:2')
1035 y
= y
+ Editor_state
.line_height
1036 App
.screen
.check(y
, 'mno ', 'F - test_pagedown_can_start_from_middle_of_long_wrapping_line/screen:3')
1039 function test_pagedown_never_moves_up()
1040 io
.write('\ntest_pagedown_never_moves_up')
1041 -- draw the final screen line of a wrapping line
1042 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1043 Editor_state
= edit
.initialize_test_state()
1044 Editor_state
.lines
= load_array
{'abc def ghi'}
1045 Text
.redraw_all(Editor_state
)
1046 Editor_state
.cursor1
= {line
=1, pos
=9}
1047 Editor_state
.screen_top1
= {line
=1, pos
=9}
1048 Editor_state
.screen_bottom1
= {}
1049 edit
.draw(Editor_state
)
1050 -- pagedown makes no change
1051 edit
.run_after_keychord(Editor_state
, 'pagedown')
1052 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_pagedown_never_moves_up/screen_top:line')
1053 check_eq(Editor_state
.screen_top1
.pos
, 9, 'F - test_pagedown_never_moves_up/screen_top:pos')
1056 function test_down_arrow_moves_cursor()
1057 io
.write('\ntest_down_arrow_moves_cursor')
1058 App
.screen
.init
{width
=120, height
=60}
1059 Editor_state
= edit
.initialize_test_state()
1060 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1061 Text
.redraw_all(Editor_state
)
1062 Editor_state
.cursor1
= {line
=1, pos
=1}
1063 Editor_state
.screen_top1
= {line
=1, pos
=1}
1064 Editor_state
.screen_bottom1
= {}
1065 -- initially the first three lines are displayed
1066 edit
.draw(Editor_state
)
1067 local y
= Editor_state
.top
1068 App
.screen
.check(y
, 'abc', 'F - test_down_arrow_moves_cursor/baseline/screen:1')
1069 y
= y
+ Editor_state
.line_height
1070 App
.screen
.check(y
, 'def', 'F - test_down_arrow_moves_cursor/baseline/screen:2')
1071 y
= y
+ Editor_state
.line_height
1072 App
.screen
.check(y
, 'ghi', 'F - test_down_arrow_moves_cursor/baseline/screen:3')
1073 -- after hitting the down arrow, the cursor moves down by 1 line
1074 edit
.run_after_keychord(Editor_state
, 'down')
1075 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_down_arrow_moves_cursor/screen_top')
1076 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_down_arrow_moves_cursor/cursor')
1077 -- the screen is unchanged
1078 y
= Editor_state
.top
1079 App
.screen
.check(y
, 'abc', 'F - test_down_arrow_moves_cursor/screen:1')
1080 y
= y
+ Editor_state
.line_height
1081 App
.screen
.check(y
, 'def', 'F - test_down_arrow_moves_cursor/screen:2')
1082 y
= y
+ Editor_state
.line_height
1083 App
.screen
.check(y
, 'ghi', 'F - test_down_arrow_moves_cursor/screen:3')
1086 function test_down_arrow_scrolls_down_by_one_line()
1087 io
.write('\ntest_down_arrow_scrolls_down_by_one_line')
1088 -- display the first three lines with the cursor on the bottom line
1089 App
.screen
.init
{width
=120, height
=60}
1090 Editor_state
= edit
.initialize_test_state()
1091 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1092 Text
.redraw_all(Editor_state
)
1093 Editor_state
.cursor1
= {line
=3, pos
=1}
1094 Editor_state
.screen_top1
= {line
=1, pos
=1}
1095 Editor_state
.screen_bottom1
= {}
1096 edit
.draw(Editor_state
)
1097 local y
= Editor_state
.top
1098 App
.screen
.check(y
, 'abc', 'F - test_down_arrow_scrolls_down_by_one_line/baseline/screen:1')
1099 y
= y
+ Editor_state
.line_height
1100 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_line/baseline/screen:2')
1101 y
= y
+ Editor_state
.line_height
1102 App
.screen
.check(y
, 'ghi', 'F - test_down_arrow_scrolls_down_by_one_line/baseline/screen:3')
1103 -- after hitting the down arrow the screen scrolls down by one line
1104 edit
.run_after_keychord(Editor_state
, 'down')
1105 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_down_arrow_scrolls_down_by_one_line/screen_top')
1106 check_eq(Editor_state
.cursor1
.line
, 4, 'F - test_down_arrow_scrolls_down_by_one_line/cursor')
1107 y
= Editor_state
.top
1108 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_line/screen:1')
1109 y
= y
+ Editor_state
.line_height
1110 App
.screen
.check(y
, 'ghi', 'F - test_down_arrow_scrolls_down_by_one_line/screen:2')
1111 y
= y
+ Editor_state
.line_height
1112 App
.screen
.check(y
, 'jkl', 'F - test_down_arrow_scrolls_down_by_one_line/screen:3')
1115 function test_down_arrow_scrolls_down_by_one_screen_line()
1116 io
.write('\ntest_down_arrow_scrolls_down_by_one_screen_line')
1117 -- display the first three lines with the cursor on the bottom line
1118 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1119 Editor_state
= edit
.initialize_test_state()
1120 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1121 Text
.redraw_all(Editor_state
)
1122 Editor_state
.cursor1
= {line
=3, pos
=1}
1123 Editor_state
.screen_top1
= {line
=1, pos
=1}
1124 Editor_state
.screen_bottom1
= {}
1125 edit
.draw(Editor_state
)
1126 local y
= Editor_state
.top
1127 App
.screen
.check(y
, 'abc', 'F - test_down_arrow_scrolls_down_by_one_screen_line/baseline/screen:1')
1128 y
= y
+ Editor_state
.line_height
1129 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_screen_line/baseline/screen:2')
1130 y
= y
+ Editor_state
.line_height
1131 App
.screen
.check(y
, 'ghi ', 'F - test_down_arrow_scrolls_down_by_one_screen_line/baseline/screen:3') -- line wrapping includes trailing whitespace
1132 -- after hitting the down arrow the screen scrolls down by one line
1133 edit
.run_after_keychord(Editor_state
, 'down')
1134 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_down_arrow_scrolls_down_by_one_screen_line/screen_top')
1135 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_down_arrow_scrolls_down_by_one_screen_line/cursor:line')
1136 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_down_arrow_scrolls_down_by_one_screen_line/cursor:pos')
1137 y
= Editor_state
.top
1138 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_screen_line/screen:1')
1139 y
= y
+ Editor_state
.line_height
1140 App
.screen
.check(y
, 'ghi ', 'F - test_down_arrow_scrolls_down_by_one_screen_line/screen:2')
1141 y
= y
+ Editor_state
.line_height
1142 App
.screen
.check(y
, 'jkl', 'F - test_down_arrow_scrolls_down_by_one_screen_line/screen:3')
1145 function test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word()
1146 io
.write('\ntest_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word')
1147 -- display the first three lines with the cursor on the bottom line
1148 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1149 Editor_state
= edit
.initialize_test_state()
1150 Editor_state
.lines
= load_array
{'abc', 'def', 'ghijkl', 'mno'}
1151 Text
.redraw_all(Editor_state
)
1152 Editor_state
.cursor1
= {line
=3, pos
=1}
1153 Editor_state
.screen_top1
= {line
=1, pos
=1}
1154 Editor_state
.screen_bottom1
= {}
1155 edit
.draw(Editor_state
)
1156 local y
= Editor_state
.top
1157 App
.screen
.check(y
, 'abc', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/baseline/screen:1')
1158 y
= y
+ Editor_state
.line_height
1159 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/baseline/screen:2')
1160 y
= y
+ Editor_state
.line_height
1161 App
.screen
.check(y
, 'ghij', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/baseline/screen:3')
1162 -- after hitting the down arrow the screen scrolls down by one line
1163 edit
.run_after_keychord(Editor_state
, 'down')
1164 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/screen_top')
1165 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/cursor:line')
1166 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/cursor:pos')
1167 y
= Editor_state
.top
1168 App
.screen
.check(y
, 'def', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/screen:1')
1169 y
= y
+ Editor_state
.line_height
1170 App
.screen
.check(y
, 'ghij', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/screen:2')
1171 y
= y
+ Editor_state
.line_height
1172 App
.screen
.check(y
, 'kl', 'F - test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_word/screen:3')
1175 function test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up()
1176 io
.write('\ntest_pagedown_followed_by_down_arrow_does_not_scroll_screen_up')
1177 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1178 Editor_state
= edit
.initialize_test_state()
1179 Editor_state
.lines
= load_array
{'abc', 'def', 'ghijkl', 'mno'}
1180 Text
.redraw_all(Editor_state
)
1181 Editor_state
.cursor1
= {line
=3, pos
=1}
1182 Editor_state
.screen_top1
= {line
=1, pos
=1}
1183 Editor_state
.screen_bottom1
= {}
1184 edit
.draw(Editor_state
)
1185 local y
= Editor_state
.top
1186 App
.screen
.check(y
, 'abc', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline/screen:1')
1187 y
= y
+ Editor_state
.line_height
1188 App
.screen
.check(y
, 'def', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline/screen:2')
1189 y
= y
+ Editor_state
.line_height
1190 App
.screen
.check(y
, 'ghij', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline/screen:3')
1191 -- after hitting pagedown the screen scrolls down to start of a long line
1192 edit
.run_after_keychord(Editor_state
, 'pagedown')
1193 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline2/screen_top')
1194 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline2/cursor:line')
1195 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/baseline2/cursor:pos')
1196 -- after hitting down arrow the screen doesn't scroll down further, and certainly doesn't scroll up
1197 edit
.run_after_keychord(Editor_state
, 'down')
1198 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/screen_top')
1199 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/cursor:line')
1200 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/cursor:pos')
1201 y
= Editor_state
.top
1202 App
.screen
.check(y
, 'ghij', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/screen:1')
1203 y
= y
+ Editor_state
.line_height
1204 App
.screen
.check(y
, 'kl', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/screen:2')
1205 y
= y
+ Editor_state
.line_height
1206 App
.screen
.check(y
, 'mno', 'F - test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up/screen:3')
1209 function test_up_arrow_moves_cursor()
1210 io
.write('\ntest_up_arrow_moves_cursor')
1211 -- display the first 3 lines with the cursor on the bottom line
1212 App
.screen
.init
{width
=120, height
=60}
1213 Editor_state
= edit
.initialize_test_state()
1214 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1215 Text
.redraw_all(Editor_state
)
1216 Editor_state
.cursor1
= {line
=3, pos
=1}
1217 Editor_state
.screen_top1
= {line
=1, pos
=1}
1218 Editor_state
.screen_bottom1
= {}
1219 edit
.draw(Editor_state
)
1220 local y
= Editor_state
.top
1221 App
.screen
.check(y
, 'abc', 'F - test_up_arrow_moves_cursor/baseline/screen:1')
1222 y
= y
+ Editor_state
.line_height
1223 App
.screen
.check(y
, 'def', 'F - test_up_arrow_moves_cursor/baseline/screen:2')
1224 y
= y
+ Editor_state
.line_height
1225 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_moves_cursor/baseline/screen:3')
1226 -- after hitting the up arrow the cursor moves up by 1 line
1227 edit
.run_after_keychord(Editor_state
, 'up')
1228 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_up_arrow_moves_cursor/screen_top')
1229 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_up_arrow_moves_cursor/cursor')
1230 -- the screen is unchanged
1231 y
= Editor_state
.top
1232 App
.screen
.check(y
, 'abc', 'F - test_up_arrow_moves_cursor/screen:1')
1233 y
= y
+ Editor_state
.line_height
1234 App
.screen
.check(y
, 'def', 'F - test_up_arrow_moves_cursor/screen:2')
1235 y
= y
+ Editor_state
.line_height
1236 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_moves_cursor/screen:3')
1239 function test_up_arrow_scrolls_up_by_one_line()
1240 io
.write('\ntest_up_arrow_scrolls_up_by_one_line')
1241 -- display the lines 2/3/4 with the cursor on line 2
1242 App
.screen
.init
{width
=120, height
=60}
1243 Editor_state
= edit
.initialize_test_state()
1244 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1245 Text
.redraw_all(Editor_state
)
1246 Editor_state
.cursor1
= {line
=2, pos
=1}
1247 Editor_state
.screen_top1
= {line
=2, pos
=1}
1248 Editor_state
.screen_bottom1
= {}
1249 edit
.draw(Editor_state
)
1250 local y
= Editor_state
.top
1251 App
.screen
.check(y
, 'def', 'F - test_up_arrow_scrolls_up_by_one_line/baseline/screen:1')
1252 y
= y
+ Editor_state
.line_height
1253 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_scrolls_up_by_one_line/baseline/screen:2')
1254 y
= y
+ Editor_state
.line_height
1255 App
.screen
.check(y
, 'jkl', 'F - test_up_arrow_scrolls_up_by_one_line/baseline/screen:3')
1256 -- after hitting the up arrow the screen scrolls up by one line
1257 edit
.run_after_keychord(Editor_state
, 'up')
1258 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_up_arrow_scrolls_up_by_one_line/screen_top')
1259 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_up_arrow_scrolls_up_by_one_line/cursor')
1260 y
= Editor_state
.top
1261 App
.screen
.check(y
, 'abc', 'F - test_up_arrow_scrolls_up_by_one_line/screen:1')
1262 y
= y
+ Editor_state
.line_height
1263 App
.screen
.check(y
, 'def', 'F - test_up_arrow_scrolls_up_by_one_line/screen:2')
1264 y
= y
+ Editor_state
.line_height
1265 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_scrolls_up_by_one_line/screen:3')
1268 function test_up_arrow_scrolls_up_by_one_screen_line()
1269 io
.write('\ntest_up_arrow_scrolls_up_by_one_screen_line')
1270 -- display lines starting from second screen line of a line
1271 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1272 Editor_state
= edit
.initialize_test_state()
1273 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1274 Text
.redraw_all(Editor_state
)
1275 Editor_state
.cursor1
= {line
=3, pos
=6}
1276 Editor_state
.screen_top1
= {line
=3, pos
=5}
1277 Editor_state
.screen_bottom1
= {}
1278 edit
.draw(Editor_state
)
1279 local y
= Editor_state
.top
1280 App
.screen
.check(y
, 'jkl', 'F - test_up_arrow_scrolls_up_by_one_screen_line/baseline/screen:1')
1281 y
= y
+ Editor_state
.line_height
1282 App
.screen
.check(y
, 'mno', 'F - test_up_arrow_scrolls_up_by_one_screen_line/baseline/screen:2')
1283 -- after hitting the up arrow the screen scrolls up to first screen line
1284 edit
.run_after_keychord(Editor_state
, 'up')
1285 y
= Editor_state
.top
1286 App
.screen
.check(y
, 'ghi ', 'F - test_up_arrow_scrolls_up_by_one_screen_line/screen:1')
1287 y
= y
+ Editor_state
.line_height
1288 App
.screen
.check(y
, 'jkl', 'F - test_up_arrow_scrolls_up_by_one_screen_line/screen:2')
1289 y
= y
+ Editor_state
.line_height
1290 App
.screen
.check(y
, 'mno', 'F - test_up_arrow_scrolls_up_by_one_screen_line/screen:3')
1291 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_up_arrow_scrolls_up_by_one_screen_line/screen_top')
1292 check_eq(Editor_state
.screen_top1
.pos
, 1, 'F - test_up_arrow_scrolls_up_by_one_screen_line/screen_top')
1293 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_up_arrow_scrolls_up_by_one_screen_line/cursor:line')
1294 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_up_arrow_scrolls_up_by_one_screen_line/cursor:pos')
1297 function test_up_arrow_scrolls_up_to_final_screen_line()
1298 io
.write('\ntest_up_arrow_scrolls_up_to_final_screen_line')
1299 -- display lines starting just after a long line
1300 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1301 Editor_state
= edit
.initialize_test_state()
1302 Editor_state
.lines
= load_array
{'abc def', 'ghi', 'jkl', 'mno'}
1303 Text
.redraw_all(Editor_state
)
1304 Editor_state
.cursor1
= {line
=2, pos
=1}
1305 Editor_state
.screen_top1
= {line
=2, pos
=1}
1306 Editor_state
.screen_bottom1
= {}
1307 edit
.draw(Editor_state
)
1308 local y
= Editor_state
.top
1309 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_scrolls_up_to_final_screen_line/baseline/screen:1')
1310 y
= y
+ Editor_state
.line_height
1311 App
.screen
.check(y
, 'jkl', 'F - test_up_arrow_scrolls_up_to_final_screen_line/baseline/screen:2')
1312 y
= y
+ Editor_state
.line_height
1313 App
.screen
.check(y
, 'mno', 'F - test_up_arrow_scrolls_up_to_final_screen_line/baseline/screen:3')
1314 -- after hitting the up arrow the screen scrolls up to final screen line of previous line
1315 edit
.run_after_keychord(Editor_state
, 'up')
1316 y
= Editor_state
.top
1317 App
.screen
.check(y
, 'def', 'F - test_up_arrow_scrolls_up_to_final_screen_line/screen:1')
1318 y
= y
+ Editor_state
.line_height
1319 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_scrolls_up_to_final_screen_line/screen:2')
1320 y
= y
+ Editor_state
.line_height
1321 App
.screen
.check(y
, 'jkl', 'F - test_up_arrow_scrolls_up_to_final_screen_line/screen:3')
1322 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_up_arrow_scrolls_up_to_final_screen_line/screen_top')
1323 check_eq(Editor_state
.screen_top1
.pos
, 5, 'F - test_up_arrow_scrolls_up_to_final_screen_line/screen_top')
1324 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_up_arrow_scrolls_up_to_final_screen_line/cursor:line')
1325 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_up_arrow_scrolls_up_to_final_screen_line/cursor:pos')
1328 function test_up_arrow_scrolls_up_to_empty_line()
1329 io
.write('\ntest_up_arrow_scrolls_up_to_empty_line')
1330 -- display a screenful of text with an empty line just above it outside the screen
1331 App
.screen
.init
{width
=120, height
=60}
1332 Editor_state
= edit
.initialize_test_state()
1333 Editor_state
.lines
= load_array
{'', 'abc', 'def', 'ghi', 'jkl'}
1334 Text
.redraw_all(Editor_state
)
1335 Editor_state
.cursor1
= {line
=2, pos
=1}
1336 Editor_state
.screen_top1
= {line
=2, pos
=1}
1337 Editor_state
.screen_bottom1
= {}
1338 edit
.draw(Editor_state
)
1339 local y
= Editor_state
.top
1340 App
.screen
.check(y
, 'abc', 'F - test_up_arrow_scrolls_up_to_empty_line/baseline/screen:1')
1341 y
= y
+ Editor_state
.line_height
1342 App
.screen
.check(y
, 'def', 'F - test_up_arrow_scrolls_up_to_empty_line/baseline/screen:2')
1343 y
= y
+ Editor_state
.line_height
1344 App
.screen
.check(y
, 'ghi', 'F - test_up_arrow_scrolls_up_to_empty_line/baseline/screen:3')
1345 -- after hitting the up arrow the screen scrolls up by one line
1346 edit
.run_after_keychord(Editor_state
, 'up')
1347 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_up_arrow_scrolls_up_to_empty_line/screen_top')
1348 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_up_arrow_scrolls_up_to_empty_line/cursor')
1349 y
= Editor_state
.top
1351 y
= y
+ Editor_state
.line_height
1352 App
.screen
.check(y
, 'abc', 'F - test_up_arrow_scrolls_up_to_empty_line/screen:2')
1353 y
= y
+ Editor_state
.line_height
1354 App
.screen
.check(y
, 'def', 'F - test_up_arrow_scrolls_up_to_empty_line/screen:3')
1357 function test_pageup()
1358 io
.write('\ntest_pageup')
1359 App
.screen
.init
{width
=120, height
=45}
1360 Editor_state
= edit
.initialize_test_state()
1361 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi'}
1362 Text
.redraw_all(Editor_state
)
1363 Editor_state
.cursor1
= {line
=2, pos
=1}
1364 Editor_state
.screen_top1
= {line
=2, pos
=1}
1365 Editor_state
.screen_bottom1
= {}
1366 -- initially the last two lines are displayed
1367 edit
.draw(Editor_state
)
1368 local y
= Editor_state
.top
1369 App
.screen
.check(y
, 'def', 'F - test_pageup/baseline/screen:1')
1370 y
= y
+ Editor_state
.line_height
1371 App
.screen
.check(y
, 'ghi', 'F - test_pageup/baseline/screen:2')
1372 -- after pageup the cursor goes to first line
1373 edit
.run_after_keychord(Editor_state
, 'pageup')
1374 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_pageup/screen_top')
1375 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_pageup/cursor')
1376 y
= Editor_state
.top
1377 App
.screen
.check(y
, 'abc', 'F - test_pageup/screen:1')
1378 y
= y
+ Editor_state
.line_height
1379 App
.screen
.check(y
, 'def', 'F - test_pageup/screen:2')
1382 function test_pageup_scrolls_up_by_screen_line()
1383 io
.write('\ntest_pageup_scrolls_up_by_screen_line')
1384 -- display the first three lines with the cursor on the bottom line
1385 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1386 Editor_state
= edit
.initialize_test_state()
1387 Editor_state
.lines
= load_array
{'abc def', 'ghi', 'jkl', 'mno'}
1388 Text
.redraw_all(Editor_state
)
1389 Editor_state
.cursor1
= {line
=2, pos
=1}
1390 Editor_state
.screen_top1
= {line
=2, pos
=1}
1391 Editor_state
.screen_bottom1
= {}
1392 edit
.draw(Editor_state
)
1393 local y
= Editor_state
.top
1394 App
.screen
.check(y
, 'ghi', 'F - test_pageup_scrolls_up_by_screen_line/baseline/screen:1')
1395 y
= y
+ Editor_state
.line_height
1396 App
.screen
.check(y
, 'jkl', 'F - test_pageup_scrolls_up_by_screen_line/baseline/screen:2')
1397 y
= y
+ Editor_state
.line_height
1398 App
.screen
.check(y
, 'mno', 'F - test_pageup_scrolls_up_by_screen_line/baseline/screen:3') -- line wrapping includes trailing whitespace
1399 -- after hitting the page-up key the screen scrolls up to top
1400 edit
.run_after_keychord(Editor_state
, 'pageup')
1401 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_pageup_scrolls_up_by_screen_line/screen_top')
1402 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_pageup_scrolls_up_by_screen_line/cursor:line')
1403 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_pageup_scrolls_up_by_screen_line/cursor:pos')
1404 y
= Editor_state
.top
1405 App
.screen
.check(y
, 'abc ', 'F - test_pageup_scrolls_up_by_screen_line/screen:1')
1406 y
= y
+ Editor_state
.line_height
1407 App
.screen
.check(y
, 'def', 'F - test_pageup_scrolls_up_by_screen_line/screen:2')
1408 y
= y
+ Editor_state
.line_height
1409 App
.screen
.check(y
, 'ghi', 'F - test_pageup_scrolls_up_by_screen_line/screen:3')
1412 function test_pageup_scrolls_up_from_middle_screen_line()
1413 io
.write('\ntest_pageup_scrolls_up_from_middle_screen_line')
1414 -- display a few lines starting from the middle of a line (Editor_state.cursor1.pos > 1)
1415 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1416 Editor_state
= edit
.initialize_test_state()
1417 Editor_state
.lines
= load_array
{'abc def', 'ghi jkl', 'mno'}
1418 Text
.redraw_all(Editor_state
)
1419 Editor_state
.cursor1
= {line
=2, pos
=5}
1420 Editor_state
.screen_top1
= {line
=2, pos
=5}
1421 Editor_state
.screen_bottom1
= {}
1422 edit
.draw(Editor_state
)
1423 local y
= Editor_state
.top
1424 App
.screen
.check(y
, 'jkl', 'F - test_pageup_scrolls_up_from_middle_screen_line/baseline/screen:2')
1425 y
= y
+ Editor_state
.line_height
1426 App
.screen
.check(y
, 'mno', 'F - test_pageup_scrolls_up_from_middle_screen_line/baseline/screen:3') -- line wrapping includes trailing whitespace
1427 -- after hitting the page-up key the screen scrolls up to top
1428 edit
.run_after_keychord(Editor_state
, 'pageup')
1429 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_pageup_scrolls_up_from_middle_screen_line/screen_top')
1430 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_pageup_scrolls_up_from_middle_screen_line/cursor:line')
1431 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_pageup_scrolls_up_from_middle_screen_line/cursor:pos')
1432 y
= Editor_state
.top
1433 App
.screen
.check(y
, 'abc ', 'F - test_pageup_scrolls_up_from_middle_screen_line/screen:1')
1434 y
= y
+ Editor_state
.line_height
1435 App
.screen
.check(y
, 'def', 'F - test_pageup_scrolls_up_from_middle_screen_line/screen:2')
1436 y
= y
+ Editor_state
.line_height
1437 App
.screen
.check(y
, 'ghi ', 'F - test_pageup_scrolls_up_from_middle_screen_line/screen:3')
1440 function test_enter_on_bottom_line_scrolls_down()
1441 io
.write('\ntest_enter_on_bottom_line_scrolls_down')
1442 -- display a few lines with cursor on bottom line
1443 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1444 Editor_state
= edit
.initialize_test_state()
1445 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1446 Text
.redraw_all(Editor_state
)
1447 Editor_state
.cursor1
= {line
=3, pos
=2}
1448 Editor_state
.screen_top1
= {line
=1, pos
=1}
1449 Editor_state
.screen_bottom1
= {}
1450 edit
.draw(Editor_state
)
1451 local y
= Editor_state
.top
1452 App
.screen
.check(y
, 'abc', 'F - test_enter_on_bottom_line_scrolls_down/baseline/screen:1')
1453 y
= y
+ Editor_state
.line_height
1454 App
.screen
.check(y
, 'def', 'F - test_enter_on_bottom_line_scrolls_down/baseline/screen:2')
1455 y
= y
+ Editor_state
.line_height
1456 App
.screen
.check(y
, 'ghi', 'F - test_enter_on_bottom_line_scrolls_down/baseline/screen:3')
1457 -- after hitting the enter key the screen scrolls down
1458 edit
.run_after_keychord(Editor_state
, 'return')
1459 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_enter_on_bottom_line_scrolls_down/screen_top')
1460 check_eq(Editor_state
.cursor1
.line
, 4, 'F - test_enter_on_bottom_line_scrolls_down/cursor:line')
1461 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_enter_on_bottom_line_scrolls_down/cursor:pos')
1462 y
= Editor_state
.top
1463 App
.screen
.check(y
, 'def', 'F - test_enter_on_bottom_line_scrolls_down/screen:1')
1464 y
= y
+ Editor_state
.line_height
1465 App
.screen
.check(y
, 'g', 'F - test_enter_on_bottom_line_scrolls_down/screen:2')
1466 y
= y
+ Editor_state
.line_height
1467 App
.screen
.check(y
, 'hi', 'F - test_enter_on_bottom_line_scrolls_down/screen:3')
1470 function test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom()
1471 io
.write('\ntest_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom')
1472 -- display just the bottom line on screen
1473 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1474 Editor_state
= edit
.initialize_test_state()
1475 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1476 Text
.redraw_all(Editor_state
)
1477 Editor_state
.cursor1
= {line
=4, pos
=2}
1478 Editor_state
.screen_top1
= {line
=4, pos
=1}
1479 Editor_state
.screen_bottom1
= {}
1480 edit
.draw(Editor_state
)
1481 local y
= Editor_state
.top
1482 App
.screen
.check(y
, 'jkl', 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/baseline/screen:1')
1483 -- after hitting the enter key the screen does not scroll down
1484 edit
.run_after_keychord(Editor_state
, 'return')
1485 check_eq(Editor_state
.screen_top1
.line
, 4, 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/screen_top')
1486 check_eq(Editor_state
.cursor1
.line
, 5, 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/cursor:line')
1487 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/cursor:pos')
1488 y
= Editor_state
.top
1489 App
.screen
.check(y
, 'j', 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/screen:1')
1490 y
= y
+ Editor_state
.line_height
1491 App
.screen
.check(y
, 'kl', 'F - test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom/screen:2')
1494 function test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom()
1495 io
.write('\ntest_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom')
1496 -- display just an empty bottom line on screen
1497 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1498 Editor_state
= edit
.initialize_test_state()
1499 Editor_state
.lines
= load_array
{'abc', ''}
1500 Text
.redraw_all(Editor_state
)
1501 Editor_state
.cursor1
= {line
=2, pos
=1}
1502 Editor_state
.screen_top1
= {line
=2, pos
=1}
1503 Editor_state
.screen_bottom1
= {}
1504 edit
.draw(Editor_state
)
1505 -- after hitting the inserting_text key the screen does not scroll down
1506 edit
.run_after_text_input(Editor_state
, 'a')
1507 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom/screen_top')
1508 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom/cursor:line')
1509 check_eq(Editor_state
.cursor1
.pos
, 2, 'F - test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom/cursor:pos')
1510 local y
= Editor_state
.top
1511 App
.screen
.check(y
, 'a', 'F - test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bottom/screen:1')
1514 function test_typing_on_bottom_line_scrolls_down()
1515 io
.write('\ntest_typing_on_bottom_line_scrolls_down')
1516 -- display a few lines with cursor on bottom line
1517 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1518 Editor_state
= edit
.initialize_test_state()
1519 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1520 Text
.redraw_all(Editor_state
)
1521 Editor_state
.cursor1
= {line
=3, pos
=4}
1522 Editor_state
.screen_top1
= {line
=1, pos
=1}
1523 Editor_state
.screen_bottom1
= {}
1524 edit
.draw(Editor_state
)
1525 local y
= Editor_state
.top
1526 App
.screen
.check(y
, 'abc', 'F - test_typing_on_bottom_line_scrolls_down/baseline/screen:1')
1527 y
= y
+ Editor_state
.line_height
1528 App
.screen
.check(y
, 'def', 'F - test_typing_on_bottom_line_scrolls_down/baseline/screen:2')
1529 y
= y
+ Editor_state
.line_height
1530 App
.screen
.check(y
, 'ghi', 'F - test_typing_on_bottom_line_scrolls_down/baseline/screen:3')
1531 -- after typing something the line wraps and the screen scrolls down
1532 edit
.run_after_text_input(Editor_state
, 'j')
1533 edit
.run_after_text_input(Editor_state
, 'k')
1534 edit
.run_after_text_input(Editor_state
, 'l')
1535 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_typing_on_bottom_line_scrolls_down/screen_top')
1536 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_typing_on_bottom_line_scrolls_down/cursor:line')
1537 check_eq(Editor_state
.cursor1
.pos
, 7, 'F - test_typing_on_bottom_line_scrolls_down/cursor:pos')
1538 y
= Editor_state
.top
1539 App
.screen
.check(y
, 'def', 'F - test_typing_on_bottom_line_scrolls_down/screen:1')
1540 y
= y
+ Editor_state
.line_height
1541 App
.screen
.check(y
, 'ghij', 'F - test_typing_on_bottom_line_scrolls_down/screen:2')
1542 y
= y
+ Editor_state
.line_height
1543 App
.screen
.check(y
, 'kl', 'F - test_typing_on_bottom_line_scrolls_down/screen:3')
1546 function test_left_arrow_scrolls_up_in_wrapped_line()
1547 io
.write('\ntest_left_arrow_scrolls_up_in_wrapped_line')
1548 -- display lines starting from second screen line of a line
1549 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1550 Editor_state
= edit
.initialize_test_state()
1551 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1552 Text
.redraw_all(Editor_state
)
1553 Editor_state
.screen_top1
= {line
=3, pos
=5}
1554 Editor_state
.screen_bottom1
= {}
1555 -- cursor is at top of screen
1556 Editor_state
.cursor1
= {line
=3, pos
=5}
1557 edit
.draw(Editor_state
)
1558 local y
= Editor_state
.top
1559 App
.screen
.check(y
, 'jkl', 'F - test_left_arrow_scrolls_up_in_wrapped_line/baseline/screen:1')
1560 y
= y
+ Editor_state
.line_height
1561 App
.screen
.check(y
, 'mno', 'F - test_left_arrow_scrolls_up_in_wrapped_line/baseline/screen:2')
1562 -- after hitting the left arrow the screen scrolls up to first screen line
1563 edit
.run_after_keychord(Editor_state
, 'left')
1564 y
= Editor_state
.top
1565 App
.screen
.check(y
, 'ghi ', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:1')
1566 y
= y
+ Editor_state
.line_height
1567 App
.screen
.check(y
, 'jkl', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:2')
1568 y
= y
+ Editor_state
.line_height
1569 App
.screen
.check(y
, 'mno', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:3')
1570 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen_top')
1571 check_eq(Editor_state
.screen_top1
.pos
, 1, 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen_top')
1572 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_left_arrow_scrolls_up_in_wrapped_line/cursor:line')
1573 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_left_arrow_scrolls_up_in_wrapped_line/cursor:pos')
1576 function test_right_arrow_scrolls_down_in_wrapped_line()
1577 io
.write('\ntest_right_arrow_scrolls_down_in_wrapped_line')
1578 -- display the first three lines with the cursor on the bottom line
1579 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1580 Editor_state
= edit
.initialize_test_state()
1581 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1582 Text
.redraw_all(Editor_state
)
1583 Editor_state
.screen_top1
= {line
=1, pos
=1}
1584 Editor_state
.screen_bottom1
= {}
1585 -- cursor is at bottom right of screen
1586 Editor_state
.cursor1
= {line
=3, pos
=5}
1587 edit
.draw(Editor_state
)
1588 local y
= Editor_state
.top
1589 App
.screen
.check(y
, 'abc', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:1')
1590 y
= y
+ Editor_state
.line_height
1591 App
.screen
.check(y
, 'def', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:2')
1592 y
= y
+ Editor_state
.line_height
1593 App
.screen
.check(y
, 'ghi ', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:3') -- line wrapping includes trailing whitespace
1594 -- after hitting the right arrow the screen scrolls down by one line
1595 edit
.run_after_keychord(Editor_state
, 'right')
1596 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen_top')
1597 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_right_arrow_scrolls_down_in_wrapped_line/cursor:line')
1598 check_eq(Editor_state
.cursor1
.pos
, 6, 'F - test_right_arrow_scrolls_down_in_wrapped_line/cursor:pos')
1599 y
= Editor_state
.top
1600 App
.screen
.check(y
, 'def', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:1')
1601 y
= y
+ Editor_state
.line_height
1602 App
.screen
.check(y
, 'ghi ', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:2')
1603 y
= y
+ Editor_state
.line_height
1604 App
.screen
.check(y
, 'jkl', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:3')
1607 function test_home_scrolls_up_in_wrapped_line()
1608 io
.write('\ntest_home_scrolls_up_in_wrapped_line')
1609 -- display lines starting from second screen line of a line
1610 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1611 Editor_state
= edit
.initialize_test_state()
1612 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1613 Text
.redraw_all(Editor_state
)
1614 Editor_state
.screen_top1
= {line
=3, pos
=5}
1615 Editor_state
.screen_bottom1
= {}
1616 -- cursor is at top of screen
1617 Editor_state
.cursor1
= {line
=3, pos
=5}
1618 edit
.draw(Editor_state
)
1619 local y
= Editor_state
.top
1620 App
.screen
.check(y
, 'jkl', 'F - test_home_scrolls_up_in_wrapped_line/baseline/screen:1')
1621 y
= y
+ Editor_state
.line_height
1622 App
.screen
.check(y
, 'mno', 'F - test_home_scrolls_up_in_wrapped_line/baseline/screen:2')
1623 -- after hitting home the screen scrolls up to first screen line
1624 edit
.run_after_keychord(Editor_state
, 'home')
1625 y
= Editor_state
.top
1626 App
.screen
.check(y
, 'ghi ', 'F - test_home_scrolls_up_in_wrapped_line/screen:1')
1627 y
= y
+ Editor_state
.line_height
1628 App
.screen
.check(y
, 'jkl', 'F - test_home_scrolls_up_in_wrapped_line/screen:2')
1629 y
= y
+ Editor_state
.line_height
1630 App
.screen
.check(y
, 'mno', 'F - test_home_scrolls_up_in_wrapped_line/screen:3')
1631 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_home_scrolls_up_in_wrapped_line/screen_top')
1632 check_eq(Editor_state
.screen_top1
.pos
, 1, 'F - test_home_scrolls_up_in_wrapped_line/screen_top')
1633 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_home_scrolls_up_in_wrapped_line/cursor:line')
1634 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_home_scrolls_up_in_wrapped_line/cursor:pos')
1637 function test_end_scrolls_down_in_wrapped_line()
1638 io
.write('\ntest_end_scrolls_down_in_wrapped_line')
1639 -- display the first three lines with the cursor on the bottom line
1640 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1641 Editor_state
= edit
.initialize_test_state()
1642 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1643 Text
.redraw_all(Editor_state
)
1644 Editor_state
.screen_top1
= {line
=1, pos
=1}
1645 Editor_state
.screen_bottom1
= {}
1646 -- cursor is at bottom right of screen
1647 Editor_state
.cursor1
= {line
=3, pos
=5}
1648 edit
.draw(Editor_state
)
1649 local y
= Editor_state
.top
1650 App
.screen
.check(y
, 'abc', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:1')
1651 y
= y
+ Editor_state
.line_height
1652 App
.screen
.check(y
, 'def', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:2')
1653 y
= y
+ Editor_state
.line_height
1654 App
.screen
.check(y
, 'ghi ', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:3') -- line wrapping includes trailing whitespace
1655 -- after hitting end the screen scrolls down by one line
1656 edit
.run_after_keychord(Editor_state
, 'end')
1657 check_eq(Editor_state
.screen_top1
.line
, 2, 'F - test_end_scrolls_down_in_wrapped_line/screen_top')
1658 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_end_scrolls_down_in_wrapped_line/cursor:line')
1659 check_eq(Editor_state
.cursor1
.pos
, 8, 'F - test_end_scrolls_down_in_wrapped_line/cursor:pos')
1660 y
= Editor_state
.top
1661 App
.screen
.check(y
, 'def', 'F - test_end_scrolls_down_in_wrapped_line/screen:1')
1662 y
= y
+ Editor_state
.line_height
1663 App
.screen
.check(y
, 'ghi ', 'F - test_end_scrolls_down_in_wrapped_line/screen:2')
1664 y
= y
+ Editor_state
.line_height
1665 App
.screen
.check(y
, 'jkl', 'F - test_end_scrolls_down_in_wrapped_line/screen:3')
1668 function test_position_cursor_on_recently_edited_wrapping_line()
1669 -- draw a line wrapping over 2 screen lines
1670 io
.write('\ntest_position_cursor_on_recently_edited_wrapping_line')
1671 App
.screen
.init
{width
=100, height
=200}
1672 Editor_state
= edit
.initialize_test_state()
1673 Editor_state
.lines
= load_array
{'abc def ghi jkl mno pqr ', 'xyz'}
1674 Text
.redraw_all(Editor_state
)
1675 Editor_state
.cursor1
= {line
=1, pos
=25}
1676 Editor_state
.screen_top1
= {line
=1, pos
=1}
1677 Editor_state
.screen_bottom1
= {}
1678 edit
.draw(Editor_state
)
1679 local y
= Editor_state
.top
1680 App
.screen
.check(y
, 'abc def ghi ', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline1/screen:1')
1681 y
= y
+ Editor_state
.line_height
1682 App
.screen
.check(y
, 'jkl mno pqr ', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline1/screen:2')
1683 y
= y
+ Editor_state
.line_height
1684 App
.screen
.check(y
, 'xyz', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline1/screen:3')
1685 -- add to the line until it's wrapping over 3 screen lines
1686 edit
.run_after_text_input(Editor_state
, 's')
1687 edit
.run_after_text_input(Editor_state
, 't')
1688 edit
.run_after_text_input(Editor_state
, 'u')
1689 check_eq(Editor_state
.cursor1
.pos
, 28, 'F - test_position_cursor_on_recently_edited_wrapping_line/cursor:pos')
1690 y
= Editor_state
.top
1691 App
.screen
.check(y
, 'abc def ghi ', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline2/screen:1')
1692 y
= y
+ Editor_state
.line_height
1693 App
.screen
.check(y
, 'jkl mno pqr ', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline2/screen:2')
1694 y
= y
+ Editor_state
.line_height
1695 App
.screen
.check(y
, 'stu', 'F - test_position_cursor_on_recently_edited_wrapping_line/baseline2/screen:3')
1696 -- try to move the cursor earlier in the third screen line by clicking the mouse
1697 edit
.run_after_mouse_release(Editor_state
, Editor_state
.left
+8,Editor_state
.top
+Editor_state
.line_height
*2+5, 1)
1698 -- cursor should move
1699 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_position_cursor_on_recently_edited_wrapping_line/cursor:line')
1700 check_eq(Editor_state
.cursor1
.pos
, 26, 'F - test_position_cursor_on_recently_edited_wrapping_line/cursor:pos')
1703 function test_backspace_can_scroll_up()
1704 io
.write('\ntest_backspace_can_scroll_up')
1705 -- display the lines 2/3/4 with the cursor on line 2
1706 App
.screen
.init
{width
=120, height
=60}
1707 Editor_state
= edit
.initialize_test_state()
1708 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl'}
1709 Text
.redraw_all(Editor_state
)
1710 Editor_state
.cursor1
= {line
=2, pos
=1}
1711 Editor_state
.screen_top1
= {line
=2, pos
=1}
1712 Editor_state
.screen_bottom1
= {}
1713 edit
.draw(Editor_state
)
1714 local y
= Editor_state
.top
1715 App
.screen
.check(y
, 'def', 'F - test_backspace_can_scroll_up/baseline/screen:1')
1716 y
= y
+ Editor_state
.line_height
1717 App
.screen
.check(y
, 'ghi', 'F - test_backspace_can_scroll_up/baseline/screen:2')
1718 y
= y
+ Editor_state
.line_height
1719 App
.screen
.check(y
, 'jkl', 'F - test_backspace_can_scroll_up/baseline/screen:3')
1720 -- after hitting backspace the screen scrolls up by one line
1721 edit
.run_after_keychord(Editor_state
, 'backspace')
1722 check_eq(Editor_state
.screen_top1
.line
, 1, 'F - test_backspace_can_scroll_up/screen_top')
1723 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_backspace_can_scroll_up/cursor')
1724 y
= Editor_state
.top
1725 App
.screen
.check(y
, 'abcdef', 'F - test_backspace_can_scroll_up/screen:1')
1726 y
= y
+ Editor_state
.line_height
1727 App
.screen
.check(y
, 'ghi', 'F - test_backspace_can_scroll_up/screen:2')
1728 y
= y
+ Editor_state
.line_height
1729 App
.screen
.check(y
, 'jkl', 'F - test_backspace_can_scroll_up/screen:3')
1732 function test_backspace_can_scroll_up_screen_line()
1733 io
.write('\ntest_backspace_can_scroll_up_screen_line')
1734 -- display lines starting from second screen line of a line
1735 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1736 Editor_state
= edit
.initialize_test_state()
1737 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi jkl', 'mno'}
1738 Text
.redraw_all(Editor_state
)
1739 Editor_state
.cursor1
= {line
=3, pos
=5}
1740 Editor_state
.screen_top1
= {line
=3, pos
=5}
1741 Editor_state
.screen_bottom1
= {}
1742 edit
.draw(Editor_state
)
1743 local y
= Editor_state
.top
1744 App
.screen
.check(y
, 'jkl', 'F - test_backspace_can_scroll_up_screen_line/baseline/screen:1')
1745 y
= y
+ Editor_state
.line_height
1746 App
.screen
.check(y
, 'mno', 'F - test_backspace_can_scroll_up_screen_line/baseline/screen:2')
1747 -- after hitting backspace the screen scrolls up by one screen line
1748 edit
.run_after_keychord(Editor_state
, 'backspace')
1749 y
= Editor_state
.top
1750 App
.screen
.check(y
, 'ghij', 'F - test_backspace_can_scroll_up_screen_line/screen:1')
1751 y
= y
+ Editor_state
.line_height
1752 App
.screen
.check(y
, 'kl', 'F - test_backspace_can_scroll_up_screen_line/screen:2')
1753 y
= y
+ Editor_state
.line_height
1754 App
.screen
.check(y
, 'mno', 'F - test_backspace_can_scroll_up_screen_line/screen:3')
1755 check_eq(Editor_state
.screen_top1
.line
, 3, 'F - test_backspace_can_scroll_up_screen_line/screen_top')
1756 check_eq(Editor_state
.screen_top1
.pos
, 1, 'F - test_backspace_can_scroll_up_screen_line/screen_top')
1757 check_eq(Editor_state
.cursor1
.line
, 3, 'F - test_backspace_can_scroll_up_screen_line/cursor:line')
1758 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_backspace_can_scroll_up_screen_line/cursor:pos')
1761 function test_backspace_past_line_boundary()
1762 io
.write('\ntest_backspace_past_line_boundary')
1763 -- position cursor at start of a (non-first) line
1764 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1765 Editor_state
= edit
.initialize_test_state()
1766 Editor_state
.lines
= load_array
{'abc', 'def'}
1767 Text
.redraw_all(Editor_state
)
1768 Editor_state
.cursor1
= {line
=2, pos
=1}
1769 -- backspace joins with previous line
1770 edit
.run_after_keychord(Editor_state
, 'backspace')
1771 check_eq(Editor_state
.lines
[1].data
, 'abcdef', "F - test_backspace_past_line_boundary")
1774 -- some tests for operating over selections created using Shift- chords
1775 -- we're just testing delete_selection, and it works the same for all keys
1777 function test_backspace_over_selection()
1778 io
.write('\ntest_backspace_over_selection')
1779 -- select just one character within a line with cursor before selection
1780 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1781 Editor_state
= edit
.initialize_test_state()
1782 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl', 'mno'}
1783 Text
.redraw_all(Editor_state
)
1784 Editor_state
.cursor1
= {line
=1, pos
=1}
1785 Editor_state
.selection1
= {line
=1, pos
=2}
1786 -- backspace deletes the selected character, even though it's after the cursor
1787 edit
.run_after_keychord(Editor_state
, 'backspace')
1788 check_eq(Editor_state
.lines
[1].data
, 'bc', "F - test_backspace_over_selection/data")
1789 -- cursor (remains) at start of selection
1790 check_eq(Editor_state
.cursor1
.line
, 1, "F - test_backspace_over_selection/cursor:line")
1791 check_eq(Editor_state
.cursor1
.pos
, 1, "F - test_backspace_over_selection/cursor:pos")
1792 -- selection is cleared
1793 check_nil(Editor_state
.selection1
.line
, "F - test_backspace_over_selection/selection")
1796 function test_backspace_over_selection_reverse()
1797 io
.write('\ntest_backspace_over_selection_reverse')
1798 -- select just one character within a line with cursor after selection
1799 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1800 Editor_state
= edit
.initialize_test_state()
1801 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl', 'mno'}
1802 Text
.redraw_all(Editor_state
)
1803 Editor_state
.cursor1
= {line
=1, pos
=2}
1804 Editor_state
.selection1
= {line
=1, pos
=1}
1805 -- backspace deletes the selected character
1806 edit
.run_after_keychord(Editor_state
, 'backspace')
1807 check_eq(Editor_state
.lines
[1].data
, 'bc', "F - test_backspace_over_selection_reverse/data")
1808 -- cursor moves to start of selection
1809 check_eq(Editor_state
.cursor1
.line
, 1, "F - test_backspace_over_selection_reverse/cursor:line")
1810 check_eq(Editor_state
.cursor1
.pos
, 1, "F - test_backspace_over_selection_reverse/cursor:pos")
1811 -- selection is cleared
1812 check_nil(Editor_state
.selection1
.line
, "F - test_backspace_over_selection_reverse/selection")
1815 function test_backspace_over_multiple_lines()
1816 io
.write('\ntest_backspace_over_multiple_lines')
1817 -- select just one character within a line with cursor after selection
1818 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1819 Editor_state
= edit
.initialize_test_state()
1820 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl', 'mno'}
1821 Text
.redraw_all(Editor_state
)
1822 Editor_state
.cursor1
= {line
=1, pos
=2}
1823 Editor_state
.selection1
= {line
=4, pos
=2}
1824 -- backspace deletes the region and joins the remaining portions of lines on either side
1825 edit
.run_after_keychord(Editor_state
, 'backspace')
1826 check_eq(Editor_state
.lines
[1].data
, 'akl', "F - test_backspace_over_multiple_lines/data:1")
1827 check_eq(Editor_state
.lines
[2].data
, 'mno', "F - test_backspace_over_multiple_lines/data:2")
1828 -- cursor remains at start of selection
1829 check_eq(Editor_state
.cursor1
.line
, 1, "F - test_backspace_over_multiple_lines/cursor:line")
1830 check_eq(Editor_state
.cursor1
.pos
, 2, "F - test_backspace_over_multiple_lines/cursor:pos")
1831 -- selection is cleared
1832 check_nil(Editor_state
.selection1
.line
, "F - test_backspace_over_multiple_lines/selection")
1835 function test_backspace_to_end_of_line()
1836 io
.write('\ntest_backspace_to_end_of_line')
1837 -- select region from cursor to end of line
1838 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1839 Editor_state
= edit
.initialize_test_state()
1840 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl', 'mno'}
1841 Text
.redraw_all(Editor_state
)
1842 Editor_state
.cursor1
= {line
=1, pos
=2}
1843 Editor_state
.selection1
= {line
=1, pos
=4}
1844 -- backspace deletes rest of line without joining to any other line
1845 edit
.run_after_keychord(Editor_state
, 'backspace')
1846 check_eq(Editor_state
.lines
[1].data
, 'a', "F - test_backspace_to_start_of_line/data:1")
1847 check_eq(Editor_state
.lines
[2].data
, 'def', "F - test_backspace_to_start_of_line/data:2")
1848 -- cursor remains at start of selection
1849 check_eq(Editor_state
.cursor1
.line
, 1, "F - test_backspace_to_start_of_line/cursor:line")
1850 check_eq(Editor_state
.cursor1
.pos
, 2, "F - test_backspace_to_start_of_line/cursor:pos")
1851 -- selection is cleared
1852 check_nil(Editor_state
.selection1
.line
, "F - test_backspace_to_start_of_line/selection")
1855 function test_backspace_to_start_of_line()
1856 io
.write('\ntest_backspace_to_start_of_line')
1857 -- select region from cursor to start of line
1858 App
.screen
.init
{width
=Editor_state
.left
+30, height
=60}
1859 Editor_state
= edit
.initialize_test_state()
1860 Editor_state
.lines
= load_array
{'abc', 'def', 'ghi', 'jkl', 'mno'}
1861 Text
.redraw_all(Editor_state
)
1862 Editor_state
.cursor1
= {line
=2, pos
=1}
1863 Editor_state
.selection1
= {line
=2, pos
=3}
1864 -- backspace deletes beginning of line without joining to any other line
1865 edit
.run_after_keychord(Editor_state
, 'backspace')
1866 check_eq(Editor_state
.lines
[1].data
, 'abc', "F - test_backspace_to_start_of_line/data:1")
1867 check_eq(Editor_state
.lines
[2].data
, 'f', "F - test_backspace_to_start_of_line/data:2")
1868 -- cursor remains at start of selection
1869 check_eq(Editor_state
.cursor1
.line
, 2, "F - test_backspace_to_start_of_line/cursor:line")
1870 check_eq(Editor_state
.cursor1
.pos
, 1, "F - test_backspace_to_start_of_line/cursor:pos")
1871 -- selection is cleared
1872 check_nil(Editor_state
.selection1
.line
, "F - test_backspace_to_start_of_line/selection")
1875 function test_undo_insert_text()
1876 io
.write('\ntest_undo_insert_text')
1877 App
.screen
.init
{width
=120, height
=60}
1878 Editor_state
= edit
.initialize_test_state()
1879 Editor_state
.lines
= load_array
{'abc', 'def', 'xyz'}
1880 Text
.redraw_all(Editor_state
)
1881 Editor_state
.cursor1
= {line
=2, pos
=4}
1882 Editor_state
.screen_top1
= {line
=1, pos
=1}
1883 Editor_state
.screen_bottom1
= {}
1884 -- insert a character
1885 edit
.draw(Editor_state
)
1886 edit
.run_after_text_input(Editor_state
, 'g')
1887 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_undo_insert_text/baseline/cursor:line')
1888 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_undo_insert_text/baseline/cursor:pos')
1889 check_nil(Editor_state
.selection1
.line
, 'F - test_undo_insert_text/baseline/selection:line')
1890 check_nil(Editor_state
.selection1
.pos
, 'F - test_undo_insert_text/baseline/selection:pos')
1891 local y
= Editor_state
.top
1892 App
.screen
.check(y
, 'abc', 'F - test_undo_insert_text/baseline/screen:1')
1893 y
= y
+ Editor_state
.line_height
1894 App
.screen
.check(y
, 'defg', 'F - test_undo_insert_text/baseline/screen:2')
1895 y
= y
+ Editor_state
.line_height
1896 App
.screen
.check(y
, 'xyz', 'F - test_undo_insert_text/baseline/screen:3')
1898 edit
.run_after_keychord(Editor_state
, 'C-z')
1899 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_undo_insert_text/cursor:line')
1900 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_undo_insert_text/cursor:pos')
1901 check_nil(Editor_state
.selection1
.line
, 'F - test_undo_insert_text/selection:line')
1902 check_nil(Editor_state
.selection1
.pos
, 'F - test_undo_insert_text/selection:pos')
1903 y
= Editor_state
.top
1904 App
.screen
.check(y
, 'abc', 'F - test_undo_insert_text/screen:1')
1905 y
= y
+ Editor_state
.line_height
1906 App
.screen
.check(y
, 'def', 'F - test_undo_insert_text/screen:2')
1907 y
= y
+ Editor_state
.line_height
1908 App
.screen
.check(y
, 'xyz', 'F - test_undo_insert_text/screen:3')
1911 function test_undo_delete_text()
1912 io
.write('\ntest_undo_delete_text')
1913 App
.screen
.init
{width
=120, height
=60}
1914 Editor_state
= edit
.initialize_test_state()
1915 Editor_state
.lines
= load_array
{'abc', 'defg', 'xyz'}
1916 Text
.redraw_all(Editor_state
)
1917 Editor_state
.cursor1
= {line
=2, pos
=5}
1918 Editor_state
.screen_top1
= {line
=1, pos
=1}
1919 Editor_state
.screen_bottom1
= {}
1920 -- delete a character
1921 edit
.run_after_keychord(Editor_state
, 'backspace')
1922 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_undo_delete_text/baseline/cursor:line')
1923 check_eq(Editor_state
.cursor1
.pos
, 4, 'F - test_undo_delete_text/baseline/cursor:pos')
1924 check_nil(Editor_state
.selection1
.line
, 'F - test_undo_delete_text/baseline/selection:line')
1925 check_nil(Editor_state
.selection1
.pos
, 'F - test_undo_delete_text/baseline/selection:pos')
1926 local y
= Editor_state
.top
1927 App
.screen
.check(y
, 'abc', 'F - test_undo_delete_text/baseline/screen:1')
1928 y
= y
+ Editor_state
.line_height
1929 App
.screen
.check(y
, 'def', 'F - test_undo_delete_text/baseline/screen:2')
1930 y
= y
+ Editor_state
.line_height
1931 App
.screen
.check(y
, 'xyz', 'F - test_undo_delete_text/baseline/screen:3')
1933 --? -- after undo, the backspaced key is selected
1934 edit
.run_after_keychord(Editor_state
, 'C-z')
1935 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_undo_delete_text/cursor:line')
1936 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_undo_delete_text/cursor:pos')
1937 check_nil(Editor_state
.selection1
.line
, 'F - test_undo_delete_text/selection:line')
1938 check_nil(Editor_state
.selection1
.pos
, 'F - test_undo_delete_text/selection:pos')
1939 --? check_eq(Editor_state.selection1.line, 2, 'F - test_undo_delete_text/selection:line')
1940 --? check_eq(Editor_state.selection1.pos, 4, 'F - test_undo_delete_text/selection:pos')
1941 y
= Editor_state
.top
1942 App
.screen
.check(y
, 'abc', 'F - test_undo_delete_text/screen:1')
1943 y
= y
+ Editor_state
.line_height
1944 App
.screen
.check(y
, 'defg', 'F - test_undo_delete_text/screen:2')
1945 y
= y
+ Editor_state
.line_height
1946 App
.screen
.check(y
, 'xyz', 'F - test_undo_delete_text/screen:3')
1949 function test_undo_restores_selection()
1950 io
.write('\ntest_undo_restores_selection')
1951 -- display a line of text with some part selected
1952 App
.screen
.init
{width
=75, height
=80}
1953 Editor_state
= edit
.initialize_test_state()
1954 Editor_state
.lines
= load_array
{'abc'}
1955 Text
.redraw_all(Editor_state
)
1956 Editor_state
.cursor1
= {line
=1, pos
=1}
1957 Editor_state
.selection1
= {line
=1, pos
=2}
1958 Editor_state
.screen_top1
= {line
=1, pos
=1}
1959 Editor_state
.screen_bottom1
= {}
1960 edit
.draw(Editor_state
)
1961 -- delete selected text
1962 edit
.run_after_text_input(Editor_state
, 'x')
1963 check_eq(Editor_state
.lines
[1].data
, 'xbc', 'F - test_undo_restores_selection/baseline')
1964 check_nil(Editor_state
.selection1
.line
, 'F - test_undo_restores_selection/baseline:selection')
1966 edit
.run_after_keychord(Editor_state
, 'C-z')
1967 edit
.run_after_keychord(Editor_state
, 'C-z')
1968 -- selection is restored
1969 check_eq(Editor_state
.selection1
.line
, 1, 'F - test_undo_restores_selection/line')
1970 check_eq(Editor_state
.selection1
.pos
, 2, 'F - test_undo_restores_selection/pos')
1973 function test_search()
1974 io
.write('\ntest_search')
1975 App
.screen
.init
{width
=120, height
=60}
1976 Editor_state
= edit
.initialize_test_state()
1977 Editor_state
.lines
= load_array
{'```lines', '```', 'def', 'ghi', 'deg'}
1978 Text
.redraw_all(Editor_state
)
1979 Editor_state
.cursor1
= {line
=1, pos
=1}
1980 Editor_state
.screen_top1
= {line
=1, pos
=1}
1981 Editor_state
.screen_bottom1
= {}
1982 edit
.draw(Editor_state
)
1983 -- search for a string
1984 edit
.run_after_keychord(Editor_state
, 'C-f')
1985 edit
.run_after_text_input(Editor_state
, 'd')
1986 edit
.run_after_keychord(Editor_state
, 'return')
1987 check_eq(Editor_state
.cursor1
.line
, 2, 'F - test_search/1/cursor:line')
1988 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_search/1/cursor:pos')
1990 Editor_state
.cursor1
= {line
=1, pos
=1}
1991 Editor_state
.screen_top1
= {line
=1, pos
=1}
1992 -- search for second occurrence
1993 edit
.run_after_keychord(Editor_state
, 'C-f')
1994 edit
.run_after_text_input(Editor_state
, 'de')
1995 edit
.run_after_keychord(Editor_state
, 'down')
1996 edit
.run_after_keychord(Editor_state
, 'return')
1997 check_eq(Editor_state
.cursor1
.line
, 4, 'F - test_search/2/cursor:line')
1998 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_search/2/cursor:pos')
2001 function test_search_upwards()
2002 io
.write('\ntest_search_upwards')
2003 App
.screen
.init
{width
=120, height
=60}
2004 Editor_state
= edit
.initialize_test_state()
2005 Editor_state
.lines
= load_array
{'abc abd'}
2006 Text
.redraw_all(Editor_state
)
2007 Editor_state
.cursor1
= {line
=1, pos
=2}
2008 Editor_state
.screen_top1
= {line
=1, pos
=1}
2009 Editor_state
.screen_bottom1
= {}
2010 edit
.draw(Editor_state
)
2011 -- search for a string
2012 edit
.run_after_keychord(Editor_state
, 'C-f')
2013 edit
.run_after_text_input(Editor_state
, 'a')
2014 -- search for previous occurrence
2015 edit
.run_after_keychord(Editor_state
, 'up')
2016 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_search_upwards/2/cursor:line')
2017 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_search_upwards/2/cursor:pos')
2020 function test_search_wrap()
2021 io
.write('\ntest_search_wrap')
2022 App
.screen
.init
{width
=120, height
=60}
2023 Editor_state
= edit
.initialize_test_state()
2024 Editor_state
.lines
= load_array
{'abc'}
2025 Text
.redraw_all(Editor_state
)
2026 Editor_state
.cursor1
= {line
=1, pos
=3}
2027 Editor_state
.screen_top1
= {line
=1, pos
=1}
2028 Editor_state
.screen_bottom1
= {}
2029 edit
.draw(Editor_state
)
2030 -- search for a string
2031 edit
.run_after_keychord(Editor_state
, 'C-f')
2032 edit
.run_after_text_input(Editor_state
, 'a')
2033 edit
.run_after_keychord(Editor_state
, 'return')
2035 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_search_wrap/1/cursor:line')
2036 check_eq(Editor_state
.cursor1
.pos
, 1, 'F - test_search_wrap/1/cursor:pos')
2039 function test_search_wrap_upwards()
2040 io
.write('\ntest_search_wrap_upwards')
2041 App
.screen
.init
{width
=120, height
=60}
2042 Editor_state
= edit
.initialize_test_state()
2043 Editor_state
.lines
= load_array
{'abc abd'}
2044 Text
.redraw_all(Editor_state
)
2045 Editor_state
.cursor1
= {line
=1, pos
=1}
2046 Editor_state
.screen_top1
= {line
=1, pos
=1}
2047 Editor_state
.screen_bottom1
= {}
2048 edit
.draw(Editor_state
)
2049 -- search upwards for a string
2050 edit
.run_after_keychord(Editor_state
, 'C-f')
2051 edit
.run_after_text_input(Editor_state
, 'a')
2052 edit
.run_after_keychord(Editor_state
, 'up')
2054 check_eq(Editor_state
.cursor1
.line
, 1, 'F - test_search_wrap_upwards/1/cursor:line')
2055 check_eq(Editor_state
.cursor1
.pos
, 5, 'F - test_search_wrap_upwards/1/cursor:pos')