I can't believe I didn't catch this until now. All I had to do is open MobyDick.markdown from https://www.hogbaysoftware.com/posts/moby-dick-workout, press page-down and click on the top screen line (or any screen line containing the same line as the top screen line). Easy to catch with any file containing lots of overly long lines, as happens in particular at the start of Moby Dick.
I had seen this problem before, but it seemed to disappear after unrelated changes, and I convinced myself I'd fixed it as a side-effect. The bug just failed to manifest if the top line happened to start at the top of the screen. Scroll down a few pages in Moby Dick and the dialogue starts and line length drops precipitously.
MYC7XR5QOT2AXHF6UNGSNFFD5VL6UHGUZQBP7PWWLZ5NNXE7UMTAC TNHZZYWPVWKA3OEBRH3QQ64GW3D2BQL5JJAVIUKQM5WBTYWASMIQC LAW2O3NWVFTPBSKIMIXPAGYBDOCHYJNKCAVWKNKH62G42DIKZCYQC PLKNHYZ4KXWWKC2DHXCI4WVO23I7VMEVYT5H2J6JDE4S3D3CHDJQC GJLOKCYKETWXJXBOS5222HVZIKBDOGLLR5QLUZYCTZG7FBYDTQMQC IWYLK45KJSPRXKW55OD4GEPMLTYMMTXNFJJU26JTZN3RE35DWSCQC LXTTOB33N2HCUZFIUDRQGGBVHK2HODRG4NBLH6RXRQZDCHF27BSAC H2DPLWMVRFYTO2CQTG54FMT2LF3B6UKLXH32CUA22DNQJVP5XBNQC BULPIBEGL7TMK6CVIE7IS7WGAHGOSUJBGJSFQK542MOWGHP2ADQQC CCYSVZA2ONWXB6XJXWSIEBY4CS2LGBEVV3RB6KZ6I4XYRXQLSTXQC DLQMM2656JHXX3ONOEM6UIOXKFJFT5QT7RHWK7YS2W77PVZWHRSAC HYEAFRZ2UEKDYTAE2GDQLHEJBPQASP2NDLMXB7F6MTVK2BKOXKEAC 6E3HVYWFP3JLJ3DJ5BH4WGJUXQV5MDCBCE5GH3SXRHRQZOG4VJLQC BOFNXP5GZDCUMQG3LQVTSSFEQP7REQ4RIRJLDLETFSAGFTVDVEKAC HOSPP2ANSW654DYRTC6CQUQA2GUKV6T2FI7QBKXD2DZS3R32IMGAC CBPV5SSIJFGEZLGF7LMC35KZWUTZUFNAWTTVNYDMEEUK4EBOMOVQC U52E2XZNDEMIX5QJC6TREX5BSLNYG23Y4XQVFFKS6OFB2KIBW7BAC 5L7K4GBDEAFH44LMLNKVFMHLWDNXXBKRPEI347VE5ZLXVFSMD2FAC MP2TBKU6CNDMZKENYMBV62F5KQ27ZWEVPVRFS2RESVDQQT2IRR4AC CPZGQT72EBP3SEDBPDWQRK5IUGA664PHXNP2GOHJLP43PKPWF25AC 65XHTZEKUTGHMOIWAFRH7ZVGUP4DWBCUT2TN4Y3LHYILKWTTBLKAC OTIBCAUJ3KDQJLVDN3A536DLZGNRYMGJLORZVR3WLCGXGO6UGO6AC OYXDYPGSJK2QICJ6RBA7357WT4FSNAWRUT77YLQHT3F3VYMWGNFQC UWNHC4AAO3SPOYLPANTO4WKCTZL7KAYC73Q2YUZFFW7K26FVJ7FQC ESETRNLB3MIJ2SID6HJMMP52FEVUBLGK2HLWD75KDQZAKQMKSF2QC YTSPVDZHEN5LLNMGIBUBLPWFWSFM3SOHBRGWYSDEVFKRTH24ARRQC CVGE3SIGJRGCLY3A2RBPGFXAEKVZXUUIZQLRHJLM4VPUM4SHEZIAC function test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen()io.write('\ntest_click_on_wrapping_line_rendered_from_partway_at_top_of_screen')-- display a wrapping line from its second screen lineApp.screen.init{width=80, height=80}-- 12345678901234Lines = load_array{"madam I'm adam"}Line_width = 75Cursor1 = {line=1, pos=8}Screen_top1 = {line=1, pos=7}Screen_bottom1 = {}App.draw()local y = Margin_topApp.screen.check(y, "I'm ada", 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/baseline/screen:2')y = y + Line_height-- click past end of second screen lineApp.run_after_mouse_click(App.screen.width-2,y-2, 1)-- cursor moves to end of screen linecheck_eq(Cursor1.line, 1, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:line')check_eq(Cursor1.pos, 13, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:pos')end
local y = line.yfor screen_line_index,screen_line_starting_pos in ipairs(line.screen_line_starting_pos) dolocal screen_line_starting_byte_offset = Text.offset(line.data, screen_line_starting_pos)
local y = line.startylocal start_screen_line_index = Text.screen_line_index(line, line.startpos)for screen_line_index = start_screen_line_index,#line.screen_line_starting_pos dolocal screen_line_starting_pos = line.screen_line_starting_pos[screen_line_index]local screen_line_starting_byte_offset = Text.offset(line.data, screen_line_starting_pos)