I think this works!
So the cause of all my trouble was a historical accident: I thought of computing viewport from screen_top before I thought of bring_cursor_of_cursor_pane_in_view. Turning the symbolic dependency DAG of variables into a graph turns out to be no end of trouble, where A sometimes depends on B and B sometimes on A.
Let's see if we uncover any issues.
NP5DODWMHP22MO6Z3B6NYDR7C3DLV2BD4NKT2RFFFOSIDPC3ZPWQC
4WAZ3E5BASY4GJDS5XNDRPHD4S4NVKRWHYOSFT6EXRTMM7Y5EKPAC
PKRRCD2P4LVQLDUCEJBQSKL4SJXRJ4P432VX7V27BBMGDMXIZAQAC
JMUE7GSN6QDQZ6NDRB55MRJMKJN6LBD6MVQPKROYPDOIXM7I3XNQC
UAX3KJOIN3XBSLKP4IAWAWSCI3DLDKF22A6HRMGA4FHY3AS2QRVAC
KKMFQDR43ZWVCDRHQLWWX3FCWCFA3ZSXYOBRJNPHUQZR2XPKWULAC
3U6YMMN2GMRL27TLPE7V3KUGM6MI2L3SAQSNU6HMNRINVXVRL3QAC
VPCPK52KMU4MZUXP4SUSJJDEHDR4C3KJ45HLMUQUK32FMY6OCQ4QC
F3DV7MD3AGOBXDBGFQXB5SK7ASMNGQSTN52P5AJ4MJEETMVTKYWQC
B3DXRFR34ASOJPIYXNKV27XXLRW2METE7TDN3IWLPE7AOSWVSXAAC
DYAYOMDPEQEUGTUPXWKICPBICZ67D6OW773FVIMS7XPIYPOYY2DQC
GR4RROJFJOGM2WLQSVK5R5UYD7IK6ITF6UP5RVHAHD3J4OFJWGCAC
3IBO5P7DVWMJM42VZL5HIFAJH55FK77K2IKPGMNI55GRXDXT4WUQC
CSV2GBWMGLN6CR3FIUUQ3FTZAFJJFO7DTPNOKOY5IOXNFI4O67IAC
AAYK7CECIP4352RGBPFBV52XUKI6YECVJN24PVCN4FG4NW7NQLKAC
AHOO2ILEJWTPCYHJH26WAF7A4YYVMHFX4UWHSAAAMHI73TSQZ6CAC
KTABGWEVR6D5KLOCVAOUDNQMRB3BUFU4GTR3OIAWLJSIPIG6G46QC
37AATGG5QIXOBXWA3DMSVMIIDSULA36NPETHOYZIOZ4G4RZLMHCAC
if should_update_screen_top(column_index, pane_index, pane, options) then
if body_sy < Display_settings.y then
pane.screen_top1, y_offset = schema1_of_y(pane, Display_settings.y - body_sy)
else
pane.screen_top1 = {line=1, pos=1}
end
end
function should_update_screen_top(column_index, pane_index, pane, options)
if options == nil then return true end
if column_index ~= Cursor_pane.col then return true end
if pane_index ~= Cursor_pane.row then return true end
return not options.preserve_screen_top_of_cursor_pane
end
end
end
-- return whether update happened
function maybe_update_screen_top_of_cursor_pane(pane, old_top)
local cursor_sy = up_edge_sy(Cursor_pane.col, Cursor_pane.row) + y_of_schema1(pane, pane.cursor1)
if not eq(old_top, pane.screen_top1) and eq(old_top, {line=1, pos=1}) and pane.top > Header_height and cursor_sy - Display_settings.y > App.screen.height - Header_height - Line_height then
-- updating screen_top1 can be jarring if the pane had room above it on screen
-- the editor updates screen_top1, then we update viewport based on screen_top1, and it goes from somewhere lower down to all the way at top of screen
-- prefer to pan the surface when possible
pane.screen_top1 = old_top
bring_cursor_of_cursor_pane_in_view('down')
Surface.cursor_on_screen_check = true -- cursor was on screen before keystroke, so it should remain on screen after
return false -- bring_cursor_of_cursor_pane_in_view updated Display_settings.y but not pane.screen_top1
local screen_top_updated = not eq(old_top, pane.screen_top1)
if screen_top_updated then
Display_settings.y = up_edge_sy(Cursor_pane.col, Cursor_pane.row) + y_of_schema1(pane, pane.screen_top1)
Surface.cursor_on_screen_check = true -- cursor was on screen before keystroke, so it should remain on screen after
end
return screen_top_updated