fix a bad merge
[?]
Sep 16, 2023, 7:07 AM
R2ASHK5CEE3PTRLS37GP4PXJ7HIGJ6UD72KKBI57UDJI7VRROQGQCDependencies
- [2]
6ECYOEHYbugfix: obsolete location for attribute - [3]
PV2YA7KSsubsection headings in a long switch - [4]
RRDO6H7Hbugfix - [5]
5ITAXPEPwait a little to flush disk before quitting - [6]
3KMHGUMHMerge lines.love - [7]
34BZ5ZKNMerge lines.love - [8]
UD7HNQL7purge unused button infrastructure - [9]
QQBP3G6Wreturn height of editor widget after drawing - [10]
WLJCIXYMadd state arg to a few functions - [11]
4EGQRXDAbugfix: naming points - [12]
UH4YWHW5button framework is at the app level - [13]
HNZMFBMQMerge lines.love - [14]
PP2IIHL6stop putting button state in a global - [15]
BH7BT36Lctrl+a: select entire buffer - [16]
GN3C6AGMbugfix in changing shape mid-stroke - [17]
SW7BSBMJseveral bugfixes in saving/loading cursor position - [18]
2MGBV7NPbugfix: crash when using mouse wheel - [19]
ISOFHXB2App.width can no longer take a Text - [20]
U3MJNFUYMerge lines.love - [21]
UHB4GARJleft/right margin -> left/right coordinates - [22]
4KC7I3E2make colors easier to edit - [23]
3QQZ7W4Ebring couple more globals back to the app level - [24]
LF7BWEG4group all editor globals - [25]
O4RRXNOKbugfix: disallow font size of 0 - [26]
TXI6GSQDsome minor cleanup - [27]
5ZA3BRNYadd state arg to a few functions - [28]
TGHAJBESuse line cache for drawings as well - [29]
ELJNEPW2simplify cursor-on-screen check - [30]
QJISOCHJsome temporary logging to catch a bug - [31]
2CK5QI7Wmake love event names consistent - [32]
LDFXFRUObring a few things in sync between run and source - [33]
GFXWHTE6mouse wheel support - [34]
NVSC4N4Kchange a helper slightly - [35]
X3F7ECSLadd state arg to some functions - [36]
WJBZZQE4fold together two largely similar cases - [37]
VZJHGWSPMerge lines.love - [38]
LNUHQOGHstart passing in Editor_state explicitly - [39]
AF253GHLbugfix - [40]
MD3W5IRAnew fork: rip out drawing support - [41]
6D5MOJS4allow buttons to interrupt events - [42]
WLWNS6FBa bug I've never run into - [43]
SPNMXTYRhave file API operate on state object - [44]
APX2PY6Gstop tracking wallclock time - [45]
MU2HIRR6Merge lines.love - [46]
VOU73AK6Merge lines.love - [47]
3XNFQDDNMerge lines.love - [48]
QCPXQ2E3add state arg to a few functions - [49]
PWDBOOWJcopying to clipboard can never scroll - [50]
WK6UK5AJenhance bugfix of commit a9aa3436f (Dec 2024) - [51]
YFW4MNNPhandle wrapping lines - [52]
CNCYMM6Amake test initializations a little more obvious - [53]
YRJFJNUDbugfix - [54]
KWIVKQQ7Merge lines.love - [55]
Z5HLXU4Padd state arg to a few functions - [56]
APYPFFS3call edit rather than App callbacks in tests - [57]
5UKUADTWdistinguish consistently between mouse buttons and other buttons - [58]
SPSW74Y5add state arg to Text.keychord_pressed - [59]
H6QZ7GRRmore precise name - [60]
5BMR5HRTclick to the left of a line - [61]
VP5KC4XZMerge lines.love - [62]
OGD5RAQKbugfix: naming points in drawings - [63]
ORKN6EOBMerge lines.love - [64]
7FPELAZBah, I see the problem - [65]
FPY4LO2Wmake a few names consistent with snake_case - [66]
32V6ZHQBMerge lines.love - [67]
PJEQCTBLadd state arg to Drawing.update - [68]
MUJTM6REbring back a level of wrapping - [69]
3PSFWAILMerge lines.love - [70]
2WGHUWE6self-documenting 0 Test_right_margin - [71]
2Y7YH7UPinfrastructure for caching LÖVE text objects - [72]
ILOA5BYFseparate data structure for each line's cache data - [73]
KYNGDE2Cconsistent names in a few more places - [74]
3MAZEQK5add state arg to Text.textinput - [75]
S2MISTTMadd state arg to a few functions - [76]
Z3IQ6A4Rbugfix - [77]
OI4FPFINsupport drawings in the source editor - [78]
7VGDIPLCmore robust state validation - [79]
IFTYOERMline.y -> line_cache.starty in a few more places - [80]
GZ5WULJVswitch source side to new screen-line-based render - [81]
Z3BQO2RKtypo - [82]
6XCJX4DZbugfix: inscript's bug - [83]
ONHKBLLCMerge lines.love - [84]
MTJEVRJRadd state arg to a few functions - [85]
PTDO2SOTadd state arg to schedule_save - [86]
2L5MEZV3experiment: new edit namespace - [87]
ERQKFTPVextract method - [88]
6RYLD5ONchange how we handle clicks above top margin - [89]
MOAEVTKJclean up a few more loose ends
Change contents
- replacement in edit.lua at line 98[8.22445]→[8.1951:1996](∅→∅),[8.9658]→[8.6003:6003](∅→∅),[8.470]→[5.26:113](∅→∅),[8.11328]→[8.6653:6653](∅→∅),[8.9616]→[8.11329:11507](∅→∅),[8.1870]→[8.6654:6847](∅→∅),[8.5593]→[8.170:199](∅→∅),[8.6985]→[8.134:241](∅→∅),[8.6870]→[3.26:36](∅→∅),[8.11602]→[8.75:75](∅→∅),[8.756]→[8.364:368](∅→∅),[8.258]→[8.364:368](∅→∅),[8.7283]→[8.756:756](∅→∅),[8.258]→[8.7264:7283](∅→∅),[8.7264]→[8.7264:7283](∅→∅),[8.7264]→[8.234:258](∅→∅),[8.567]→[8.7237:7264](∅→∅),[8.6186]→[8.7237:7264](∅→∅),[8.7237]→[8.7237:7264](∅→∅),[8.519]→[8.6139:6186](∅→∅),[8.7099]→[8.411:519](∅→∅),[8.233]→[8.7075:7099](∅→∅),[8.7075]→[8.7075:7099](∅→∅),[8.7075]→[8.209:233](∅→∅),[8.410]→[8.7048:7075](∅→∅),[8.880]→[8.7048:7075](∅→∅),[8.7048]→[8.7048:7075](∅→∅),[8.363]→[8.835:880](∅→∅),[8.6915]→[8.259:363](∅→∅),[8.208]→[8.6891:6915](∅→∅),[8.6891]→[8.6891:6915](∅→∅),[8.6891]→[8.184:208](∅→∅),[8.258]→[8.6864:6891](∅→∅),[8.6138]→[8.6864:6891](∅→∅),[8.6864]→[8.6864:6891](∅→∅),[8.210]→[8.6091:6138](∅→∅),[8.834]→[8.166:210](∅→∅),[8.166]→[8.166:210](∅→∅),[8.119]→[8.789:834](∅→∅),[8.6651]→[8.15:119](∅→∅),[8.183]→[8.6627:6651](∅→∅),[8.6627]→[8.6627:6651](∅→∅),[8.6627]→[8.159:183](∅→∅),[8.6090]→[8.6600:6627](∅→∅),[8.6600]→[8.6600:6627](∅→∅),[8.6528]→[8.6021:6090](∅→∅),[8.6020]→[8.6481:6528](∅→∅),[8.6481]→[8.6481:6528](∅→∅),[8.6451]→[8.5989:6020](∅→∅),[8.16047]→[8.6450:6451](∅→∅),[8.6449]→[8.16043:16047](∅→∅),[8.9642]→[8.16043:16047](∅→∅),[8.16043]→[8.16043:16047](∅→∅),[8.158]→[8.6430:6449](∅→∅),[8.6430]→[8.6430:6449](∅→∅),[8.6430]→[8.134:158](∅→∅),[8.5988]→[8.6403:6430](∅→∅),[8.6403]→[8.6403:6430](∅→∅),[8.6268]→[8.5854:5988](∅→∅),[8.5853]→[8.6228:6268](∅→∅),[8.6228]→[8.6228:6268](∅→∅),[8.6184]→[8.5808:5853](∅→∅),[8.5729]→[8.6183:6184](∅→∅),[8.6183]→[8.6183:6184](∅→∅),[8.1119]→[8.5645:5729](∅→∅),[8.5645]→[8.5645:5729](∅→∅),[8.5600]→[8.1075:1119](∅→∅),[8.1074]→[8.5422:5600](∅→∅),[8.5422]→[8.5422:5600](∅→∅),[8.5422]→[8.1052:1074](∅→∅),[8.1051]→[8.5400:5422](∅→∅),[8.5400]→[8.5400:5422](∅→∅),[8.5400]→[8.915:1051](∅→∅),[8.447]→[8.5371:5400](∅→∅),[8.6146]→[8.5371:5400](∅→∅),[8.329]→[8.442:447](∅→∅),[8.442]→[8.442:447](∅→∅),[4.92]→[8.337:387](∅→∅),[8.337]→[8.337:387](∅→∅),[8.264]→[4.26:92](∅→∅),[8.6146]→[8.175:264](∅→∅),[8.5807]→[8.6141:6146](∅→∅),[8.9642]→[8.6141:6146](∅→∅),[8.16001]→[8.5759:5807](∅→∅),[8.5758]→[8.15990:16001](∅→∅),[8.7139]→[8.15990:16001](∅→∅),[8.15990]→[8.15990:16001](∅→∅),[8.1400]→[8.5720:5758](∅→∅),[8.15878]→[8.1293:1400](∅→∅),[8.75]→[8.15871:15878](∅→∅),[8.631]→[8.15871:15878](∅→∅),[8.8798]→[8.15871:15878](∅→∅),[8.11602]→[8.15871:15878](∅→∅),[8.15871]→[8.15871:15878](∅→∅),[8.2812]→[8.11580:11602](∅→∅),[8.577]→[8.2710:2812](∅→∅),[8.14368]→[8.552:577](∅→∅),[8.1438]→[8.14360:14368](∅→∅),[8.8913]→[8.14360:14368](∅→∅),[8.23116]→[8.14360:14368](∅→∅),[8.105181]→[8.14360:14368](∅→∅),[8.14360]→[8.14360:14368](∅→∅),[8.360]→[8.23041:23116](∅→∅),[8.1331]→[8.23041:23116](∅→∅),[8.14227]→[8.315:360](∅→∅),[8.8706]→[8.14209:14227](∅→∅),[8.14209]→[8.14209:14227](∅→∅),[8.14176]→[8.8666:8706](∅→∅),[8.8665]→[8.14165:14176](∅→∅),[8.14165]→[8.14165:14176](∅→∅),[8.14136]→[8.8631:8665](∅→∅),[8.454]→[8.14032:14136](∅→∅),[8.14032]→[8.14032:14136](∅→∅),[8.2709]→[8.407:454](∅→∅),[8.8812]→[8.2661:2709](∅→∅),[8.13904]→[8.8769:8812](∅→∅),[2.230]→[8.13768:13904](∅→∅),[8.1249]→[8.13768:13904](∅→∅),[8.8768]→[8.13768:13904](∅→∅),[8.105015]→[8.13768:13904](∅→∅),[8.13768]→[8.13768:13904](∅→∅),[8.13689]→[2.123:230](∅→∅),[8.551]→[8.13660:13689](∅→∅),[8.13660]→[8.13660:13689](∅→∅),[8.13640]→[8.526:551](∅→∅),[8.406]→[8.13632:13640](∅→∅),[8.13632]→[8.13632:13640](∅→∅),[8.13602]→[8.379:406](∅→∅),[8.3962]→[8.13588:13602](∅→∅),[8.8682]→[8.13588:13602](∅→∅),[8.23040]→[8.13588:13602](∅→∅),[8.104922]→[8.13588:13602](∅→∅),[8.13588]→[8.13588:13602](∅→∅),[8.1158]→[8.22975:23040](∅→∅),[8.8593]→[8.22975:23040](∅→∅),[8.13432]→[8.1051:1158](∅→∅),[8.378]→[8.13395:13432](∅→∅),[8.13395]→[8.13395:13432](∅→∅),[8.13365]→[8.351:378](∅→∅),[8.3865]→[8.13351:13365](∅→∅),[8.13351]→[8.13351:13365](∅→∅),[8.1050]→[8.3829:3865](∅→∅),[8.8507]→[8.3829:3865](∅→∅),[8.657]→[8.13212:13241](∅→∅),[8.13212]→[8.13212:13241](∅→∅),[8.13212]→[8.501:657](∅→∅),[8.525]→[8.13189:13212](∅→∅),[8.13189]→[8.13189:13212](∅→∅),[8.398]→[8.498:525](∅→∅),[8.7066]→[8.498:525](∅→∅),[8.13167]→[8.498:525](∅→∅),[8.296]→[8.296:398](∅→∅),[8.12904]→[8.8226:8421](∅→∅),[8.2660]→[8.12856:12904](∅→∅),[8.12856]→[8.12856:12904](∅→∅),[8.942]→[8.2624:2660](∅→∅),[8.8225]→[8.2624:2660](∅→∅),[8.12746]→[8.835:942](∅→∅),[8.497]→[8.12709:12746](∅→∅),[8.12709]→[8.12709:12746](∅→∅),[8.206]→[8.470:497](∅→∅),[8.6968]→[8.470:497](∅→∅),[8.12687]→[8.470:497](∅→∅),[8.104]→[8.104:206](∅→∅),[8.8139]→[8.1967:2037](∅→∅),[8.12424]→[8.7944:8139](∅→∅),[8.2623]→[8.12375:12424](∅→∅),[8.12375]→[8.12375:12424](∅→∅),[2.122]→[8.2587:2623](∅→∅),[8.834]→[8.2587:2623](∅→∅),[8.7943]→[8.2587:2623](∅→∅),[8.12265]→[2.15:122](∅→∅),[3.36]→[8.12236:12265](∅→∅),[8.6870]→[8.12236:12265](∅→∅),[8.12236]→[8.12236:12265](∅→∅),[8.174]→[8.6843:6870](∅→∅),[8.12214]→[8.6843:6870](∅→∅),[8.12181]→[8.133:174](∅→∅),[8.289]→[8.12152:12181](∅→∅),[8.6842]→[8.12152:12181](∅→∅),[8.12152]→[8.12152:12181](∅→∅),[8.12086]→[8.158:289](∅→∅),[8.6814]→[8.12057:12086](∅→∅),[8.12057]→[8.12057:12086](∅→∅),[8.73]→[8.6787:6814](∅→∅),[8.7806]→[8.6787:6814](∅→∅),[8.11991]→[8.15:73](∅→∅),[3.25]→[8.11962:11991](∅→∅),[8.7755]→[8.11962:11991](∅→∅),[8.103883]→[8.11962:11991](∅→∅),[8.11962]→[8.11962:11991](∅→∅),[8.7755]→[3.15:25](∅→∅),[8.7565]→[8.25240:25412](∅→∅),[8.11787]→[8.7538:7565](∅→∅),[8.2183]→[8.11739:11787](∅→∅),[8.11739]→[8.11739:11787](∅→∅),[8.11710]→[8.2149:2183](∅→∅),[8.2148]→[8.11680:11710](∅→∅),[8.11680]→[8.11680:11710](∅→∅),[8.7537]→[8.2118:2148](∅→∅),[8.11621]→[8.7491:7537](∅→∅),[8.7490]→[8.11589:11621](∅→∅),[8.103555]→[8.11589:11621](∅→∅),[8.11589]→[8.11589:11621](∅→∅),[8.11407]→[8.7278:7460](∅→∅),[8.7277]→[8.11370:11407](∅→∅),[8.103307]→[8.11370:11407](∅→∅),[8.11370]→[8.11370:11407](∅→∅),[8.7245]→[8.7245:7277](∅→∅),[8.11296]→[8.7185:7215](∅→∅),[8.6786]→[8.11262:11296](∅→∅),[8.11262]→[8.11262:11296](∅→∅),[8.7184]→[8.6689:6786](∅→∅),[8.7046]→[8.7046:7184](∅→∅),[8.11014]→[8.6986:7016](∅→∅),[8.241]→[8.10984:11014](∅→∅),[8.6985]→[8.10984:11014](∅→∅),[8.102945]→[8.10984:11014](∅→∅),[8.10984]→[8.10984:11014](∅→∅),[8.10962]→[8.6957:6985](∅→∅),[8.3828]→[8.10956:10962](∅→∅),[8.6956]→[8.10956:10962](∅→∅),[8.22974]→[8.10956:10962](∅→∅),[8.102909]→[8.10956:10962](∅→∅),[8.10956]→[8.10956:10962](∅→∅),[8.325]→[8.22916:22974](∅→∅),[8.363]→[8.22916:22974](∅→∅),[8.401]→[8.22916:22974](∅→∅),[8.500]→[8.22916:22974](∅→∅),[8.10886]→[8.22916:22974](∅→∅),[8.10752]→[8.214:401](∅→∅),[8.6873]→[8.10522:10752](∅→∅),[8.102812]→[8.10522:10752](∅→∅),[8.10522]→[8.10522:10752](∅→∅),[8.5675]→[8.6800:6831](∅→∅),[8.6800]→[8.6800:6831](∅→∅),[8.10343]→[8.5627:5675](∅→∅),[8.469]→[8.10338:10343](∅→∅),[8.10338]→[8.10338:10343](∅→∅),[8.10320]→[8.446:469](∅→∅),[8.162]→[8.10314:10320](∅→∅),[8.273]→[8.10314:10320](∅→∅),[8.806]→[8.10314:10320](∅→∅),[8.8796]→[8.10314:10320](∅→∅),[8.10314]→[8.10314:10320](∅→∅),[8.8765]→[8.8766:8796](∅→∅),[8.133]→[8.8765:8765](∅→∅),[8.10292]→[8.26:133](∅→∅),[8.2586]→[8.10285:10292](∅→∅),[8.6749]→[8.10285:10292](∅→∅),[8.102724]→[8.10285:10292](∅→∅),[8.10285]→[8.10285:10292](∅→∅),[8.6495]→[8.2089:2117](∅→∅),[8.199]→[8.6394:6467](∅→∅),[8.743]→[8.6394:6467](∅→∅),[8.5593]→[8.6394:6467](∅→∅),[8.6394]→[8.6394:6467](∅→∅),[8.9696]→[8.5558:5593](∅→∅),[8.11579]→[8.9691:9696](∅→∅),[8.9691]→[8.9691:9696](∅→∅),[8.2225]→[8.9685:9691](∅→∅),[8.6276]→[8.9685:9691](∅→∅),[8.102222]→[8.9685:9691](∅→∅),[8.9685]→[8.9685:9691](∅→∅),[8.212]→[8.2163:2225](∅→∅),[8.2163]→[8.2163:2225](∅→∅),[8.2163]→[8.167:212](∅→∅),[8.182]→[8.2080:2163](∅→∅),[8.2080]→[8.2080:2163](∅→∅),[8.2073]→[8.161:182](∅→∅),[8.166]→[8.2014:2073](∅→∅),[8.2014]→[8.2014:2073](∅→∅),[8.2014]→[8.121:166](∅→∅),[8.2028]→[8.1870:2014](∅→∅),[8.6847]→[8.1870:2014](∅→∅),[8.1870]→[8.1870:2014](∅→∅),[8.936]→[8.1864:1870](∅→∅),[8.1241]→[8.1864:1870](∅→∅),[8.3165]→[8.1864:1870](∅→∅),[8.6276]→[8.1864:1870](∅→∅),[8.11507]→[8.9616:9624](∅→∅),[8.9616]→[8.9616:9624](∅→∅),[8.73]→[8.9594:9616](∅→∅),[8.6653]→[8.9594:9616](∅→∅),[8.8763]→[8.9594:9616](∅→∅),[8.11328]→[8.9594:9616](∅→∅),[8.9594]→[8.9594:9616](∅→∅),[8.6651]→[8.11132:11328](∅→∅),[8.11132]→[8.11132:11328](∅→∅),[8.11067]→[8.6539:6651](∅→∅),[8.6538]→[8.10948:11067](∅→∅),[8.10948]→[8.10948:11067](∅→∅),[8.10913]→[8.6459:6538](∅→∅),[8.71]→[8.10816:10913](∅→∅),[8.6458]→[8.10816:10913](∅→∅),[8.8468]→[8.10816:10913](∅→∅),[8.5338]→[8.6339:6458](∅→∅),[8.5504]→[8.5299:5338](∅→∅),[8.5299]→[8.5299:5338](∅→∅),[8.8364]→[8.5450:5504](∅→∅),[8.2595]→[8.8359:8364](∅→∅),[8.8359]→[8.8359:8364](∅→∅),[8.8359]→[8.2287:2595](∅→∅),[8.6338]→[8.8345:8359](∅→∅),[8.8761]→[8.8345:8359](∅→∅),[8.10815]→[8.8345:8359](∅→∅),[8.8345]→[8.8345:8359](∅→∅),[8.6324]→[8.6325:6338](∅→∅),[8.10729]→[8.6324:6324](∅→∅),[8.6322]→[8.10473:10729](∅→∅),[8.10473]→[8.10473:10729](∅→∅),[8.10408]→[8.6181:6322](∅→∅),[8.4696]→[8.9917:10408](∅→∅),[8.1281]→[8.4648:4696](∅→∅),[8.7017]→[8.4648:4696](∅→∅),[8.865]→[8.1257:1281](∅→∅),[8.1257]→[8.1257:1281](∅→∅),[8.1226]→[8.793:865](∅→∅),[8.6180]→[8.1049:1226](∅→∅),[8.7017]→[8.1049:1226](∅→∅),[8.4581]→[8.6075:6180](∅→∅),[8.721]→[8.4542:4581](∅→∅),[8.4542]→[8.4542:4581](∅→∅),[8.6757]→[8.669:721](∅→∅),[5.113]→[8.6746:6757](∅→∅),[8.470]→[8.6746:6757](∅→∅),[8.4487]→[8.6746:6757](∅→∅),[8.100241]→[8.6746:6757](∅→∅),[8.6746]→[8.6746:6757](∅→∅),[8.4441]→[8.446:470](∅→∅),[8.6692]→[8.4415:4441](∅→∅),[8.4414]→[8.6653:6692](∅→∅),[8.6653]→[8.6653:6692](∅→∅),[8.6632]→[8.4388:4414](∅→∅),[8.419]→[8.6621:6632](∅→∅),[8.895]→[8.6621:6632](∅→∅),[8.100147]→[8.6621:6632](∅→∅),[8.6621]→[8.6621:6632](∅→∅),[8.312]→[8.789:895](∅→∅),[8.6468]→[8.249:312](∅→∅),[8.4387]→[8.6457:6468](∅→∅),[8.99992]→[8.6457:6468](∅→∅),[8.6457]→[8.6457:6468](∅→∅),[8.445]→[8.4361:4387](∅→∅),[8.4361]→[8.4361:4387](∅→∅),[8.544]→[8.421:445](∅→∅),[8.788]→[8.421:445](∅→∅),[8.4315]→[8.421:445](∅→∅),[8.4252]→[8.483:544](∅→∅),[8.6095]→[8.4220:4252](∅→∅),[8.64]→[8.6090:6095](∅→∅),[8.6090]→[8.6090:6095](∅→∅),[8.6090]→[8.53:64](∅→∅),[8.2101]→[8.6084:6090](∅→∅),[8.6084]→[8.6084:6090](∅→∅),[8.4219]→[8.2069:2101](∅→∅),[8.2148]→[8.4191:4219](∅→∅),[8.8245]→[8.4191:4219](∅→∅),[8.9916]→[8.4191:4219](∅→∅),[8.4191]→[8.4191:4219](∅→∅),[8.5923]→[8.2108:2148](∅→∅),[8.4060]→[8.5917:5923](∅→∅),[8.99635]→[8.5917:5923](∅→∅),[8.5917]→[8.5917:5923](∅→∅),[8.6074]→[8.9765:9790](∅→∅),[8.9765]→[8.9765:9790](∅→∅),[8.5853]→[8.6004:6074](∅→∅),[8.13]→[8.5845:5853](∅→∅),[8.1110]→[8.5845:5853](∅→∅),[8.6003]→[8.5845:5853](∅→∅),[8.9658]→[8.5845:5853](∅→∅),[8.37331]→[8.5845:5853](∅→∅),[8.5845]→[8.5845:5853](∅→∅),[8.6001]→[8.9505:9658](∅→∅),[8.37329]→[8.9505:9658](∅→∅),[8.3138]→[8.9505:9658](∅→∅),[8.3095]→[8.5964:6001](∅→∅),[8.4249]→[8.3031:3095](∅→∅),[8.3030]→[8.4205:4249](∅→∅),[8.98451]→[8.4205:4249](∅→∅),[8.4205]→[8.4205:4249](∅→∅),[8.4124]→[8.2931:3030](∅→∅),[8.1996]→[8.4101:4124](∅→∅),[8.2930]→[8.4101:4124](∅→∅),[8.22445]→[8.4101:4124](∅→∅),[8.98330]→[8.4101:4124](∅→∅),[8.4101]→[8.4101:4124](∅→∅),[8.314]→[8.22423:22445](∅→∅),[8.2901]→[8.22423:22445](∅→∅),[8.1165]→[8.268:314](∅→∅),[8.816]→[8.988:1165](∅→∅),[8.1895]→[8.988:1165](∅→∅),[8.1023]→[8.642:816](∅→∅),[8.44]→[8.999:1023](∅→∅),[8.2727]→[8.999:1023](∅→∅),[8.3913]→[8.999:1023](∅→∅),[8.52]→[8.2701:2727](∅→∅),[8.366]→[8.2701:2727](∅→∅),[8.3868]→[8.2701:2727](∅→∅),[8.366]→[8.28:52](∅→∅),[8.754]→[8.790:795](∅→∅),[8.790]→[8.790:795](∅→∅)
local screen_bottom1 = {line=nil, pos=nil}-- give some time for the OS to flush everything to disklove.timer.sleep(0.1)State.old_cursor1, State.old_selection1, State.mousepress_shift = nilif eq(State.cursor1, State.selection1) thenState.selection1 = {}endbreak--? print_and_log(('edit.mouse_release: finally selection %s,%s cursor %d,%d'):format(tostring(State.selection1.line), tostring(State.selection1.pos), State.cursor1.line, State.cursor1.pos))--? print('text input', t)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scroll-- undoendedit.draw(State)edit.update(State, 0)App.screen.contents = {}edit.mouse_release(State, x,y, mouse_button)function edit.run_after_mouse_release(State, x,y, mouse_button)App.fake_mouse_release(x,y, mouse_button)edit.draw(State)endedit.update(State, 0)App.screen.contents = {}edit.mouse_press(State, x,y, mouse_button)function edit.run_after_mouse_press(State, x,y, mouse_button)App.fake_mouse_press(x,y, mouse_button)edit.draw(State)endedit.update(State, 0)App.screen.contents = {}edit.mouse_release(State, x,y, mouse_button)App.fake_mouse_release(x,y, mouse_button)edit.mouse_press(State, x,y, mouse_button)function edit.run_after_mouse_click(State, x,y, mouse_button)App.fake_mouse_press(x,y, mouse_button)edit.draw(State)endedit.update(State, 0)App.screen.contents = {}edit.keychord_press(State, chord)edit.key_release(State, chord)function edit.run_after_keychord(State, chord)-- not all keys are text_inputendedit.draw(State)edit.update(State, 0)App.screen.contents = {}function edit.run_after_text_input(State, t)edit.keychord_press(State, t)edit.text_input(State, t)edit.key_release(State, t)-- TODO: handle chords of multiple keys-- all text_input events are also keypresses14, -- font height assuming default LÖVE font15) -- line heightendApp.screen.width - Test_margin_right,function edit.initialize_test_state()-- if you change these values, tests will start failingreturn edit.initialize_state(15, -- top marginTest_margin_left,Test_margin_right = 0Test_margin_left = 25-- 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.--== some methods for testsendState.line_height = math.floor(font_height*1.3)love.graphics.setFont(love.graphics.newFont(State.font_height))function edit.update_font_settings(State, font_height)State.font_height = font_heightendfunction edit.key_release(State, key, scancode)endendText.keychord_press(State, chord)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollelse-- dispatch to textrecord_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor1.line)})schedule_save(State)endText.snap_cursor_to_bottom_of_screen(State, State.left, State.right)if Text.cursor_out_of_screen(State) thenendendText.insert_at_cursor(State, c)elseText.insert_return(State)for _,code in utf8.codes(clipboard_data) dolocal c = utf8.char(code)if c == '\n' thenlocal clipboard_data = App.get_clipboard()local before = snapshot(State, before_line)local before_line = State.cursor1.line-- 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.for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollelseif chord == 'C-v' thenschedule_save(State)endApp.set_clipboard(s)if s thenlocal s = Text.cut_selection(State, State.left, State.right)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollendelseif chord == 'C-x' thenApp.set_clipboard(s)if s thenlocal s = Text.selection(State)elseif chord == 'C-c' thenelseif chord == 'C-a' thenState.selection1 = {line=1, pos=1}State.cursor1 = {line=#State.lines, pos=utf8.len(State.lines[#State.lines].data)+1}end-- clipboardschedule_save(State)-- if we're scrolling, reclaim all fragments to avoid memory leaksText.redraw_all(State)State.screen_top1 = deepcopy(src.screen_top)State.cursor1 = deepcopy(src.cursor)State.selection1 = deepcopy(src.selection)patch(State.lines, event.before, event.after)if event thenlocal src = event.afterlocal event = redo_event(State)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollendelseif chord == 'C-y' thenschedule_save(State)-- if we're scrolling, reclaim all fragments to avoid memory leaksText.redraw_all(State)patch_placeholders(State.line_cache, event.after, event.before)State.screen_top1 = deepcopy(src.screen_top)State.cursor1 = deepcopy(src.cursor)State.selection1 = deepcopy(src.selection)patch(State.lines, event.after, event.before)if event thenlocal src = event.beforelocal event = undo_event(State)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollelseif chord == 'C-z' thenText.redraw_all(State)edit.update_font_settings(State, 20)elseif chord == 'C-0' thenif State.font_height > 2 thenedit.update_font_settings(State, State.font_height-2)Text.redraw_all(State)endelseif chord == 'C--' thenText.redraw_all(State)edit.update_font_settings(State, State.font_height+2)elseif chord == 'C-=' then-- zoomState.search_backup = {cursor={line=State.cursor1.line, pos=State.cursor1.pos},screen_top={line=State.screen_top1.line, pos=State.screen_top1.pos},}State.search_term = ''endreturnelseif chord == 'C-f' thenText.search_previous(State)elseif chord == 'up' thenText.search_next(State)State.cursor1.pos = State.cursor1.pos+1elseif chord == 'down' 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 == 'backspace' thenState.search_backup = nilState.search_term = nilelseif chord == 'return' thenText.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leaksState.cursor1 = State.search_backup.cursorState.screen_top1 = State.search_backup.screen_topState.search_backup = nilState.search_term = nilif chord == 'escape' thenif State.search_term thenendText.delete_selection(State, State.left, State.right)chord ~= 'C-a' and chord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and chord ~= 'delete' and chord ~= 'C-z' and chord ~= 'C-y' and not App.is_cursor_movement(chord) then-- printable character created using shift key => delete selection-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)(not App.shift_down() or utf8.len(key) == 1) andif State.selection1.line andfunction edit.keychord_press(State, chord, key)endschedule_save(State)endText.text_input(State, t)for _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollelseText.search_next(State)if State.search_term thenState.search_term = State.search_term..tfunction edit.text_input(State, t)endendfor i=1,math.floor(-dy) doText.down(State)endedit.put_cursor_on_next_text_line(State)State.cursor1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}elseif dy < 0 thenfor i=1,math.floor(dy) doText.up(State)endedit.put_cursor_on_next_text_line(State)endfunction edit.mouse_wheel_move(State, dx,dy)if dy > 0 thenState.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}endendendendif State.mousepress_shift thenif State.old_selection1.line == nil thenState.selection1 = State.old_cursor1elseState.selection1 = State.old_selection1--? print_and_log(('edit.mouse_release: cursor now %d,%d'):format(State.cursor1.line, State.cursor1.pos))State.cursor1 = {line=line_index,pos=Text.to_pos_on_line(State, line_index, x, y),}--? print_and_log(('edit.mouse_release: in line %d'):format(line_index))for line_index,line in ipairs(State.lines) doif Text.in_line(State, line_index, x,y) then--? print_and_log(('edit.mouse_release(%d,%d): cursor at %d,%d'):format(x,y, State.cursor1.line, State.cursor1.pos))if State.search_term then return endfunction edit.mouse_release(State, x,y, mouse_button)end-- still here? click is below all screen linesState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {line=State.screen_bottom1.line,pos=Text.pos_at_end_of_screen_line(State, State.screen_bottom1),}endendreturnState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {line=line_index,pos=Text.to_pos_on_line(State, line_index, x, y),}-- i.e. mouse_release should never look at shift state--? print_and_log(('edit.mouse_press: in line %d'):format(line_index))if Text.in_line(State, line_index, x,y) then-- delicate dance between cursor, selection and old cursor/selection-- scenarios:-- regular press+release: sets cursor, clears selection-- shift press+release:-- sets selection to old cursor if not set otherwise leaves it untouched-- sets cursor-- press and hold to start a selection: sets selection on press, cursor on release-- press and hold, then press shift: ignore shiftfor line_index,line in ipairs(State.lines) do}returnendline=State.screen_top1.line,pos=State.screen_top1.pos,if y < State.top thenState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {--? print_and_log(('edit.mouse_press: cursor at %d,%d'):format(State.cursor1.line, State.cursor1.pos))if State.search_term then return endfunction edit.mouse_press(State, x,y, mouse_button)endendsave_to_disk(State)if State.next_save then-- make sure to save before quittingfunction edit.quit(State)endendState.next_save = Current_time + 3 -- short enough that you're likely to still remember what you didfunction schedule_save(State)if State.next_save == nil thenendendState.next_save = nilsave_to_disk(State)if State.next_save and State.next_save < Current_time thenfunction edit.update(State, dt)endreturn yendText.draw_search_bar(State)if State.search_term thenState.screen_bottom1 = screen_bottom1end--? print('=> y', y)y, screen_bottom1.pos = Text.draw(State, line_index, y, startpos)end--? print('text.draw', y, line_index)local startpos = 1if line_index == State.screen_top1.line thenstartpos = State.screen_top1.posscreen_bottom1.line = line_indexif y + State.line_height > App.screen.height then break end--? print('draw:', y, line_index, line)for line_index = State.screen_top1.line,#State.lines dolocal line = State.lines[line_index]--? print('== draw')local y = State.topState.cursor_x = nilState.cursor_y = nilif not Text.le1(State.screen_top1, State.cursor1) thenprint(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)assert(false)endif #State.lines ~= #State.line_cache thenprint(('line_cache is out of date; %d when it should be %d'):format(#State.line_cache, #State.lines))assert(false)endApp.color(Text_color)function edit.draw(State)-- return y drawn untilend[8.754]end-- return y drawn untilfunction edit.draw(State)App.color(Text_color)if #State.lines ~= #State.line_cache thenprint(('line_cache is out of date; %d when it should be %d'):format(#State.line_cache, #State.lines))assert(false)endif not Text.le1(State.screen_top1, State.cursor1) thenprint(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)assert(false)endState.cursor_x = nilState.cursor_y = nillocal y = State.toplocal screen_bottom1 = {line=nil, pos=nil}--? print('== draw')for line_index = State.screen_top1.line,#State.lines dolocal line = State.lines[line_index]--? print('draw:', y, line_index, line)if y + State.line_height > App.screen.height then break endscreen_bottom1.line = line_index--? print('text.draw', y, line_index)local startpos = 1if line_index == State.screen_top1.line thenstartpos = State.screen_top1.posendy, screen_bottom1.pos = Text.draw(State, line_index, y, startpos)--? print('=> y', y)endState.screen_bottom1 = screen_bottom1if State.search_term thenText.draw_search_bar(State)endreturn yendfunction edit.update(State, dt)if State.next_save and State.next_save < Current_time thensave_to_disk(State)State.next_save = nilendendfunction schedule_save(State)if State.next_save == nil thenState.next_save = Current_time + 3 -- short enough that you're likely to still remember what you didendendfunction edit.quit(State)-- make sure to save before quittingif State.next_save thensave_to_disk(State)-- give some time for the OS to flush everything to disklove.timer.sleep(0.1)endendfunction edit.mouse_press(State, x,y, mouse_button)if State.search_term then return end--? print_and_log(('edit.mouse_press: cursor at %d,%d'):format(State.cursor1.line, State.cursor1.pos))if y < State.top thenState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {line=State.screen_top1.line,pos=State.screen_top1.pos,}returnendfor line_index,line in ipairs(State.lines) doif Text.in_line(State, line_index, x,y) then-- delicate dance between cursor, selection and old cursor/selection-- scenarios:-- regular press+release: sets cursor, clears selection-- shift press+release:-- sets selection to old cursor if not set otherwise leaves it untouched-- sets cursor-- press and hold to start a selection: sets selection on press, cursor on release-- press and hold, then press shift: ignore shift-- i.e. mouse_release should never look at shift state--? print_and_log(('edit.mouse_press: in line %d'):format(line_index))State.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {line=line_index,pos=Text.to_pos_on_line(State, line_index, x, y),}returnendend-- still here? click is below all screen linesState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()State.selection1 = {line=State.screen_bottom1.line,pos=Text.pos_at_end_of_screen_line(State, State.screen_bottom1),}endfunction edit.mouse_release(State, x,y, mouse_button)if State.search_term then return end--? print_and_log(('edit.mouse_release(%d,%d): cursor at %d,%d'):format(x,y, State.cursor1.line, State.cursor1.pos))for line_index,line in ipairs(State.lines) doif Text.in_line(State, line_index, x,y) then--? print_and_log(('edit.mouse_release: in line %d'):format(line_index))State.cursor1 = {line=line_index,pos=Text.to_pos_on_line(State, line_index, x, y),}--? print_and_log(('edit.mouse_release: cursor now %d,%d'):format(State.cursor1.line, State.cursor1.pos))if State.mousepress_shift thenif State.old_selection1.line == nil thenState.selection1 = State.old_cursor1elseState.selection1 = State.old_selection1endendState.old_cursor1, State.old_selection1, State.mousepress_shift = nilif eq(State.cursor1, State.selection1) thenState.selection1 = {}endbreakendend--? print_and_log(('edit.mouse_release: finally selection %s,%s cursor %d,%d'):format(tostring(State.selection1.line), tostring(State.selection1.pos), State.cursor1.line, State.cursor1.pos))endfunction edit.mouse_wheel_move(State, dx,dy)if dy > 0 thenState.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}for i=1,math.floor(dy) doText.up(State)endelseif dy < 0 thenState.cursor1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}for i=1,math.floor(-dy) doText.down(State)endendendfunction edit.text_input(State, t)--? print('text input', t)if State.search_term thenState.search_term = State.search_term..tText.search_next(State)elsefor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrollText.text_input(State, t)endschedule_save(State)endfunction edit.keychord_press(State, chord, key)if State.selection1.line and-- printable character created using shift key => delete selection-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)(not App.shift_down() or utf8.len(key) == 1) andchord ~= 'C-a' and chord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and chord ~= 'delete' and chord ~= 'C-z' and chord ~= 'C-y' and not App.is_cursor_movement(chord) thenText.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' thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrolllocal 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' thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrolllocal 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' thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrolllocal s = Text.cut_selection(State, State.left, State.right)if s thenApp.set_clipboard(s)endschedule_save(State)elseif chord == 'C-v' thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scroll-- 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_heightlove.graphics.setFont(love.graphics.newFont(State.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,14, -- font height assuming default LÖVE font15) -- 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_inputfunction edit.run_after_keychord(State, chord)edit.keychord_press(State, chord)edit.key_release(State, chord)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