about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2024-06-11 06:58:07 -0700
committerKartik K. Agaram <vc@akkartik.com>2024-06-11 07:02:46 -0700
commitf2299cb422d0fc07a1b01f0c31f88e9ae5ab168f (patch)
tree1216103a49bdba04dbcad0f35f14ee3128e51a9c
parent19615eade0106ad5a3a988b3f1f257367aceb7ec (diff)
downloadview.love-f2299cb422d0fc07a1b01f0c31f88e9ae5ab168f.tar.gz
stop caching screen_bottom1
I'm not sure this is very useful. I had an initial idea to stop using
screen_bottom1 in final_text_loc_on_screen, by starting from screen_top1
rather than screen_bottom1. But that changes the direction in which we
scan for the text line in situations where there is somehow no text on
screen (something that should never happen but I have zero confidence in
that).

Still, it doesn't seem like a bad thing to drastically reduce the
lifetime of some derived state.

Really what I need to do is throw this whole UX out and allow the cursor
to be on a drawing as a whole. So up arrow or left arrow below a drawing
would focus the whole drawing in a red border, and another up arrow and
left arrow would skip the drawing and continue upward. I think that
change to the UX will eliminate a whole class of special cases in the
code.
-rw-r--r--app.lua5
-rw-r--r--edit.lua8
-rw-r--r--search.lua6
-rw-r--r--select.lua3
-rw-r--r--source_edit.lua8
-rw-r--r--source_select.lua3
-rw-r--r--source_text.lua123
-rw-r--r--source_text_tests.lua76
-rw-r--r--text.lua138
-rw-r--r--text_tests.lua106
10 files changed, 173 insertions, 303 deletions
diff --git a/app.lua b/app.lua
index 627a438..5e61d47 100644
--- a/app.lua
+++ b/app.lua
@@ -130,6 +130,8 @@ function App.run_tests()
     end
   end
   table.sort(sorted_names)
+--?   App.initialize_for_test() -- debug: run a single test at a time like these 2 lines
+--?   test_pagedown_skips_drawings()
   for _,name in ipairs(sorted_names) do
     App.initialize_for_test()
 --?     print('=== '..name)
@@ -404,9 +406,10 @@ end
 -- prepend file/line/test
 function prepend_debug_info_to_test_failure(test_name, err)
   local err_without_line_number = err:gsub('^[^:]*:[^:]*: ', '')
-  local stack_trace = debug.traceback('', --[[stack frame]]5)
+  local stack_trace = debug.traceback('', --[[stack frame]]5)  -- most likely to be useful, but set to 0 for a complete stack trace
   local file_and_line_number = stack_trace:gsub('stack traceback:\n', ''):gsub(': .*', '')
   local full_error = file_and_line_number..':'..test_name..' -- '..err_without_line_number
+  -- uncomment this line for a complete stack trace
 --?   local full_error = file_and_line_number..':'..test_name..' -- '..err_without_line_number..'\t\t'..stack_trace:gsub('\n', '\n\t\t')
   table.insert(Test_errors, full_error)
 end
diff --git a/edit.lua b/edit.lua
index 42309df..5a2ab28 100644
--- a/edit.lua
+++ b/edit.lua
@@ -70,7 +70,6 @@ function edit.initialize_state(top, left, right, font, font_height, line_height)
     -- On lines that are drawings, pos will be nil.
     screen_top1 = {line=1, pos=1},  -- position of start of screen line at top of screen
     cursor1 = {line=1, pos=1},  -- position of cursor; must be on a text line
-    screen_bottom1 = {line=1, pos=1},  -- position of start of screen line at bottom of screen
 
     selection1 = {},
     -- some extra state to compute selection between mouse press and release
@@ -166,13 +165,11 @@ function edit.draw(State)
   State.cursor_x = nil
   State.cursor_y = nil
   local y = State.top
-  local screen_bottom1 = {line=nil, pos=nil}
 --?   print('== draw')
   for line_index = State.screen_top1.line,#State.lines do
     local line = State.lines[line_index]
 --?     print('draw:', y, line_index, line)
     if y + State.line_height > App.screen.height then break end
-    screen_bottom1.line = line_index
     if line.mode == 'text' then
 --?       print('text.draw', y, line_index)
       local startpos = 1
@@ -196,7 +193,7 @@ function edit.draw(State)
                      end,
         })
       end
-      y, screen_bottom1.pos = Text.draw(State, line_index, y, startpos)
+      y = Text.draw(State, line_index, y, startpos)
 --?       print('=> y', y)
     elseif line.mode == 'drawing' then
       y = y+Drawing_padding_top
@@ -206,7 +203,6 @@ function edit.draw(State)
       assert(false, ('unknown line mode %s'):format(line.mode))
     end
   end
-  State.screen_bottom1 = screen_bottom1
   if State.search_term then
     Text.draw_search_bar(State)
   end
@@ -361,7 +357,7 @@ function edit.mouse_wheel_move(State, dx,dy)
       Text.up(State)
     end
   elseif dy < 0 then
-    State.cursor1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
+    State.cursor1 = Text.screen_bottom1(State)
     edit.put_cursor_on_next_text_line(State)
     for i=1,math.floor(-dy) do
       Text.down(State)
diff --git a/search.lua b/search.lua
index 54bab14..d3a5fea 100644
--- a/search.lua
+++ b/search.lua
@@ -62,7 +62,8 @@ function Text.search_next(State)
     State.screen_top1.line = State.search_backup.screen_top.line
     State.screen_top1.pos = State.search_backup.screen_top.pos
   end
-  if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
+  local screen_bottom1 = Text.screen_bottom1(State)
+  if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(screen_bottom1, State.cursor1) then
     State.screen_top1.line = State.cursor1.line
     local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
     State.screen_top1.pos = pos
@@ -115,7 +116,8 @@ function Text.search_previous(State)
     State.screen_top1.line = State.search_backup.screen_top.line
     State.screen_top1.pos = State.search_backup.screen_top.pos
   end
-  if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
+  local screen_bottom1 = Text.screen_bottom1(State)
+  if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(screen_bottom1, State.cursor1) then
     State.screen_top1.line = State.cursor1.line
     local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
     State.screen_top1.pos = pos
diff --git a/select.lua b/select.lua
index 6e21c7b..78d18db 100644
--- a/select.lua
+++ b/select.lua
@@ -79,7 +79,8 @@ function Text.mouse_pos(State)
       end
     end
   end
-  return State.screen_bottom1.line, Text.pos_at_end_of_screen_line(State, State.screen_bottom1)
+  local screen_bottom1 = Text.screen_bottom1(State)
+  return screen_bottom1.line, Text.pos_at_end_of_screen_line(State, screen_bottom1)
 end
 
 function Text.cut_selection(State)
diff --git a/source_edit.lua b/source_edit.lua
index 53b50eb..64c8980 100644
--- a/source_edit.lua
+++ b/source_edit.lua
@@ -72,7 +72,6 @@ function edit.initialize_state(top, left, right, font, font_height, line_height)
     -- On lines that are drawings, pos will be nil.
     screen_top1 = {line=1, pos=1},  -- position of start of screen line at top of screen
     cursor1 = {line=1, pos=1},  -- position of cursor; must be on a text line
-    screen_bottom1 = {line=1, pos=1},  -- position of start of screen line at bottom of screen
 
     selection1 = {},
     -- some extra state to compute selection between mouse press and release
@@ -167,13 +166,11 @@ function edit.draw(State, hide_cursor, show_line_numbers)
   State.cursor_x = nil
   State.cursor_y = nil
   local y = State.top
-  local screen_bottom1 = {line=nil, pos=nil}
 --?   print('== draw')
   for line_index = State.screen_top1.line,#State.lines do
     local line = State.lines[line_index]
 --?     print('draw:', y, line_index, line)
     if y + State.line_height > App.screen.height then break end
-    screen_bottom1.line = line_index
     if line.mode == 'text' then
 --?       print('text.draw', y, line_index)
       local startpos = 1
@@ -201,7 +198,7 @@ function edit.draw(State, hide_cursor, show_line_numbers)
                      end,
         })
       end
-      y, screen_bottom1.pos = Text.draw(State, line_index, y, startpos, hide_cursor, show_line_numbers)
+      y = Text.draw(State, line_index, y, startpos, hide_cursor, show_line_numbers)
 --?       print('=> y', y)
     elseif line.mode == 'drawing' then
       y = y+Drawing_padding_top
@@ -211,7 +208,6 @@ function edit.draw(State, hide_cursor, show_line_numbers)
       assert(false, ('unknown line mode %s'):format(line.mode))
     end
   end
-  State.screen_bottom1 = screen_bottom1
   if State.search_term then
     Text.draw_search_bar(State)
   end
@@ -365,7 +361,7 @@ function edit.mouse_wheel_move(State, dx,dy)
       Text.up(State)
     end
   elseif dy < 0 then
-    State.cursor1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
+    State.cursor1 = Text.screen_bottom1(State)
     edit.put_cursor_on_next_text_line(State)
     for i=1,math.floor(-dy) do
       Text.down(State)
diff --git a/source_select.lua b/source_select.lua
index 6e21c7b..78d18db 100644
--- a/source_select.lua
+++ b/source_select.lua
@@ -79,7 +79,8 @@ function Text.mouse_pos(State)
       end
     end
   end
-  return State.screen_bottom1.line, Text.pos_at_end_of_screen_line(State, State.screen_bottom1)
+  local screen_bottom1 = Text.screen_bottom1(State)
+  return screen_bottom1.line, Text.pos_at_end_of_screen_line(State, screen_bottom1)
 end
 
 function Text.cut_selection(State)
diff --git a/source_text.lua b/source_text.lua
index 0fced93..0fb1147 100644
--- a/source_text.lua
+++ b/source_text.lua
@@ -2,14 +2,13 @@
 Text = {}
 
 -- draw a line starting from startpos to screen at y between State.left and State.right
--- return y for the next line, and position of start of final screen line drawn
+-- return y for the next line
 function Text.draw(State, line_index, y, startpos, hide_cursor, show_line_numbers)
   local line = State.lines[line_index]
   local line_cache = State.line_cache[line_index]
   line_cache.starty = y
   line_cache.startpos = startpos
   -- wrap long lines
-  local final_screen_line_starting_pos = startpos  -- track value to return
   Text.populate_screen_line_starting_pos(State, line_index)
   Text.populate_link_offsets(State, line_index)
   if show_line_numbers then
@@ -24,7 +23,6 @@ function Text.draw(State, line_index, y, startpos, hide_cursor, show_line_number
       -- render nothing
 --?       print('skipping', screen_line)
     else
-      final_screen_line_starting_pos = pos
       local screen_line = Text.screen_line(line, line_cache, i)
 --?       print('text.draw:', screen_line, 'at', line_index,pos, 'after', x,y)
       local frag_len = utf8.len(screen_line)
@@ -84,7 +82,7 @@ function Text.draw(State, line_index, y, startpos, hide_cursor, show_line_number
       end
     end
   end
-  return y, final_screen_line_starting_pos
+  return y
 end
 
 function Text.screen_line(line, line_cache, i)
@@ -208,7 +206,7 @@ function Text.text_input(State, t)
     end
   end
   local before = snapshot(State, State.cursor1.line)
---?   print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
   Text.insert_at_cursor(State, t)
   if State.cursor_y > App.screen.height - State.line_height then
     Text.populate_screen_line_starting_pos(State, State.cursor1.line)
@@ -241,12 +239,12 @@ function Text.keychord_press(State, chord)
     record_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor1.line)})
   elseif chord == 'tab' then
     local before = snapshot(State, State.cursor1.line)
---?     print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?     print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
     Text.insert_at_cursor(State, '\t')
     if State.cursor_y > App.screen.height - State.line_height then
       Text.populate_screen_line_starting_pos(State, State.cursor1.line)
       Text.snap_cursor_to_bottom_of_screen(State, State.left, State.right)
---?       print('=>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?       print('=>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
     end
     schedule_save(State)
     record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
@@ -427,37 +425,54 @@ function Text.insert_return(State)
 end
 
 function Text.pageup(State)
---?   print('pageup')
+  State.screen_top1 = Text.previous_screen_top1(State)
+  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
+  Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
+end
+
+function Text.previous_screen_top1(State)
   -- duplicate some logic from love.draw
-  local top2 = Text.to2(State, State.screen_top1)
---?   print(App.screen.height)
+  -- does not modify State (except to populate line_cache)
+  local loc2 = Text.to2(State, State.screen_top1)
   local y = App.screen.height - State.line_height
   while y >= State.top do
---?     print(y, top2.line, top2.screen_line, top2.screen_pos)
-    if State.screen_top1.line == 1 and State.screen_top1.pos == 1 then break end
-    if State.lines[State.screen_top1.line].mode == 'text' then
+    if loc2.line == 1 and loc2.screen_line == 1 and loc2.screen_pos == 1 then break end
+    if State.lines[loc2.line].mode == 'text' then
       y = y - State.line_height
-    elseif State.lines[State.screen_top1.line].mode == 'drawing' then
-      y = y - Drawing_padding_height - Drawing.pixels(State.lines[State.screen_top1.line].h, State.width)
+    elseif State.lines[loc2.line].mode == 'drawing' then
+      y = y - Drawing_padding_height - Drawing.pixels(State.lines[loc2.line].h, State.width)
     end
-    top2 = Text.previous_screen_line(State, top2)
+    loc2 = Text.previous_screen_line(State, loc2)
   end
-  State.screen_top1 = Text.to1(State, top2)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
-  Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
---?   print(State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
---?   print('pageup end')
+  return Text.to1(State, loc2)
 end
 
 function Text.pagedown(State)
---?   print('pagedown')
-  State.screen_top1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
---?   print('setting top to', State.screen_top1.line, State.screen_top1.pos)
+  State.screen_top1 = Text.screen_bottom1(State)
   State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
---?   print('top now', State.screen_top1.line)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
---?   print('pagedown end')
+end
+
+-- return the location of the start of the bottom-most line on screen
+function Text.screen_bottom1(State)
+  -- duplicate some logic from love.draw
+  -- does not modify State (except to populate line_cache)
+  local loc2 = Text.to2(State, State.screen_top1)
+  local y = State.top
+  while true do
+    if State.lines[loc2.line].mode == 'text' then
+      y = y + State.line_height
+    elseif State.lines[loc2.line].mode == 'drawing' then
+      y = y + Drawing_padding_height + Drawing.pixels(State.lines[loc2.line].h, State.width)
+    end
+    if y + State.line_height > App.screen.height then break end
+    local next_loc2 = Text.next_screen_line(State, loc2)
+    if Text.eq2(next_loc2, loc2) then break end
+    loc2 = next_loc2
+  end
+  return Text.to1(State, loc2)
 end
 
 function Text.up(State)
@@ -505,7 +520,7 @@ end
 
 function Text.down(State)
   assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
---?   print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
   assert(State.cursor1.pos, 'cursor has no pos')
   if Text.cursor_at_final_screen_line(State) then
     -- line is done, skip to next text line
@@ -522,7 +537,9 @@ function Text.down(State)
         break
       end
     end
-    if State.cursor1.line > State.screen_bottom1.line then
+    local screen_bottom1 = Text.screen_bottom1(State)
+--?   print('down 2', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, screen_bottom1.line, screen_bottom1.pos)
+    if State.cursor1.line > screen_bottom1.line then
 --?       print('screen top before:', State.screen_top1.line, State.screen_top1.pos)
 --?       print('scroll up preserving cursor')
       Text.snap_cursor_to_bottom_of_screen(State)
@@ -530,7 +547,8 @@ function Text.down(State)
     end
   else
     -- move down one screen line in current line
-    local scroll_down = Text.le1(State.screen_bottom1, State.cursor1)
+    local screen_bottom1 = Text.screen_bottom1(State)
+    local scroll_down = Text.le1(screen_bottom1, State.cursor1)
 --?     print('cursor is NOT at final screen line of its line')
     local screen_line_starting_pos, screen_line_index = Text.pos_at_start_of_screen_line(State, State.cursor1)
     Text.populate_screen_line_starting_pos(State, State.cursor1.line)
@@ -546,7 +564,7 @@ function Text.down(State)
 --?       print('screen top after:', State.screen_top1.line, State.screen_top1.pos)
     end
   end
---?   print('=>', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('=>', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
 end
 
 function Text.start_of_line(State)
@@ -698,13 +716,14 @@ function Text.pos_at_end_of_screen_line(State, loc1)
 end
 
 function Text.final_text_loc_on_screen(State)
-  if State.lines[State.screen_bottom1.line].mode == 'text' then
+  local screen_bottom1 = Text.screen_bottom1(State)
+  if State.lines[screen_bottom1.line].mode == 'text' then
     return {
-      line=State.screen_bottom1.line,
-      pos=Text.pos_at_end_of_screen_line(State, State.screen_bottom1),
+      line=screen_bottom1.line,
+      pos=Text.pos_at_end_of_screen_line(State, screen_bottom1),
     }
   end
-  local loc2 = Text.to2(State, State.screen_bottom1)
+  local loc2 = Text.to2(State, screen_bottom1)
   while true do
     if State.lines[loc2.line].mode == 'text' then break end
     assert(loc2.line > 1 or loc2.screen_line > 1 and loc2.screen_pos > 1)  -- elsewhere we're making sure there's always at least one text line on screen
@@ -755,7 +774,7 @@ function Text.snap_cursor_to_bottom_of_screen(State)
 --?   print('to2: =>', top2.line, top2.screen_line, top2.screen_pos)
   -- slide to start of screen line
   top2.screen_pos = 1  -- start of screen line
---?   print('snap', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('snap', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
 --?   print('cursor pos '..tostring(State.cursor1.pos)..' is on the #'..tostring(top2.screen_line)..' screen line down')
   local y = App.screen.height - State.line_height
   -- duplicate some logic from love.draw
@@ -785,7 +804,7 @@ function Text.snap_cursor_to_bottom_of_screen(State)
 --?   print('top2 finally:', top2.line, top2.screen_line, top2.screen_pos)
   State.screen_top1 = Text.to1(State, top2)
 --?   print('top1 finally:', State.screen_top1.line, State.screen_top1.pos)
---?   print('snap =>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('snap =>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
 
@@ -990,6 +1009,10 @@ function Text.le1(a, b)
   return a.pos <= b.pos
 end
 
+function Text.eq2(a, b)
+  return a.line == b.line and a.screen_line == b.screen_line and a.screen_pos == b.screen_pos
+end
+
 function Text.offset(s, pos1)
   if pos1 == 1 then return 1 end
   local result = utf8.offset(s, pos1)
@@ -1013,6 +1036,22 @@ function Text.previous_screen_line(State, loc2)
   end
 end
 
+function Text.next_screen_line(State, loc2)
+  if State.lines[loc2.line].mode == 'drawing' then
+    return {line=loc2.line+1, screen_line=1, screen_pos=1}
+  end
+  Text.populate_screen_line_starting_pos(State, loc2.line)
+  if loc2.screen_line >= #State.line_cache[loc2.line].screen_line_starting_pos then
+    if loc2.line < #State.lines then
+      return {line=loc2.line+1, screen_line=1, screen_pos=1}
+    else
+      return loc2
+    end
+  else
+    return {line=loc2.line, screen_line=loc2.screen_line+1, screen_pos=1}
+  end
+end
+
 -- resize helper
 function Text.tweak_screen_top_and_cursor(State)
   if State.screen_top1.pos == 1 then return end
@@ -1036,15 +1075,16 @@ function Text.tweak_screen_top_and_cursor(State)
     end
   end
   -- make sure cursor is on screen
+  local screen_bottom1 = Text.screen_bottom1(State)
   if Text.lt1(State.cursor1, State.screen_top1) then
     State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
-  elseif State.cursor1.line >= State.screen_bottom1.line then
+  elseif State.cursor1.line >= screen_bottom1.line then
 --?     print('too low')
     if Text.cursor_out_of_screen(State) then
 --?       print('tweak')
       State.cursor1 = {
-          line=State.screen_bottom1.line,
-          pos=Text.to_pos_on_line(State, State.screen_bottom1.line, State.right-5, App.screen.height-5),
+          line=screen_bottom1.line,
+          pos=Text.to_pos_on_line(State, screen_bottom1.line, State.right-5, App.screen.height-5),
       }
     end
   end
@@ -1054,11 +1094,6 @@ end
 function Text.cursor_out_of_screen(State)
   edit.draw(State)
   return State.cursor_y == nil
-  -- this approach is cheaper and almost works, except on the final screen
-  -- where file ends above bottom of screen
---?   local botpos = Text.pos_at_start_of_screen_line(State, State.cursor1)
---?   local botline1 = {line=State.cursor1.line, pos=botpos}
---?   return Text.lt1(State.screen_bottom1, botline1)
 end
 
 function Text.redraw_all(State)
diff --git a/source_text_tests.lua b/source_text_tests.lua
index b8f29d1..c17842a 100644
--- a/source_text_tests.lua
+++ b/source_text_tests.lua
@@ -75,7 +75,6 @@ function test_press_ctrl()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.run_after_keychord(Editor_state, 'C-m', 'm')
 end
 
@@ -255,7 +254,6 @@ function test_click_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -274,7 +272,6 @@ function test_click_to_left_of_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=3}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click to the left of the line
   edit.draw(Editor_state)
@@ -294,7 +291,6 @@ function test_click_takes_margins_into_account()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click on the other line
   edit.draw(Editor_state)
@@ -313,7 +309,6 @@ function test_click_on_empty_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click on the empty line
   edit.draw(Editor_state)
@@ -332,7 +327,6 @@ function test_click_below_all_lines()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click below first line
   edit.draw(Editor_state)
@@ -350,7 +344,6 @@ function test_draw_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'screen:1')
@@ -367,7 +360,6 @@ function test_draw_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'screen:1')
@@ -384,7 +376,6 @@ function test_draw_word_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc ', 'screen:1')
@@ -402,7 +393,6 @@ function test_click_on_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=20}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- click on the other line
   edit.draw(Editor_state)
   edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -421,7 +411,6 @@ function test_click_on_wrapping_line_takes_margins_into_account()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=20}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- click on the other line
   edit.draw(Editor_state)
   edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -439,7 +428,6 @@ function test_draw_text_wrapping_within_word()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abcd ', 'screen:1')
@@ -457,7 +445,6 @@ function test_draw_wrapping_text_containing_non_ascii()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'mad', 'screen:1')
@@ -476,7 +463,6 @@ function test_click_past_end_of_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -499,7 +485,6 @@ function test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=8}
   Editor_state.screen_top1 = {line=1, pos=7}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, "I'm ad", 'baseline/screen:2')
@@ -520,7 +505,6 @@ function test_click_past_end_of_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -544,7 +528,6 @@ function test_click_past_end_of_wrapping_line_containing_non_ascii()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -569,7 +552,6 @@ function test_click_past_end_of_word_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'the quick brown fox ', 'baseline/screen:1')
@@ -588,7 +570,6 @@ function test_select_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- select a letter
   App.fake_key_press('lshift')
@@ -611,7 +592,6 @@ function test_cursor_movement_without_shift_resets_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press an arrow key without shift
   edit.run_after_keychord(Editor_state, 'right',  'right')
@@ -629,7 +609,6 @@ function test_edit_deletes_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press a key
   edit.run_after_text_input(Editor_state, 'x')
@@ -646,7 +625,6 @@ function test_edit_with_shift_key_deletes_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- mimic precise keypresses for a capital letter
   App.fake_key_press('lshift')
@@ -668,7 +646,6 @@ function test_copy_does_not_reset_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- copy selection
   edit.run_after_keychord(Editor_state, 'C-c', 'c')
@@ -686,7 +663,6 @@ function test_cut()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press a key
   edit.run_after_keychord(Editor_state, 'C-x', 'x')
@@ -704,7 +680,6 @@ function test_paste_replaces_selection()
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.selection1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- set clipboard
   App.clipboard = 'xyz'
@@ -723,7 +698,6 @@ function test_deleting_selection_may_scroll()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=2}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -747,7 +721,6 @@ function test_edit_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   edit.run_after_text_input(Editor_state, 'g')
   local y = Editor_state.top
@@ -766,7 +739,6 @@ function test_insert_newline()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -795,7 +767,6 @@ function test_insert_newline_at_start_of_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- hitting the enter key splits the line
   edit.run_after_keychord(Editor_state, 'return', 'return')
   check_eq(Editor_state.cursor1.line, 2, 'cursor:line')
@@ -812,7 +783,6 @@ function test_insert_from_clipboard()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -841,7 +811,6 @@ function test_select_text_using_mouse()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- press and hold on first location
@@ -861,7 +830,6 @@ function test_select_text_using_mouse_starting_above_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- press mouse above first line of text
@@ -879,7 +847,6 @@ function test_select_text_using_mouse_starting_above_text_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=2, pos=3}
-  Editor_state.screen_bottom1 = {}
   -- press mouse above first line of text
   edit.draw(Editor_state)
   edit.run_after_mouse_press(Editor_state, Editor_state.left+8,5, 1)
@@ -902,7 +869,6 @@ function test_select_text_using_mouse_starting_below_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ab', 'baseline:screen:1')
@@ -923,7 +889,6 @@ function test_select_text_using_mouse_and_shift()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- click on first location
@@ -948,7 +913,6 @@ function test_select_text_repeatedly_using_mouse_and_shift()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- click on first location
@@ -978,7 +942,6 @@ function test_select_all_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- select all
   App.fake_key_press('lctrl')
@@ -1000,7 +963,6 @@ function test_cut_without_selection()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)
   -- try to cut without selecting text
@@ -1016,7 +978,6 @@ function test_pagedown()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the first two lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1046,7 +1007,6 @@ function test_pagedown_skips_drawings()
   check_eq(Editor_state.lines[2].mode, 'drawing', 'baseline/lines')
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   local drawing_height = Drawing_padding_height + drawing_width/2  -- default
   -- initially the screen displays the first line and the drawing
   -- 15px margin + 15px line1 + 10px margin + 25px drawing + 10px margin = 75px < screen height 80px
@@ -1070,7 +1030,6 @@ function test_pagedown_can_start_from_middle_of_long_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc ', 'baseline/screen:1')
@@ -1105,7 +1064,6 @@ function test_pagedown_never_moves_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=9}
   Editor_state.screen_top1 = {line=1, pos=9}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- pagedown makes no change
   edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')
@@ -1120,7 +1078,6 @@ function test_down_arrow_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the first three lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1153,7 +1110,6 @@ function test_down_arrow_skips_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1175,7 +1131,6 @@ function test_down_arrow_scrolls_down_by_one_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1203,7 +1158,6 @@ function test_down_arrow_scrolls_down_by_one_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1232,7 +1186,6 @@ function test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1260,7 +1213,6 @@ function test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1294,7 +1246,6 @@ function test_up_arrow_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1326,7 +1277,6 @@ function test_up_arrow_skips_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1348,7 +1298,6 @@ function test_up_arrow_scrolls_up_by_one_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1376,7 +1325,6 @@ function test_up_arrow_scrolls_up_by_one_line_skipping_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=3, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1398,7 +1346,6 @@ function test_up_arrow_scrolls_up_by_one_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=6}
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -1426,7 +1373,6 @@ function test_up_arrow_scrolls_up_to_final_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ghi', 'baseline/screen:1')
@@ -1456,7 +1402,6 @@ function test_up_arrow_scrolls_up_to_empty_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1483,7 +1428,6 @@ function test_pageup()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the last two lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1508,7 +1452,6 @@ function test_pageup_scrolls_up_by_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ghi', 'baseline/screen:1')
@@ -1537,7 +1480,6 @@ function test_pageup_scrolls_up_from_middle_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=2, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:2')
@@ -1564,7 +1506,6 @@ function test_enter_on_bottom_line_scrolls_down()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1593,7 +1534,6 @@ function test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=4, pos=2}
   Editor_state.screen_top1 = {line=4, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -1616,7 +1556,6 @@ function test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bot
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- after hitting the inserting_text key the screen does not scroll down
   edit.run_after_text_input(Editor_state, 'a')
@@ -1635,7 +1574,6 @@ function test_typing_on_bottom_line_scrolls_down()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1665,7 +1603,6 @@ function test_left_arrow_scrolls_up_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at top of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1694,7 +1631,6 @@ function test_right_arrow_scrolls_down_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at bottom right of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1724,7 +1660,6 @@ function test_home_scrolls_up_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at top of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1753,7 +1688,6 @@ function test_end_scrolls_down_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at bottom right of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1784,7 +1718,6 @@ function test_position_cursor_on_recently_edited_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=25}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc def ghi ', 'baseline1/screen:1')
@@ -1818,7 +1751,6 @@ function test_backspace_can_scroll_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1846,7 +1778,6 @@ function test_backspace_can_scroll_up_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=5}
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -1981,7 +1912,6 @@ function test_undo_insert_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- insert a character
   edit.draw(Editor_state)
   edit.run_after_text_input(Editor_state, 'g')
@@ -2016,7 +1946,6 @@ function test_undo_delete_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- delete a character
   edit.run_after_keychord(Editor_state, 'backspace', 'backspace')
   check_eq(Editor_state.cursor1.line, 2, 'baseline/cursor:line')
@@ -2055,7 +1984,6 @@ function test_undo_restores_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- delete selected text
   edit.run_after_text_input(Editor_state, 'x')
@@ -2076,7 +2004,6 @@ function test_search()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2103,7 +2030,6 @@ function test_search_upwards()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2121,7 +2047,6 @@ function test_search_wrap()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2139,7 +2064,6 @@ function test_search_wrap_upwards()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search upwards for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
diff --git a/text.lua b/text.lua
index d9e7653..f203950 100644
--- a/text.lua
+++ b/text.lua
@@ -2,7 +2,7 @@
 Text = {}
 
 -- draw a line starting from startpos to screen at y between State.left and State.right
--- return y for the next line, and position of start of final screen line drawn
+-- return y for the next line
 function Text.draw(State, line_index, y, startpos)
 --?   print('text.draw', line_index, y)
   local line = State.lines[line_index]
@@ -10,7 +10,6 @@ function Text.draw(State, line_index, y, startpos)
   line_cache.starty = y
   line_cache.startpos = startpos
   -- wrap long lines
-  local final_screen_line_starting_pos = startpos  -- track value to return
   Text.populate_screen_line_starting_pos(State, line_index)
   assert(#line_cache.screen_line_starting_pos >= 1, 'line cache missing screen line info')
   for i=1,#line_cache.screen_line_starting_pos do
@@ -18,7 +17,6 @@ function Text.draw(State, line_index, y, startpos)
     if pos < startpos then
       -- render nothing
     else
-      final_screen_line_starting_pos = pos
       local screen_line = Text.screen_line(line, line_cache, i)
 --?       print('text.draw:', screen_line, 'at', line_index,pos, 'after', x,y)
       local frag_len = utf8.len(screen_line)
@@ -59,7 +57,7 @@ function Text.draw(State, line_index, y, startpos)
       end
     end
   end
-  return y, final_screen_line_starting_pos
+  return y
 end
 
 function Text.screen_line(line, line_cache, i)
@@ -134,7 +132,7 @@ function Text.text_input(State, t)
     end
   end
   local before = snapshot(State, State.cursor1.line)
---?   print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
   Text.insert_at_cursor(State, t)
   if State.cursor_y > App.screen.height - State.line_height then
     Text.populate_screen_line_starting_pos(State, State.cursor1.line)
@@ -167,12 +165,12 @@ function Text.keychord_press(State, chord)
     record_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor1.line)})
   elseif chord == 'tab' then
     local before = snapshot(State, State.cursor1.line)
---?     print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?     print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
     Text.insert_at_cursor(State, '\t')
     if State.cursor_y > App.screen.height - State.line_height then
       Text.populate_screen_line_starting_pos(State, State.cursor1.line)
       Text.snap_cursor_to_bottom_of_screen(State, State.left, State.right)
---?       print('=>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?       print('=>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
     end
     schedule_save(State)
     record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
@@ -353,49 +351,54 @@ function Text.insert_return(State)
 end
 
 function Text.pageup(State)
---?   print('pageup')
+  State.screen_top1 = Text.previous_screen_top1(State)
+  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
+  Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
+end
+
+function Text.previous_screen_top1(State)
   -- duplicate some logic from love.draw
-  local top2 = Text.to2(State, State.screen_top1)
---?   print(App.screen.height)
+  -- does not modify State (except to populate line_cache)
+  local loc2 = Text.to2(State, State.screen_top1)
   local y = App.screen.height - State.line_height
   while y >= State.top do
---?     print(y, top2.line, top2.screen_line, top2.screen_pos)
-    if State.screen_top1.line == 1 and State.screen_top1.pos == 1 then break end
-    if State.lines[State.screen_top1.line].mode == 'text' then
+    if loc2.line == 1 and loc2.screen_line == 1 and loc2.screen_pos == 1 then break end
+    if State.lines[loc2.line].mode == 'text' then
       y = y - State.line_height
-    elseif State.lines[State.screen_top1.line].mode == 'drawing' then
-      y = y - Drawing_padding_height - Drawing.pixels(State.lines[State.screen_top1.line].h, State.width)
+    elseif State.lines[loc2.line].mode == 'drawing' then
+      y = y - Drawing_padding_height - Drawing.pixels(State.lines[loc2.line].h, State.width)
     end
-    top2 = Text.previous_screen_line(State, top2)
+    loc2 = Text.previous_screen_line(State, loc2)
   end
-  State.screen_top1 = Text.to1(State, top2)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
-  Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
---?   print(State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
---?   print('pageup end')
+  return Text.to1(State, loc2)
 end
 
 function Text.pagedown(State)
---?   print('pagedown')
-  -- If a line/paragraph gets to a page boundary, I often want to scroll
-  -- before I get to the bottom.
-  -- However, only do this if it makes forward progress.
-  local bot2 = Text.to2(State, State.screen_bottom1)
-  if bot2.screen_line > 1 then
-    bot2.screen_line = math.max(bot2.screen_line-10, 1)
-  end
-  local new_top1 = Text.to1(State, bot2)
-  if Text.lt1(State.screen_top1, new_top1) then
-    State.screen_top1 = new_top1
-  else
-    State.screen_top1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
-  end
---?   print('setting top to', State.screen_top1.line, State.screen_top1.pos)
+  State.screen_top1 = Text.screen_bottom1(State)
   State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
---?   print('top now', State.screen_top1.line)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
---?   print('pagedown end')
+end
+
+-- return the location of the start of the bottom-most line on screen
+function Text.screen_bottom1(State)
+  -- duplicate some logic from love.draw
+  -- does not modify State (except to populate line_cache)
+  local loc2 = Text.to2(State, State.screen_top1)
+  local y = State.top
+  while true do
+    if State.lines[loc2.line].mode == 'text' then
+      y = y + State.line_height
+    elseif State.lines[loc2.line].mode == 'drawing' then
+      y = y + Drawing_padding_height + Drawing.pixels(State.lines[loc2.line].h, State.width)
+    end
+    if y + State.line_height > App.screen.height then break end
+    local next_loc2 = Text.next_screen_line(State, loc2)
+    if Text.eq2(next_loc2, loc2) then break end
+    loc2 = next_loc2
+  end
+  return Text.to1(State, loc2)
 end
 
 function Text.up(State)
@@ -443,7 +446,7 @@ end
 
 function Text.down(State)
   assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
---?   print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
   assert(State.cursor1.pos, 'cursor has no pos')
   if Text.cursor_at_final_screen_line(State) then
     -- line is done, skip to next text line
@@ -460,7 +463,9 @@ function Text.down(State)
         break
       end
     end
-    if State.cursor1.line > State.screen_bottom1.line then
+    local screen_bottom1 = Text.screen_bottom1(State)
+--?   print('down 2', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, screen_bottom1.line, screen_bottom1.pos)
+    if State.cursor1.line > screen_bottom1.line then
 --?       print('screen top before:', State.screen_top1.line, State.screen_top1.pos)
 --?       print('scroll up preserving cursor')
       Text.snap_cursor_to_bottom_of_screen(State)
@@ -468,7 +473,8 @@ function Text.down(State)
     end
   else
     -- move down one screen line in current line
-    local scroll_down = Text.le1(State.screen_bottom1, State.cursor1)
+    local screen_bottom1 = Text.screen_bottom1(State)
+    local scroll_down = Text.le1(screen_bottom1, State.cursor1)
 --?     print('cursor is NOT at final screen line of its line')
     local screen_line_starting_pos, screen_line_index = Text.pos_at_start_of_screen_line(State, State.cursor1)
     Text.populate_screen_line_starting_pos(State, State.cursor1.line)
@@ -484,7 +490,7 @@ function Text.down(State)
 --?       print('screen top after:', State.screen_top1.line, State.screen_top1.pos)
     end
   end
---?   print('=>', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('=>', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
 end
 
 function Text.start_of_line(State)
@@ -636,13 +642,14 @@ function Text.pos_at_end_of_screen_line(State, loc1)
 end
 
 function Text.final_text_loc_on_screen(State)
-  if State.lines[State.screen_bottom1.line].mode == 'text' then
+  local screen_bottom1 = Text.screen_bottom1(State)
+  if State.lines[screen_bottom1.line].mode == 'text' then
     return {
-      line=State.screen_bottom1.line,
-      pos=Text.pos_at_end_of_screen_line(State, State.screen_bottom1),
+      line=screen_bottom1.line,
+      pos=Text.pos_at_end_of_screen_line(State, screen_bottom1),
     }
   end
-  local loc2 = Text.to2(State, State.screen_bottom1)
+  local loc2 = Text.to2(State, screen_bottom1)
   while true do
     if State.lines[loc2.line].mode == 'text' then break end
     assert(loc2.line > 1 or loc2.screen_line > 1 and loc2.screen_pos > 1)  -- elsewhere we're making sure there's always at least one text line on screen
@@ -693,7 +700,7 @@ function Text.snap_cursor_to_bottom_of_screen(State)
 --?   print('to2: =>', top2.line, top2.screen_line, top2.screen_pos)
   -- slide to start of screen line
   top2.screen_pos = 1  -- start of screen line
---?   print('snap', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('snap', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
 --?   print('cursor pos '..tostring(State.cursor1.pos)..' is on the #'..tostring(top2.screen_line)..' screen line down')
   local y = App.screen.height - State.line_height
   -- duplicate some logic from love.draw
@@ -723,7 +730,7 @@ function Text.snap_cursor_to_bottom_of_screen(State)
 --?   print('top2 finally:', top2.line, top2.screen_line, top2.screen_pos)
   State.screen_top1 = Text.to1(State, top2)
 --?   print('top1 finally:', State.screen_top1.line, State.screen_top1.pos)
---?   print('snap =>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
+--?   print('snap =>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
 
@@ -928,6 +935,10 @@ function Text.le1(a, b)
   return a.pos <= b.pos
 end
 
+function Text.eq2(a, b)
+  return a.line == b.line and a.screen_line == b.screen_line and a.screen_pos == b.screen_pos
+end
+
 function Text.offset(s, pos1)
   if pos1 == 1 then return 1 end
   local result = utf8.offset(s, pos1)
@@ -951,6 +962,22 @@ function Text.previous_screen_line(State, loc2)
   end
 end
 
+function Text.next_screen_line(State, loc2)
+  if State.lines[loc2.line].mode == 'drawing' then
+    return {line=loc2.line+1, screen_line=1, screen_pos=1}
+  end
+  Text.populate_screen_line_starting_pos(State, loc2.line)
+  if loc2.screen_line >= #State.line_cache[loc2.line].screen_line_starting_pos then
+    if loc2.line < #State.lines then
+      return {line=loc2.line+1, screen_line=1, screen_pos=1}
+    else
+      return loc2
+    end
+  else
+    return {line=loc2.line, screen_line=loc2.screen_line+1, screen_pos=1}
+  end
+end
+
 -- resize helper
 function Text.tweak_screen_top_and_cursor(State)
   if State.screen_top1.pos == 1 then return end
@@ -974,16 +1001,12 @@ function Text.tweak_screen_top_and_cursor(State)
     end
   end
   -- make sure cursor is on screen
+  local screen_bottom1 = Text.screen_bottom1(State)
   if Text.lt1(State.cursor1, State.screen_top1) then
     State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
-  elseif State.cursor1.line >= State.screen_bottom1.line then
---?     print('too low')
+  elseif State.cursor1.line >= screen_bottom1.line then
     if Text.cursor_out_of_screen(State) then
---?       print('tweak')
-      State.cursor1 = {
-          line=State.screen_bottom1.line,
-          pos=Text.to_pos_on_line(State, State.screen_bottom1.line, State.right-5, App.screen.height-5),
-      }
+      State.cursor1 = Text.final_text_loc_on_screen(State)
     end
   end
 end
@@ -992,11 +1015,6 @@ end
 function Text.cursor_out_of_screen(State)
   edit.draw(State)
   return State.cursor_y == nil
-  -- this approach is cheaper and almost works, except on the final screen
-  -- where file ends above bottom of screen
---?   local botpos = Text.pos_at_start_of_screen_line(State, State.cursor1)
---?   local botline1 = {line=State.cursor1.line, pos=botpos}
---?   return Text.lt1(State.screen_bottom1, botline1)
 end
 
 function Text.redraw_all(State)
diff --git a/text_tests.lua b/text_tests.lua
index 44cdafc..40320b1 100644
--- a/text_tests.lua
+++ b/text_tests.lua
@@ -75,7 +75,6 @@ function test_press_ctrl()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.run_after_keychord(Editor_state, 'C-m', 'm')
 end
 
@@ -255,7 +254,6 @@ function test_click_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -274,7 +272,6 @@ function test_click_to_left_of_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=3}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click to the left of the line
   edit.draw(Editor_state)
@@ -294,7 +291,6 @@ function test_click_takes_margins_into_account()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click on the other line
   edit.draw(Editor_state)
@@ -313,7 +309,6 @@ function test_click_on_empty_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click on the empty line
   edit.draw(Editor_state)
@@ -332,7 +327,6 @@ function test_click_below_all_lines()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   -- click below first line
   edit.draw(Editor_state)
@@ -350,7 +344,6 @@ function test_draw_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'screen:1')
@@ -367,7 +360,6 @@ function test_draw_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'screen:1')
@@ -384,7 +376,6 @@ function test_draw_word_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc ', 'screen:1')
@@ -402,7 +393,6 @@ function test_click_on_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=20}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- click on the other line
   edit.draw(Editor_state)
   edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -421,7 +411,6 @@ function test_click_on_wrapping_line_takes_margins_into_account()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=20}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- click on the other line
   edit.draw(Editor_state)
   edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)
@@ -439,7 +428,6 @@ function test_draw_text_wrapping_within_word()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abcd ', 'screen:1')
@@ -457,7 +445,6 @@ function test_draw_wrapping_text_containing_non_ascii()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'mad', 'screen:1')
@@ -476,7 +463,6 @@ function test_click_past_end_of_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -499,7 +485,6 @@ function test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=8}
   Editor_state.screen_top1 = {line=1, pos=7}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, "I'm ad", 'baseline/screen:2')
@@ -520,7 +505,6 @@ function test_click_past_end_of_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -544,7 +528,6 @@ function test_click_past_end_of_wrapping_line_containing_non_ascii()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'madam ', 'baseline/screen:1')
@@ -569,7 +552,6 @@ function test_click_past_end_of_word_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'the quick brown fox ', 'baseline/screen:1')
@@ -588,7 +570,6 @@ function test_select_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- select a letter
   App.fake_key_press('lshift')
@@ -611,7 +592,6 @@ function test_cursor_movement_without_shift_resets_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press an arrow key without shift
   edit.run_after_keychord(Editor_state, 'right', 'right')
@@ -629,7 +609,6 @@ function test_edit_deletes_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press a key
   edit.run_after_text_input(Editor_state, 'x')
@@ -646,7 +625,6 @@ function test_edit_with_shift_key_deletes_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- mimic precise keypresses for a capital letter
   App.fake_key_press('lshift')
@@ -668,7 +646,6 @@ function test_copy_does_not_reset_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- copy selection
   edit.run_after_keychord(Editor_state, 'C-c', 'c')
@@ -686,7 +663,6 @@ function test_cut()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- press a key
   edit.run_after_keychord(Editor_state, 'C-x', 'x')
@@ -704,7 +680,6 @@ function test_paste_replaces_selection()
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.selection1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- set clipboard
   App.clipboard = 'xyz'
@@ -723,7 +698,6 @@ function test_deleting_selection_may_scroll()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=2}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -747,7 +721,6 @@ function test_edit_wrapping_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   edit.run_after_text_input(Editor_state, 'g')
   local y = Editor_state.top
@@ -766,7 +739,6 @@ function test_insert_newline()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -795,7 +767,6 @@ function test_insert_newline_at_start_of_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- hitting the enter key splits the line
   edit.run_after_keychord(Editor_state, 'return', 'return')
   check_eq(Editor_state.cursor1.line, 2, 'cursor:line')
@@ -812,7 +783,6 @@ function test_insert_from_clipboard()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -841,7 +811,6 @@ function test_select_text_using_mouse()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- press and hold on first location
@@ -861,7 +830,6 @@ function test_select_text_using_mouse_starting_above_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- press mouse above first line of text
@@ -879,7 +847,6 @@ function test_select_text_using_mouse_starting_above_text_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=2, pos=3}
-  Editor_state.screen_bottom1 = {}
   -- press mouse above first line of text
   edit.draw(Editor_state)
   edit.run_after_mouse_press(Editor_state, Editor_state.left+8,5, 1)
@@ -902,7 +869,6 @@ function test_select_text_using_mouse_starting_below_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ab', 'baseline:screen:1')
@@ -923,7 +889,6 @@ function test_select_text_using_mouse_and_shift()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- click on first location
@@ -948,7 +913,6 @@ function test_select_text_repeatedly_using_mouse_and_shift()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)  -- populate line_cache.starty for each line Editor_state.line_cache
   -- click on first location
@@ -978,7 +942,6 @@ function test_select_all_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- select all
   App.fake_key_press('lctrl')
@@ -1000,7 +963,6 @@ function test_cut_without_selection()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   Editor_state.selection1 = {}
   edit.draw(Editor_state)
   -- try to cut without selecting text
@@ -1016,7 +978,6 @@ function test_pagedown()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the first two lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1046,7 +1007,6 @@ function test_pagedown_skips_drawings()
   check_eq(Editor_state.lines[2].mode, 'drawing', 'baseline/lines')
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   local drawing_height = Drawing_padding_height + drawing_width/2  -- default
   -- initially the screen displays the first line and the drawing
   -- 15px margin + 15px line1 + 10px margin + 25px drawing + 10px margin = 75px < screen height 80px
@@ -1062,36 +1022,6 @@ function test_pagedown_skips_drawings()
   App.screen.check(y, 'def', 'screen:1')
 end
 
-function test_pagedown_often_shows_start_of_wrapping_line()
-  -- draw a few lines ending in part of a wrapping line
-  App.screen.init{width=50, height=60}
-  Editor_state = edit.initialize_test_state()
-  Editor_state.lines = load_array{'abc', 'def ghi jkl', 'mno'}
-  Text.redraw_all(Editor_state)
-  Editor_state.cursor1 = {line=1, pos=1}
-  Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
-  edit.draw(Editor_state)
-  local y = Editor_state.top
-  App.screen.check(y, 'abc', 'baseline/screen:1')
-  y = y + Editor_state.line_height
-  App.screen.check(y, 'def ', 'baseline/screen:2')
-  y = y + Editor_state.line_height
-  App.screen.check(y, 'ghi ', 'baseline/screen:3')
-  -- after pagedown we start drawing from the bottom _line_ (multiple screen lines)
-  edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')
-  check_eq(Editor_state.screen_top1.line, 2, 'screen_top:line')
-  check_eq(Editor_state.screen_top1.pos, 1, 'screen_top:pos')
-  check_eq(Editor_state.cursor1.line, 2, 'cursor:line')
-  check_eq(Editor_state.cursor1.pos, 1, 'cursor:pos')
-  y = Editor_state.top
-  App.screen.check(y, 'def ', 'screen:1')
-  y = y + Editor_state.line_height
-  App.screen.check(y, 'ghi ', 'screen:2')
-  y = y + Editor_state.line_height
-  App.screen.check(y, 'jkl', 'screen:3')
-end
-
 function test_pagedown_can_start_from_middle_of_long_wrapping_line()
   -- draw a few lines starting from a very long wrapping line
   App.screen.init{width=Editor_state.left+30, height=60}
@@ -1100,7 +1030,6 @@ function test_pagedown_can_start_from_middle_of_long_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc ', 'baseline/screen:1')
@@ -1135,7 +1064,6 @@ function test_pagedown_never_moves_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=9}
   Editor_state.screen_top1 = {line=1, pos=9}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- pagedown makes no change
   edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')
@@ -1150,7 +1078,6 @@ function test_down_arrow_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the first three lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1183,7 +1110,6 @@ function test_down_arrow_skips_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1205,7 +1131,6 @@ function test_down_arrow_scrolls_down_by_one_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1233,7 +1158,6 @@ function test_down_arrow_scrolls_down_by_one_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1262,7 +1186,6 @@ function test_down_arrow_scrolls_down_by_one_screen_line_after_splitting_within_
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1290,7 +1213,6 @@ function test_pagedown_followed_by_down_arrow_does_not_scroll_screen_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1324,7 +1246,6 @@ function test_up_arrow_moves_cursor()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1356,7 +1277,6 @@ function test_up_arrow_skips_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1378,7 +1298,6 @@ function test_up_arrow_scrolls_up_by_one_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1406,7 +1325,6 @@ function test_up_arrow_scrolls_up_by_one_line_skipping_drawing()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=1}
   Editor_state.screen_top1 = {line=3, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1428,7 +1346,6 @@ function test_up_arrow_scrolls_up_by_one_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=6}
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -1456,7 +1373,6 @@ function test_up_arrow_scrolls_up_to_final_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ghi', 'baseline/screen:1')
@@ -1486,7 +1402,6 @@ function test_up_arrow_scrolls_up_to_empty_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1513,7 +1428,6 @@ function test_pageup()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- initially the last two lines are displayed
   edit.draw(Editor_state)
   local y = Editor_state.top
@@ -1538,7 +1452,6 @@ function test_pageup_scrolls_up_by_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'ghi', 'baseline/screen:1')
@@ -1567,7 +1480,6 @@ function test_pageup_scrolls_up_from_middle_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=2, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:2')
@@ -1594,7 +1506,6 @@ function test_enter_on_bottom_line_scrolls_down()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1623,7 +1534,6 @@ function test_enter_on_final_line_avoids_scrolling_down_when_not_at_bottom()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=4, pos=2}
   Editor_state.screen_top1 = {line=4, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -1646,7 +1556,6 @@ function test_inserting_text_on_final_line_avoids_scrolling_down_when_not_at_bot
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- after hitting the inserting_text key the screen does not scroll down
   edit.run_after_text_input(Editor_state, 'a')
@@ -1665,7 +1574,6 @@ function test_typing_on_bottom_line_scrolls_down()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc', 'baseline/screen:1')
@@ -1695,7 +1603,6 @@ function test_left_arrow_scrolls_up_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at top of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1724,7 +1631,6 @@ function test_right_arrow_scrolls_down_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at bottom right of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1754,7 +1660,6 @@ function test_home_scrolls_up_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at top of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1783,7 +1688,6 @@ function test_end_scrolls_down_in_wrapped_line()
   Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}
   Text.redraw_all(Editor_state)
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- cursor is at bottom right of screen
   Editor_state.cursor1 = {line=3, pos=5}
   edit.draw(Editor_state)
@@ -1814,7 +1718,6 @@ function test_position_cursor_on_recently_edited_wrapping_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=25}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'abc def ghi ', 'baseline1/screen:1')
@@ -1848,7 +1751,6 @@ function test_backspace_can_scroll_up()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=2, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'def', 'baseline/screen:1')
@@ -1876,7 +1778,6 @@ function test_backspace_can_scroll_up_screen_line()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=3, pos=5}
   Editor_state.screen_top1 = {line=3, pos=5}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   local y = Editor_state.top
   App.screen.check(y, 'jkl', 'baseline/screen:1')
@@ -2011,7 +1912,6 @@ function test_undo_insert_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=4}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- insert a character
   edit.draw(Editor_state)
   edit.run_after_text_input(Editor_state, 'g')
@@ -2046,7 +1946,6 @@ function test_undo_delete_text()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=5}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   -- delete a character
   edit.run_after_keychord(Editor_state, 'backspace', 'backspace')
   check_eq(Editor_state.cursor1.line, 2, 'baseline/cursor:line')
@@ -2085,7 +1984,6 @@ function test_undo_restores_selection()
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.selection1 = {line=1, pos=2}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- delete selected text
   edit.run_after_text_input(Editor_state, 'x')
@@ -2106,7 +2004,6 @@ function test_search()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2133,7 +2030,6 @@ function test_search_upwards()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2151,7 +2047,6 @@ function test_search_wrap()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=2, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')
@@ -2169,7 +2064,6 @@ function test_search_wrap_upwards()
   Text.redraw_all(Editor_state)
   Editor_state.cursor1 = {line=1, pos=1}
   Editor_state.screen_top1 = {line=1, pos=1}
-  Editor_state.screen_bottom1 = {}
   edit.draw(Editor_state)
   -- search upwards for a string
   edit.run_after_keychord(Editor_state, 'C-f', 'f')