KN4TZ6RJ55FT3FPOZXM7WMS7UWG3VKERDEIJVRAJYEB4BETI4IRAC 6YWKM6WS4IKDNRDZED7A7L5G7SR5PXINOH53X2IH2DFJKS4TVPZQC 2QLTVKM6MVC25L44BSHKPZAXOOLK2VAUCGCYRUDRXXNYNSWDIWQAC MBAJPTDJ4KHWACEHWYGCFMHPQYM6FQKCSIIDKWCE765UI3VTDMIAC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC JOPVPUSAMMU6RFVDQR4NJC4GNNUFB7GPKVH7OS5FKCYS5QZ53VLQC KCDRLLAAANY5USQHWZ5QQDZDHJFJB6NS4WYZB3WE4AW4LPIV2RAAC VP5KC4XZBKD536KCBFO47UKH74RNONENDCFJAHUMVUTPVPGJWD4AC AYX33NBCPCBFWEZI5KZXHP3Y2Q62GYVT4WHYJUYRIPYV67KPSYZAC A4BSGS2CX4JK7IELL655EC6HAY6ILCWTGIHWZXHRGQOKU3HSUPLAC ICUW7F3XQLURK4LSNPH5E3NDEFSRHKATEUHH2UPFJTMHYR3ZJF3QC LXTTOB33N2HCUZFIUDRQGGBVHK2HODRG4NBLH6RXRQZDCHF27BSAC FNJFBXABRFX5WK6SSRDLZDCNCABN5X36HUPKRMJ7ECQTEK2XJJJQC 3OY667VAHI7ZNCTQH7NVPLJP42G3IBEZCU3CBYTQCOTJOZF5ZAZQC 62JEPVQ34SOTQI6VQNLGLKS5O4KFU52UKAVDHN6N7G5T6Z5EZO5QC FHNPQBLKB5EEJA4XDF2QJBCKB4W56LYWHJLVYA7ZPUSKM27QWWNQC LLQC2M2IMEJBJQXZTKC3OAKG5WKHSERXKAKCYHQRUZZD6CVRIHAQC 3SMSYTKNRPZXV5TFOVAKW7FUPPPDSTG6BWVT3ZAXB23YCH36MXCAC LF7BWEG4DKQI7NMXMZC4LC2BE5PB42HK5PD6OYBNIDMAZBJASOKQC LNUHQOGHIOFGJXNGA3DZLYEASLYYDGLN2I3EDZY5ANASQAHCG3YQC EMHRPJ3RAVIVJEQIRXIVDGENV6QHUUGXXRWTJ3BXC7SZNC66VK5QC 6PCE7VUWEE5UVSE3ZZSQAMGUJDDHOBNO2MVD6POUWFP7UY7WOZHAC 7EQLPB3O4DPUWGILY4P5D32SSIKL63QWWU5XRL2HISGNJXFWD2SAC 4WAFGF4ZMUQOLBWRZ2SI6RWEBKMFNFZQJMPECT25C2VPYHNDK2JQC KMRJOSLYYHHPGMYXBSLUQTICP6F4LXRCGYSP55YTZQSX4SZISDEAC 4J2L6JMR7NZBGCNX63CL2E3AIB7P7QTCC7QQBPNAEPQ7ISQXL7EQC CUIV2LE5D6GUQ4NU7K2TGUVO5CTUXVJDRCZUIV47LXTOUSEPEJHQC DSLD74DK3P6J2VAFCYF5BGTHZ637QTW3PDHOUHFACDZU66YNM3IAC CVSRHMJ2BM4LPVG67ULIVQMP2NW3YY2JC2ZQBEA6EB5KVM4O2L5AC FO6ZBUW6N7MTC5EXKJ5MP5NAUEBDM24DD5CVOJ6QYSANNKL2HNEQC T3B4NLV33PBD2L3YL3MHSOXZUWHDOGHPWLKKKHEBKJFSHYQWUK3AC 7RKFA3VAGK73SLC3NCOKHVMOWLTC4EUQYS47P3LVVKDVLBVGBEHAC Y4SPXCM3PKARGUU22FNBEDRU7S6CJSNYVAA76JYH4I4EMMMKP6LQC HTWAM4NZFOY463TNSKYIM2EWB7QNBGDRRTTGHF5N3Z4TGC7Q3SFAC S2YQBEYCOBS4ADO5VX4YLAWY6CJEQOOZM3THYTDOTXM7ADID6PGQC FZBXBUFFNRE5ZJO5DLRU375HOXT2B7FO35XD7BTHHUXSARVWDFLQC GG2553RBUKMCWIAD3EWJV7C2QH2BIS5V2E3BDTFSTYRHAPXGBF7QC 2CK5QI7WA7M4IVSACFGOJYAIDKRUTZVMMPSFWEJTUNMWTN7AX4NAC LLAOOMULEBXFMIGRBY6LRVEK4RXQGPNTFVWMCZNUEJZHWC7UGUEAC MSOQI3A5BC5PY2MZXZQAQ4EQDT4KICQJPN3YUZVDYTWXSPZWBLIAC AMOPICKVRHMQERJLFPMAAEBV7TL5QACGGSBJWRCMV5R5O3KDVETAC 3PSFWAILGRA4OYXWS2DX7VF332AIBPYBXHEA4GIQY2XEJVD65UMAC GLZ6ZD6U52AJ7QYPR3CCJUGD3JDDGZ4NU3FAQXBMHMZ5O5XGOKAQC 3VHUIIATPOF7FXB7NTL5MESCV5BCQACII2D7QZ4UIUCBX3CWXMMAC D4B52CQ2QKG2HQKFUQOO5S2ME325DTW3PH2D7SBXCW4BPQFYG7CAC 5XMBCKJZ7YCUOOQWWZRNLXMXD3MUYC2VAF3VKA4BIEHQRPDQMUMAC ONHKBLLCD5NDO3HSSUMAMGJ7HDT53JYVV56DI42AEYI3W63GKACQC WB66TPZSJ6SPPZKQVDON56URAO3XPKSY7CE5WKDSE4S36U2ZE6PAC NAGDS5E2LF4PFXZS72KKDWQ5K5KMZXLV763Q4VCKIT6GOBAWB6MAC F52PSTYSIIUD7UPEVLEJPVSBQU7IKVHM4GN4YASNSKFP4MRE6S6AC B4FAIVRAXKCS2ZZXYUHL7HHWVMDMG2MQ3BY6IOJARK7B5XTBAQNAC 2TQUKHBC2EB3WDBD5UL62DQYV7CV6B7OJYK7CHOEDNOZENSOG42AC M7SW76FQORGMK7VH5LCFBFZMGONVIAEHYPGQAWTKTKANU7ZAT6CQC ORKN6EOBUFVAD2TXYW5OIKSL55RU24LOFDTTTXHDZUZ57QRDCY7QC 22K3VJIL4SRPXVAEJSWRS7KM4UPV4SOODPSTSSKPFWKLTYRG365QC TOJA6VDEWPXDE4KE6URFLNIZBQ6ASAFDZMSYSIBDBKACBGUKZI3QC CE4LZV4TNXJT54CVGM3QANCBP42TMLMZWF2DBSMUYKAHILXIZEMQC R2ASHK5CEE3PTRLS37GP4PXJ7HIGJ6UD72KKBI57UDJI7VRROQGQC UGTWUIS4MWIITRDEAGULOPRV5KJD7HEGCOSR5BP4KLVBAVHU2ETQC 2L5MEZV344TOZLVY3432RHJFIRVXFD6O3GWLL5O4CV66BGAFTURQC QMRQL2FOIIXU3PCSH7UQIDRLKJN2DQHB5IUL4TLBVANNHWWETL6AC MYQNSDA3BKAVX3AKPKUDVFOL7B2O53O7U75B6Y673HJZGOULFBYAC App.run_after_keychord('C-l', 'l')App.run_after_keychord('C-l', 'l')-- margins are now adjustedcheck(Show_log_browser_side, 'check')
edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'C-m', 'm')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'S-right', 'right')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'C-c', 'c')edit.run_after_keychord(Editor_state, 'C-x', 'x')edit.run_after_keychord(Editor_state, 'C-v', 'v')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-v', 'v')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'C-x', 'x')edit.run_after_keychord(Editor_state, 'C-a', 'a')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'home', 'home')edit.run_after_keychord(Editor_state, 'end', 'end')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'C-z', 'z')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'C-z', 'z')edit.run_after_keychord(Editor_state, 'C-z', 'z')edit.run_after_keychord(Editor_state, 'C-z', 'z')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'up', 'up')
edit.run_after_keychord(Editor_state, 'M-left')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'C-m', 'm')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')
edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-left', 'left')
edit.run_after_keychord(Editor_state, 'M-left', 'left')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'M-right', 'right')edit.run_after_keychord(Editor_state, 'S-right', 'right')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'C-c', 'c')edit.run_after_keychord(Editor_state, 'C-x', 'x')edit.run_after_keychord(Editor_state, 'C-v', 'v')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-v', 'v')
edit.run_after_keychord(Editor_state, 'C-a', 'a')edit.run_after_keychord(Editor_state, 'C-x', 'x')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')
edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'pagedown', 'pagedown')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'pageup', 'pageup')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'left', 'left')edit.run_after_keychord(Editor_state, 'right', 'right')edit.run_after_keychord(Editor_state, 'home', 'home')edit.run_after_keychord(Editor_state, 'end', 'end')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')edit.run_after_keychord(Editor_state, 'backspace', 'backspace')
check_eq(Editor_state.cursor1.line, 2, 'baseline/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'baseline/cursor:pos')check_nil(Editor_state.selection1.line, 'baseline/selection:line')check_nil(Editor_state.selection1.pos, 'baseline/selection:pos')
check_eq(Editor_state.cursor1.line, 2, 'cursor:line')check_eq(Editor_state.cursor1.pos, 5, 'cursor:pos')check_nil(Editor_state.selection1.line, 'selection:line')check_nil(Editor_state.selection1.pos, 'selection:pos')--? check_eq(Editor_state.selection1.line, 2, 'selection:line')--? check_eq(Editor_state.selection1.pos, 4, 'selection:pos')
edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'down', 'down')edit.run_after_keychord(Editor_state, 'return', 'return')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'up', 'up')edit.run_after_keychord(Editor_state, 'C-f', 'f')edit.run_after_keychord(Editor_state, 'return', 'return')
function edit.run_after_keychord(State, chord)edit.keychord_press(State, chord)edit.key_release(State, chord)
function edit.run_after_keychord(State, chord, key)edit.keychord_press(State, chord, key)edit.key_release(State, key)
Text.delete_selection(State, State.left, State.right)endif State.search_term thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollif chord == 'escape' thenState.search_term = nilState.cursor1 = State.search_backup.cursorState.screen_top1 = State.search_backup.screen_topState.search_backup = nilText.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leakselseif chord == 'return' thenState.search_term = nilState.search_backup = nilelseif chord == 'backspace' thenlocal len = utf8.len(State.search_term)local byte_offset = Text.offset(State.search_term, len)State.search_term = string.sub(State.search_term, 1, byte_offset-1)elseif chord == 'down' thenState.cursor1.pos = State.cursor1.pos+1Text.search_next(State)elseif chord == 'up' thenText.search_previous(State)endreturnelseif chord == 'C-f' thenState.search_term = ''State.search_backup = {cursor={line=State.cursor1.line, pos=State.cursor1.pos},screen_top={line=State.screen_top1.line, pos=State.screen_top1.pos},}-- zoomelseif chord == 'C-=' thenedit.update_font_settings(State, State.font_height+2)Text.redraw_all(State)elseif chord == 'C--' thenif State.font_height > 2 thenedit.update_font_settings(State, State.font_height-2)Text.redraw_all(State)endelseif chord == 'C-0' thenedit.update_font_settings(State, 20)Text.redraw_all(State)-- undoelseif chord == 'C-z' thenlocal event = undo_event(State)if event thenlocal src = event.beforeState.screen_top1 = deepcopy(src.screen_top)State.cursor1 = deepcopy(src.cursor)State.selection1 = deepcopy(src.selection)patch(State.lines, event.after, event.before)patch_placeholders(State.line_cache, event.after, event.before)-- if we're scrolling, reclaim all fragments to avoid memory leaksText.redraw_all(State)schedule_save(State)endelseif chord == 'C-y' thenlocal event = redo_event(State)if event thenlocal src = event.afterState.screen_top1 = deepcopy(src.screen_top)State.cursor1 = deepcopy(src.cursor)State.selection1 = deepcopy(src.selection)patch(State.lines, event.before, event.after)-- if we're scrolling, reclaim all fragments to avoid memory leaksText.redraw_all(State)schedule_save(State)end-- clipboardelseif chord == 'C-a' thenState.selection1 = {line=1, pos=1}State.cursor1 = {line=#State.lines, pos=utf8.len(State.lines[#State.lines].data)+1}elseif chord == 'C-c' thenlocal s = Text.selection(State)if s thenApp.set_clipboard(s)endelseif chord == 'C-x' thenlocal s = Text.cut_selection(State, State.left, State.right)if s thenApp.set_clipboard(s)endschedule_save(State)elseif chord == 'C-v' then-- We don't have a good sense of when to scroll, so we'll be conservative-- and sometimes scroll when we didn't quite need to.local before_line = State.cursor1.linelocal before = snapshot(State, before_line)local clipboard_data = App.get_clipboard()for _,code in utf8.codes(clipboard_data) dolocal c = utf8.char(code)if c == '\n' thenText.insert_return(State)elseText.insert_at_cursor(State, c)endendif Text.cursor_out_of_screen(State) thenText.snap_cursor_to_bottom_of_screen(State, State.left, State.right)endschedule_save(State)record_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor1.line)})-- dispatch to textelsefor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollText.keychord_press(State, chord)endendfunction edit.key_release(State, key, scancode)endfunction edit.update_font_settings(State, font_height)State.font_height = font_height
State.line_height = math.floor(font_height*1.3)end--== some methods for tests-- Insulate tests from some key globals so I don't have to change the vast-- majority of tests when they're modified for the real app.Test_margin_left = 25Test_margin_right = 0function edit.initialize_test_state()-- if you change these values, tests will start failingreturn edit.initialize_state(15, -- top marginTest_margin_left,App.screen.width - Test_margin_right,
15) -- line heightend-- all text_input events are also keypresses-- TODO: handle chords of multiple keysfunction edit.run_after_text_input(State, t)edit.keychord_press(State, t)edit.text_input(State, t)edit.key_release(State, t)App.screen.contents = {}edit.update(State, 0)edit.draw(State)end-- not all keys are text_input
App.screen.contents = {}edit.update(State, 0)edit.draw(State)endfunction edit.run_after_mouse_click(State, x,y, mouse_button)App.fake_mouse_press(x,y, mouse_button)edit.mouse_press(State, x,y, mouse_button)App.fake_mouse_release(x,y, mouse_button)edit.mouse_release(State, x,y, mouse_button)App.screen.contents = {}edit.update(State, 0)edit.draw(State)endfunction edit.run_after_mouse_press(State, x,y, mouse_button)App.fake_mouse_press(x,y, mouse_button)edit.mouse_press(State, x,y, mouse_button)App.screen.contents = {}edit.update(State, 0)edit.draw(State)endfunction edit.run_after_mouse_release(State, x,y, mouse_button)App.fake_mouse_release(x,y, mouse_button)edit.mouse_release(State, x,y, mouse_button)App.screen.contents = {}edit.update(State, 0)edit.draw(State)end