vterm_spec.lua 98 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592
  1. local t = require('test.unit.testutil')
  2. local itp = t.gen_itp(it)
  3. local bit = require('bit')
  4. --- @class vterm
  5. --- @field ENC_UTF8 integer
  6. --- @field VTERM_ATTR_BLINK integer
  7. --- @field VTERM_ATTR_BOLD integer
  8. --- @field VTERM_ATTR_FONT integer
  9. --- @field VTERM_ATTR_ITALIC integer
  10. --- @field VTERM_ATTR_REVERSE integer
  11. --- @field VTERM_ATTR_UNDERLINE integer
  12. --- @field VTERM_BASELINE_RAISE integer
  13. --- @field VTERM_KEY_ENTER integer
  14. --- @field VTERM_KEY_FUNCTION_0 integer
  15. --- @field VTERM_KEY_KP_0 integer
  16. --- @field VTERM_KEY_NONE integer
  17. --- @field VTERM_KEY_TAB integer
  18. --- @field VTERM_KEY_UP integer
  19. --- @field VTERM_MAX_CHARS_PER_CELL integer
  20. --- @field VTERM_MOD_ALT integer
  21. --- @field VTERM_MOD_CTRL integer
  22. --- @field VTERM_MOD_SHIFT integer
  23. --- @field parser_apc function
  24. --- @field parser_csi function
  25. --- @field parser_dcs function
  26. --- @field parser_osc function
  27. --- @field parser_pm function
  28. --- @field parser_sos function
  29. --- @field parser_text function
  30. --- @field print_color function
  31. --- @field screen_sb_clear function
  32. --- @field screen_sb_popline function
  33. --- @field screen_sb_pushline function
  34. --- @field selection_query function
  35. --- @field selection_set function
  36. --- @field state_erase function
  37. --- @field state_movecursor function
  38. --- @field state_moverect function
  39. --- @field state_pos function
  40. --- @field state_putglyph function
  41. --- @field state_sb_clear function
  42. --- @field state_scrollrect function
  43. --- @field state_setpenattr function
  44. --- @field state_settermprop function
  45. --- @field term_output function
  46. --- @field vterm_input_write function
  47. --- @field vterm_keyboard_end_paste function
  48. --- @field vterm_keyboard_key function
  49. --- @field vterm_keyboard_start_paste function
  50. --- @field vterm_keyboard_unichar function
  51. --- @field vterm_lookup_encoding fun(any, any):any
  52. --- @field vterm_mouse_button function
  53. --- @field vterm_mouse_move function
  54. --- @field vterm_new fun(any, any):any
  55. --- @field vterm_obtain_screen fun(any):any
  56. --- @field vterm_obtain_state fun(any): any
  57. --- @field vterm_output_set_callback function
  58. --- @field vterm_parser_set_callbacks fun(any, any, any):any
  59. --- @field vterm_screen_convert_color_to_rgb function
  60. --- @field vterm_screen_enable_altscreen function
  61. --- @field vterm_screen_enable_reflow function
  62. --- @field vterm_screen_get_attrs_extent function
  63. --- @field vterm_screen_get_cell function
  64. --- @field vterm_screen_get_chars fun(any, any, any, any):any
  65. --- @field vterm_screen_get_text fun(any, any, any, any):any
  66. --- @field vterm_screen_is_eol fun(any, any):any
  67. --- @field vterm_screen_reset function
  68. --- @field vterm_screen_set_callbacks function
  69. --- @field vterm_set_size function
  70. --- @field vterm_set_utf8 fun(any, any, any):any
  71. --- @field vterm_state_focus_in function
  72. --- @field vterm_state_focus_out function
  73. --- @field vterm_state_get_cursorpos fun(any, any)
  74. --- @field vterm_state_get_lineinfo fun(any, any):any
  75. --- @field vterm_state_get_penattr function
  76. --- @field vterm_state_reset function
  77. --- @field vterm_state_set_bold_highbright function
  78. --- @field vterm_state_set_callbacks function
  79. --- @field vterm_state_set_selection_callbacks function
  80. --- @field vterm_state_set_unrecognised_fallbacks function
  81. local vterm = t.cimport('./src/vterm/vterm.h', './src/vterm/vterm_internal.h')
  82. --- @return string
  83. local function read_rm()
  84. local f = assert(io.open(t.paths.vterm_test_file, 'rb'))
  85. local text = f:read('*a')
  86. f:close()
  87. vim.fs.rm(t.paths.vterm_test_file, { force = true })
  88. return text
  89. end
  90. local function append(str)
  91. local f = assert(io.open(t.paths.vterm_test_file, 'a'))
  92. f:write(str)
  93. f:close()
  94. return 1
  95. end
  96. local function parser_control(control)
  97. return append(string.format('control %02x\n', control))
  98. end
  99. local function parser_escape(bytes)
  100. return append(string.format('escape %s\n', t.ffi.string(bytes)))
  101. end
  102. local function wantparser(vt)
  103. assert(vt)
  104. local parser_cbs = t.ffi.new('VTermParserCallbacks')
  105. parser_cbs['text'] = vterm.parser_text
  106. parser_cbs['control'] = parser_control
  107. parser_cbs['escape'] = parser_escape
  108. parser_cbs['csi'] = vterm.parser_csi
  109. parser_cbs['osc'] = vterm.parser_osc
  110. parser_cbs['dcs'] = vterm.parser_dcs
  111. parser_cbs['apc'] = vterm.parser_apc
  112. parser_cbs['pm'] = vterm.parser_pm
  113. parser_cbs['sos'] = vterm.parser_sos
  114. vterm.vterm_parser_set_callbacks(vt, parser_cbs, nil)
  115. end
  116. --- @return any
  117. local function init()
  118. local vt = vterm.vterm_new(25, 80)
  119. vterm.vterm_output_set_callback(vt, vterm.term_output, nil)
  120. vterm.vterm_set_utf8(vt, true)
  121. return vt
  122. end
  123. local function state_setlineinfo()
  124. return 1
  125. end
  126. --- @return any
  127. local function wantstate(vt, opts)
  128. opts = opts or {}
  129. assert(vt)
  130. local state = vterm.vterm_obtain_state(vt)
  131. local state_cbs = t.ffi.new('VTermStateCallbacks')
  132. state_cbs['putglyph'] = vterm.state_putglyph
  133. state_cbs['movecursor'] = vterm.state_movecursor
  134. state_cbs['scrollrect'] = vterm.state_scrollrect
  135. state_cbs['moverect'] = vterm.state_moverect
  136. state_cbs['erase'] = vterm.state_erase
  137. state_cbs['setpenattr'] = vterm.state_setpenattr
  138. state_cbs['settermprop'] = vterm.state_settermprop
  139. state_cbs['setlineinfo'] = state_setlineinfo
  140. state_cbs['sb_clear'] = vterm.state_sb_clear
  141. local selection_cbs = t.ffi.new('VTermSelectionCallbacks')
  142. selection_cbs['set'] = vterm.selection_set
  143. selection_cbs['query'] = vterm.selection_query
  144. vterm.vterm_state_set_callbacks(state, state_cbs, nil)
  145. -- In some tests we want to check the behaviour of overflowing the buffer, so make it nicely small
  146. vterm.vterm_state_set_selection_callbacks(state, selection_cbs, nil, nil, 16)
  147. vterm.vterm_state_set_bold_highbright(state, 1)
  148. vterm.vterm_state_reset(state, 1)
  149. local fallbacks = t.ffi.new('VTermStateFallbacks')
  150. fallbacks['control'] = parser_control
  151. fallbacks['csi'] = vterm.parser_csi
  152. fallbacks['osc'] = vterm.parser_osc
  153. fallbacks['dcs'] = vterm.parser_dcs
  154. fallbacks['apc'] = vterm.parser_apc
  155. fallbacks['pm'] = vterm.parser_pm
  156. fallbacks['sos'] = vterm.parser_sos
  157. vterm.want_state_scrollback = opts.b or false
  158. vterm.want_state_erase = opts.e or false
  159. vterm.vterm_state_set_unrecognised_fallbacks(state, opts.f and fallbacks or nil, nil)
  160. vterm.want_state_putglyph = opts.g or false
  161. vterm.want_state_moverect = opts.m or false
  162. vterm.want_state_settermprop = opts.p or false
  163. vterm.want_state_scrollrect = opts.s or false
  164. return state
  165. end
  166. --- @return any
  167. local function wantscreen(vt, opts)
  168. opts = opts or {}
  169. local screen = vterm.vterm_obtain_screen(vt)
  170. local screen_cbs = t.ffi.new('VTermScreenCallbacks')
  171. -- TODO(dundargoc): fix
  172. -- screen_cbs['damage'] = vterm.screen_damage
  173. screen_cbs['moverect'] = vterm.state_moverect
  174. screen_cbs['movecursor'] = vterm.state_movecursor
  175. screen_cbs['settermprop'] = vterm.state_settermprop
  176. screen_cbs['sb_pushline'] = vterm.screen_sb_pushline
  177. screen_cbs['sb_popline'] = vterm.screen_sb_popline
  178. screen_cbs['sb_clear'] = vterm.screen_sb_clear
  179. vterm.vterm_screen_set_callbacks(screen, screen_cbs, nil)
  180. if opts.a then
  181. vterm.vterm_screen_enable_altscreen(screen, 1)
  182. end
  183. vterm.want_screen_scrollback = opts.b or false
  184. vterm.want_state_movecursor = opts.c or false
  185. -- TODO(dundargoc): fix
  186. -- vterm.want_screen_damage = opts.d or opts.D or false
  187. -- vterm.want_screen_cells = opts.D or false
  188. vterm.want_state_moverect = opts.m or false
  189. vterm.want_state_settermprop = opts.p or false
  190. if opts.r then
  191. vterm.vterm_screen_enable_reflow(screen, true)
  192. end
  193. return screen
  194. end
  195. local function reset(state, screen)
  196. if state then
  197. vterm.vterm_state_reset(state, 1)
  198. vterm.vterm_state_get_cursorpos(state, vterm.state_pos)
  199. end
  200. if screen then
  201. vterm.vterm_screen_reset(screen, 1)
  202. end
  203. end
  204. local function push(input, vt)
  205. vterm.vterm_input_write(vt, input, string.len(input))
  206. end
  207. local function expect(expected)
  208. local actual = read_rm()
  209. t.eq(expected .. '\n', actual)
  210. end
  211. local function expect_output(expected_preformat)
  212. local actual = read_rm()
  213. local expected = 'output '
  214. for c in string.gmatch(expected_preformat, '.') do
  215. if expected ~= 'output ' then
  216. expected = expected .. ','
  217. end
  218. expected = string.format('%s%x', expected, string.byte(c))
  219. end
  220. t.eq(expected .. '\n', actual)
  221. end
  222. local function cursor(row, col, state)
  223. local pos = t.ffi.new('VTermPos') --- @type {row: integer, col: integer}
  224. vterm.vterm_state_get_cursorpos(state, pos)
  225. t.eq(row, pos.row)
  226. t.eq(col, pos.col)
  227. end
  228. local function lineinfo(row, expected, state)
  229. local info = vterm.vterm_state_get_lineinfo(state, row)
  230. local dwl = info.doublewidth == 1
  231. local dhl = info.doubleheight == 1
  232. local cont = info.continuation == 1
  233. t.eq(dwl, expected.dwl or false)
  234. t.eq(dhl, expected.dhl or false)
  235. t.eq(cont, expected.cont or false)
  236. end
  237. local function pen(attribute, expected, state)
  238. local is_bool = { bold = true, italic = true, blink = true, reverse = true }
  239. local vterm_attribute = {
  240. bold = vterm.VTERM_ATTR_BOLD,
  241. underline = vterm.VTERM_ATTR_UNDERLINE,
  242. italic = vterm.VTERM_ATTR_ITALIC,
  243. blink = vterm.VTERM_ATTR_BLINK,
  244. reverse = vterm.VTERM_ATTR_REVERSE,
  245. font = vterm.VTERM_ATTR_FONT,
  246. }
  247. local val = t.ffi.new('VTermValue') --- @type {boolean: integer}
  248. vterm.vterm_state_get_penattr(state, vterm_attribute[attribute], val)
  249. local actual = val.boolean --- @type integer|boolean
  250. if is_bool[attribute] then
  251. actual = val.boolean == 1
  252. end
  253. t.eq(expected, actual)
  254. end
  255. local function resize(rows, cols, vt)
  256. vterm.vterm_set_size(vt, rows, cols)
  257. end
  258. local function screen_chars(start_row, start_col, end_row, end_col, expected, screen)
  259. local rect = t.ffi.new('VTermRect')
  260. rect['start_row'] = start_row
  261. rect['start_col'] = start_col
  262. rect['end_row'] = end_row
  263. rect['end_col'] = end_col
  264. local len = vterm.vterm_screen_get_chars(screen, nil, 0, rect)
  265. local chars = t.ffi.new('uint32_t[?]', len)
  266. vterm.vterm_screen_get_chars(screen, chars, len, rect)
  267. local actual = ''
  268. for i = 0, tonumber(len) - 1 do
  269. actual = actual .. string.char(chars[i])
  270. end
  271. t.eq(expected, actual)
  272. end
  273. local function screen_text(start_row, start_col, end_row, end_col, expected, screen)
  274. local rect = t.ffi.new('VTermRect')
  275. rect['start_row'] = start_row
  276. rect['start_col'] = start_col
  277. rect['end_row'] = end_row
  278. rect['end_col'] = end_col
  279. local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
  280. local text = t.ffi.new('unsigned char[?]', len)
  281. vterm.vterm_screen_get_text(screen, text, len, rect)
  282. local actual = ''
  283. for i = 0, tonumber(len) - 1 do
  284. actual = string.format('%s%02x,', actual, text[i])
  285. end
  286. actual = actual:sub(1, -2)
  287. t.eq(expected, actual)
  288. end
  289. --- @param row integer
  290. local function screen_row(row, expected, screen, end_col)
  291. local rect = t.ffi.new('VTermRect')
  292. rect['start_row'] = row
  293. rect['start_col'] = 0
  294. rect['end_row'] = row + 1
  295. rect['end_col'] = end_col or 80
  296. local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
  297. local text = t.ffi.new('unsigned char[?]', len)
  298. vterm.vterm_screen_get_text(screen, text, len, rect)
  299. t.eq(expected, t.ffi.string(text))
  300. end
  301. local function screen_cell(row, col, expected, screen)
  302. local pos = t.ffi.new('VTermPos')
  303. pos['row'] = row
  304. pos['col'] = col
  305. local cell = t.ffi.new('VTermScreenCell')
  306. vterm.vterm_screen_get_cell(screen, pos, cell)
  307. local actual = '{'
  308. for i = 0, vterm.VTERM_MAX_CHARS_PER_CELL - 1 do
  309. if cell['chars'][i] ~= 0 then
  310. if i > 0 then
  311. actual = actual .. ','
  312. end
  313. actual = string.format('%s%02x', actual, cell['chars'][i])
  314. end
  315. end
  316. actual = string.format('%s} width=%d attrs={', actual, cell['width'])
  317. actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '')
  318. actual = actual
  319. .. (cell['attrs'].underline ~= 0 and string.format('U%d', cell['attrs'].underline) or '')
  320. actual = actual .. (cell['attrs'].italic ~= 0 and 'I' or '')
  321. actual = actual .. (cell['attrs'].blink ~= 0 and 'K' or '')
  322. actual = actual .. (cell['attrs'].reverse ~= 0 and 'R' or '')
  323. actual = actual .. (cell['attrs'].font ~= 0 and string.format('F%d', cell['attrs'].font) or '')
  324. actual = actual .. (cell['attrs'].small ~= 0 and 'S' or '')
  325. if cell['attrs'].baseline ~= 0 then
  326. actual = actual .. (cell['attrs'].baseline == vterm.VTERM_BASELINE_RAISE and '^' or '_')
  327. end
  328. actual = actual .. '} '
  329. actual = actual .. (cell['attrs'].dwl ~= 0 and 'dwl ' or '')
  330. if cell['attrs'].dhl ~= 0 then
  331. actual = actual .. string.format('dhl-%s ', cell['attrs'].dhl == 2 and 'bottom' or 'top')
  332. end
  333. actual = string.format('%sfg=', actual)
  334. vterm.vterm_screen_convert_color_to_rgb(screen, cell['fg'])
  335. vterm.print_color(cell['fg'])
  336. actual = actual .. read_rm()
  337. actual = actual .. ' bg='
  338. vterm.vterm_screen_convert_color_to_rgb(screen, cell['bg'])
  339. vterm.print_color(cell['bg'])
  340. actual = actual .. read_rm()
  341. t.eq(expected, actual)
  342. end
  343. local function screen_eol(row, col, expected, screen)
  344. local pos = t.ffi.new('VTermPos')
  345. pos['row'] = row
  346. pos['col'] = col
  347. local is_eol = vterm.vterm_screen_is_eol(screen, pos)
  348. t.eq(expected, is_eol)
  349. end
  350. local function screen_attrs_extent(row, col, expected, screen)
  351. local pos = t.ffi.new('VTermPos')
  352. pos['row'] = row
  353. pos['col'] = col
  354. local rect = t.ffi.new('VTermRect')
  355. rect['start_col'] = 0
  356. rect['end_col'] = -1
  357. vterm.vterm_screen_get_attrs_extent(screen, rect, pos, 1)
  358. local actual = string.format(
  359. '%d,%d-%d,%d',
  360. rect['start_row'],
  361. rect['start_col'],
  362. rect['end_row'],
  363. rect['end_col']
  364. )
  365. t.eq(expected, actual)
  366. end
  367. local function wantencoding()
  368. local encoding = t.ffi.new('VTermEncodingInstance')
  369. encoding['enc'] = vterm.vterm_lookup_encoding(vterm.ENC_UTF8, string.byte('u'))
  370. if encoding.enc.init then
  371. encoding.enc.init(encoding.enc, encoding['data'])
  372. end
  373. return encoding
  374. end
  375. local function encin(input, encoding)
  376. local len = string.len(input)
  377. local cp = t.ffi.new('uint32_t[?]', len)
  378. local cpi = t.ffi.new('int[1]')
  379. local pos = t.ffi.new('size_t[1]', 0)
  380. encoding.enc.decode(encoding.enc, encoding.data, cp, cpi, len, input, pos, len)
  381. local f = assert(io.open(t.paths.vterm_test_file, 'w'))
  382. if tonumber(cpi[0]) > 0 then
  383. f:write('encout ')
  384. for i = 0, cpi[0] - 1 do
  385. if i == 0 then
  386. f:write(string.format('%x', cp[i]))
  387. else
  388. f:write(string.format(',%x', cp[i]))
  389. end
  390. end
  391. f:write('\n')
  392. end
  393. f:close()
  394. end
  395. local function strpe_modifiers(input_mod)
  396. local mod = t.ffi.new('VTermModifier') ---@type any
  397. if input_mod.C then
  398. mod = bit.bor(mod, vterm.VTERM_MOD_CTRL)
  399. end
  400. if input_mod.S then
  401. mod = bit.bor(mod, vterm.VTERM_MOD_SHIFT)
  402. end
  403. if input_mod.A then
  404. mod = bit.bor(mod, vterm.VTERM_MOD_ALT)
  405. end
  406. return mod
  407. end
  408. local function strp_key(input_key)
  409. if input_key == 'up' then
  410. return vterm.VTERM_KEY_UP
  411. end
  412. if input_key == 'tab' then
  413. return vterm.VTERM_KEY_TAB
  414. end
  415. if input_key == 'enter' then
  416. return vterm.VTERM_KEY_ENTER
  417. end
  418. if input_key == 'f1' then
  419. return vterm.VTERM_KEY_FUNCTION_0 + 1
  420. end
  421. if input_key == 'kp0' then
  422. return vterm.VTERM_KEY_KP_0
  423. end
  424. return vterm.VTERM_KEY_NONE
  425. end
  426. local function mousemove(row, col, vt, input_mod)
  427. input_mod = input_mod or {}
  428. local mod = strpe_modifiers(input_mod)
  429. vterm.vterm_mouse_move(vt, row, col, mod)
  430. end
  431. local function mousebtn(press, button, vt, input_mod)
  432. input_mod = input_mod or {}
  433. local mod = strpe_modifiers(input_mod)
  434. local flag = press == 'd' or press == 'D'
  435. vterm.vterm_mouse_button(vt, button, flag, mod)
  436. end
  437. local function inchar(c, vt, input_mod)
  438. input_mod = input_mod or {}
  439. local mod = strpe_modifiers(input_mod)
  440. vterm.vterm_keyboard_unichar(vt, c, mod)
  441. end
  442. local function inkey(input_key, vt, input_mod)
  443. input_mod = input_mod or {}
  444. local mod = strpe_modifiers(input_mod)
  445. local key = strp_key(input_key)
  446. vterm.vterm_keyboard_key(vt, key, mod)
  447. end
  448. before_each(function()
  449. vim.fs.rm(t.paths.vterm_test_file, { force = true })
  450. end)
  451. describe('vterm', function()
  452. itp('02parser', function()
  453. local vt = init()
  454. vterm.vterm_set_utf8(vt, false)
  455. wantparser(vt)
  456. -- Basic text
  457. push('hello', vt)
  458. expect('text 68,65,6c,6c,6f')
  459. -- C0
  460. push('\x03', vt)
  461. expect('control 03')
  462. push('\x1f', vt)
  463. expect('control 1f')
  464. -- C1 8bit
  465. push('\x83', vt)
  466. expect('control 83')
  467. push('\x99', vt)
  468. expect('control 99')
  469. -- C1 7bit
  470. push('\x1b\x43', vt)
  471. expect('control 83')
  472. push('\x1b\x59', vt)
  473. expect('control 99')
  474. -- High bytes
  475. push('\xa0\xcc\xfe', vt)
  476. expect('text a0,cc,fe')
  477. -- Mixed
  478. push('1\n2', vt)
  479. expect('text 31\ncontrol 0a\ntext 32')
  480. -- Escape
  481. push('\x1b=', vt)
  482. expect('escape =')
  483. -- Escape 2-byte
  484. push('\x1b(X', vt)
  485. expect('escape (X')
  486. -- Split write Escape
  487. push('\x1b(', vt)
  488. push('Y', vt)
  489. expect('escape (Y')
  490. -- Escape cancels Escape, starts another
  491. push('\x1b(\x1b)Z', vt)
  492. expect('escape )Z')
  493. -- CAN cancels Escape, returns to normal mode
  494. push('\x1b(\x18AB', vt)
  495. expect('text 41,42')
  496. -- C0 in Escape interrupts and continues
  497. push('\x1b(\nX', vt)
  498. expect('control 0a\nescape (X')
  499. -- CSI 0 args
  500. push('\x1b[a', vt)
  501. expect('csi 61 *')
  502. -- CSI 1 arg
  503. push('\x1b[9b', vt)
  504. expect('csi 62 9')
  505. -- CSI 2 args
  506. push('\x1b[3;4c', vt)
  507. expect('csi 63 3,4')
  508. -- CSI 1 arg 1 sub
  509. push('\x1b[1:2c', vt)
  510. expect('csi 63 1+,2')
  511. -- CSI many digits
  512. push('\x1b[678d', vt)
  513. expect('csi 64 678')
  514. -- CSI leading zero
  515. push('\x1b[007e', vt)
  516. expect('csi 65 7')
  517. -- CSI qmark
  518. push('\x1b[?2;7f', vt)
  519. expect('csi 66 L=3f 2,7')
  520. -- CSI greater
  521. push('\x1b[>c', vt)
  522. expect('csi 63 L=3e *')
  523. -- CSI SP
  524. push('\x1b[12 q', vt)
  525. expect('csi 71 12 I=20')
  526. -- Mixed CSI
  527. push('A\x1b[8mB', vt)
  528. expect('text 41\ncsi 6d 8\ntext 42')
  529. -- Split write
  530. push('\x1b', vt)
  531. push('[a', vt)
  532. expect('csi 61 *')
  533. push('foo\x1b[', vt)
  534. expect('text 66,6f,6f')
  535. push('4b', vt)
  536. expect('csi 62 4')
  537. push('\x1b[12;', vt)
  538. push('3c', vt)
  539. expect('csi 63 12,3')
  540. -- Escape cancels CSI, starts Escape
  541. push('\x1b[123\x1b9', vt)
  542. expect('escape 9')
  543. -- CAN cancels CSI, returns to normal mode
  544. push('\x1b[12\x18AB', vt)
  545. expect('text 41,42')
  546. -- C0 in Escape interrupts and continues
  547. push('\x1b(\nX', vt)
  548. expect('control 0a\nescape (X')
  549. -- OSC BEL
  550. push('\x1b]1;Hello\x07', vt)
  551. expect('osc [1;Hello]')
  552. -- OSC ST (7bit)
  553. push('\x1b]1;Hello\x1b\\', vt)
  554. expect('osc [1;Hello]')
  555. -- OSC ST (8bit)
  556. push('\x9d1;Hello\x9c', vt)
  557. expect('osc [1;Hello]')
  558. -- OSC in parts
  559. push('\x1b]52;abc', vt)
  560. expect('osc [52;abc')
  561. push('def', vt)
  562. expect('osc def')
  563. push('ghi\x1b\\', vt)
  564. expect('osc ghi]')
  565. -- OSC BEL without semicolon
  566. push('\x1b]1234\x07', vt)
  567. expect('osc [1234;]')
  568. -- OSC ST without semicolon
  569. push('\x1b]1234\x1b\\', vt)
  570. expect('osc [1234;]')
  571. -- Escape cancels OSC, starts Escape
  572. push('\x1b]Something\x1b9', vt)
  573. expect('escape 9')
  574. -- CAN cancels OSC, returns to normal mode
  575. push('\x1b]12\x18AB', vt)
  576. expect('text 41,42')
  577. -- C0 in OSC interrupts and continues
  578. push('\x1b]2;\nBye\x07', vt)
  579. expect('osc [2;\ncontrol 0a\nosc Bye]')
  580. -- DCS BEL
  581. push('\x1bPHello\x07', vt)
  582. expect('dcs [Hello]')
  583. -- DCS ST (7bit)
  584. push('\x1bPHello\x1b\\', vt)
  585. expect('dcs [Hello]')
  586. -- DCS ST (8bit)
  587. push('\x90Hello\x9c', vt)
  588. expect('dcs [Hello]')
  589. -- Split write of 7bit ST
  590. push('\x1bPABC\x1b', vt)
  591. expect('dcs [ABC')
  592. push('\\', vt)
  593. expect('dcs ]')
  594. -- Escape cancels DCS, starts Escape
  595. push('\x1bPSomething\x1b9', vt)
  596. expect('escape 9')
  597. -- CAN cancels DCS, returns to normal mode
  598. push('\x1bP12\x18AB', vt)
  599. expect('text 41,42')
  600. -- C0 in OSC interrupts and continues
  601. push('\x1bPBy\ne\x07', vt)
  602. expect('dcs [By\ncontrol 0a\ndcs e]')
  603. -- APC BEL
  604. push('\x1b_Hello\x07', vt)
  605. expect('apc [Hello]')
  606. -- APC ST (7bit)
  607. push('\x1b_Hello\x1b\\', vt)
  608. expect('apc [Hello]')
  609. -- APC ST (8bit)
  610. push('\x9fHello\x9c', vt)
  611. expect('apc [Hello]')
  612. -- PM BEL
  613. push('\x1b^Hello\x07', vt)
  614. expect('pm [Hello]')
  615. -- PM ST (7bit)
  616. push('\x1b^Hello\x1b\\', vt)
  617. expect('pm [Hello]')
  618. -- PM ST (8bit)
  619. push('\x9eHello\x9c', vt)
  620. expect('pm [Hello]')
  621. -- SOS BEL
  622. push('\x1bXHello\x07', vt)
  623. expect('sos [Hello]')
  624. -- SOS ST (7bit)
  625. push('\x1bXHello\x1b\\', vt)
  626. expect('sos [Hello]')
  627. -- SOS ST (8bit)
  628. push('\x98Hello\x9c', vt)
  629. expect('sos [Hello]')
  630. push('\x1bXABC\x01DEF\x1b\\', vt)
  631. expect('sos [ABC\x01DEF]')
  632. push('\x1bXABC\x99DEF\x1b\\', vt)
  633. expect('sos [ABC\x99DEF]')
  634. -- NUL ignored
  635. push('\x00', vt)
  636. -- NUL ignored within CSI
  637. push('\x1b[12\x003m', vt)
  638. expect('csi 6d 123')
  639. -- DEL ignored
  640. push('\x7f', vt)
  641. -- DEL ignored within CSI
  642. push('\x1b[12\x7f3m', vt)
  643. expect('csi 6d 123')
  644. -- DEL inside text"
  645. push('AB\x7fC', vt)
  646. expect('text 41,42\ntext 43')
  647. end)
  648. itp('03encoding_utf8', function()
  649. local encoding = wantencoding()
  650. -- Low
  651. encin('123', encoding)
  652. expect('encout 31,32,33')
  653. -- We want to prove the UTF-8 parser correctly handles all the sequences.
  654. -- Easy way to do this is to check it does low/high boundary cases, as that
  655. -- leaves only two for each sequence length
  656. --
  657. -- These ranges are therefore:
  658. --
  659. -- Two bytes:
  660. -- U+0080 = 000 10000000 => 00010 000000
  661. -- => 11000010 10000000 = C2 80
  662. -- U+07FF = 111 11111111 => 11111 111111
  663. -- => 11011111 10111111 = DF BF
  664. --
  665. -- Three bytes:
  666. -- U+0800 = 00001000 00000000 => 0000 100000 000000
  667. -- => 11100000 10100000 10000000 = E0 A0 80
  668. -- U+FFFD = 11111111 11111101 => 1111 111111 111101
  669. -- => 11101111 10111111 10111101 = EF BF BD
  670. -- (We avoid U+FFFE and U+FFFF as they're invalid codepoints)
  671. --
  672. -- Four bytes:
  673. -- U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000
  674. -- => 11110000 10010000 10000000 10000000 = F0 90 80 80
  675. -- U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111
  676. -- => 11110111 10111111 10111111 10111111 = F7 BF BF BF
  677. -- 2 byte
  678. encin('\xC2\x80\xDF\xBF', encoding)
  679. expect('encout 80,7ff')
  680. -- 3 byte
  681. encin('\xE0\xA0\x80\xEF\xBF\xBD', encoding)
  682. expect('encout 800,fffd')
  683. -- 4 byte
  684. encin('\xF0\x90\x80\x80\xF7\xBF\xBF\xBF', encoding)
  685. expect('encout 10000,1fffff')
  686. -- Next up, we check some invalid sequences
  687. -- + Early termination (back to low bytes too soon)
  688. -- + Early restart (another sequence introduction before the previous one was finished)
  689. -- Early termination
  690. encin('\xC2!', encoding)
  691. expect('encout fffd,21')
  692. encin('\xE0!\xE0\xA0!', encoding)
  693. expect('encout fffd,21,fffd,21')
  694. encin('\xF0!\xF0\x90!\xF0\x90\x80!', encoding)
  695. expect('encout fffd,21,fffd,21,fffd,21')
  696. -- Early restart
  697. encin('\xC2\xC2\x90', encoding)
  698. expect('encout fffd,90')
  699. encin('\xE0\xC2\x90\xE0\xA0\xC2\x90', encoding)
  700. expect('encout fffd,90,fffd,90')
  701. encin('\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90', encoding)
  702. expect('encout fffd,90,fffd,90,fffd,90')
  703. -- Test the overlong sequences by giving an overlong encoding of U+0000 and
  704. -- an encoding of the highest codepoint still too short
  705. --
  706. -- Two bytes:
  707. -- U+0000 = C0 80
  708. -- U+007F = 000 01111111 => 00001 111111 =>
  709. -- => 11000001 10111111 => C1 BF
  710. --
  711. -- Three bytes:
  712. -- U+0000 = E0 80 80
  713. -- U+07FF = 00000111 11111111 => 0000 011111 111111
  714. -- => 11100000 10011111 10111111 = E0 9F BF
  715. --
  716. -- Four bytes:
  717. -- U+0000 = F0 80 80 80
  718. -- U+FFFF = 11111111 11111111 => 000 001111 111111 111111
  719. -- => 11110000 10001111 10111111 10111111 = F0 8F BF BF
  720. -- Overlong
  721. encin('\xC0\x80\xC1\xBF', encoding)
  722. expect('encout fffd,fffd')
  723. encin('\xE0\x80\x80\xE0\x9F\xBF', encoding)
  724. expect('encout fffd,fffd')
  725. encin('\xF0\x80\x80\x80\xF0\x8F\xBF\xBF', encoding)
  726. expect('encout fffd,fffd')
  727. -- UTF-16 surrogates U+D800 and U+DFFF
  728. -- UTF-16 Surrogates
  729. encin('\xED\xA0\x80\xED\xBF\xBF', encoding)
  730. expect('encout fffd,fffd')
  731. -- Split write
  732. encin('\xC2', encoding)
  733. encin('\xA0', encoding)
  734. expect('encout a0')
  735. encin('\xE0', encoding)
  736. encin('\xA0\x80', encoding)
  737. expect('encout 800')
  738. encin('\xE0\xA0', encoding)
  739. encin('\x80', encoding)
  740. expect('encout 800')
  741. encin('\xF0', encoding)
  742. encin('\x90\x80\x80', encoding)
  743. expect('encout 10000')
  744. encin('\xF0\x90', encoding)
  745. encin('\x80\x80', encoding)
  746. expect('encout 10000')
  747. encin('\xF0\x90\x80', encoding)
  748. encin('\x80', encoding)
  749. expect('encout 10000')
  750. end)
  751. itp('10state_putglyph', function()
  752. local vt = init()
  753. local state = wantstate(vt, { g = true })
  754. -- Low
  755. reset(state, nil)
  756. push('ABC', vt)
  757. expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,2')
  758. -- UTF-8 1 char
  759. -- U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
  760. -- U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
  761. reset(state, nil)
  762. push('\xC3\x81\xC3\xA9', vt)
  763. expect('putglyph c1 1 0,0\nputglyph e9 1 0,1')
  764. -- UTF-8 split writes
  765. reset(state, nil)
  766. push('\xC3', vt)
  767. push('\x81', vt)
  768. expect('putglyph c1 1 0,0')
  769. -- UTF-8 wide char
  770. -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO
  771. reset(state, nil)
  772. push('\xEF\xBC\x90 ', vt)
  773. expect('putglyph ff10 2 0,0\nputglyph 20 1 0,2')
  774. -- UTF-8 emoji wide char
  775. -- U+1F600 = F0 9F 98 80 name: GRINNING FACE
  776. reset(state, nil)
  777. push('\xF0\x9F\x98\x80 ', vt)
  778. expect('putglyph 1f600 2 0,0\nputglyph 20 1 0,2')
  779. -- UTF-8 combining chars
  780. -- U+0301 = CC 81 name: COMBINING ACUTE
  781. reset(state, nil)
  782. push('e\xCC\x81Z', vt)
  783. expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1')
  784. -- Combining across buffers
  785. reset(state, nil)
  786. push('e', vt)
  787. expect('putglyph 65 1 0,0')
  788. push('\xCC\x81Z', vt)
  789. expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1')
  790. -- Spare combining chars get truncated
  791. reset(state, nil)
  792. push('e' .. string.rep('\xCC\x81', 10), vt)
  793. expect('putglyph 65,301,301,301,301,301 1 0,0') -- and nothing more
  794. reset(state, nil)
  795. push('e', vt)
  796. expect('putglyph 65 1 0,0')
  797. push('\xCC\x81', vt)
  798. expect('putglyph 65,301 1 0,0')
  799. push('\xCC\x82', vt)
  800. expect('putglyph 65,301,302 1 0,0')
  801. -- DECSCA protected
  802. reset(state, nil)
  803. push('A\x1b[1"qB\x1b[2"qC', vt)
  804. expect('putglyph 41 1 0,0\nputglyph 42 1 0,1 prot\nputglyph 43 1 0,2')
  805. end)
  806. itp('11state_movecursor', function()
  807. local vt = init()
  808. local state = wantstate(vt)
  809. -- Implicit
  810. push('ABC', vt)
  811. cursor(0, 3, state)
  812. -- Backspace
  813. push('\b', vt)
  814. cursor(0, 2, state)
  815. -- Horizontal Tab
  816. push('\t', vt)
  817. cursor(0, 8, state)
  818. -- Carriage Return
  819. push('\r', vt)
  820. cursor(0, 0, state)
  821. -- Linefeed
  822. push('\n', vt)
  823. cursor(1, 0, state)
  824. -- Backspace bounded by lefthand edge
  825. push('\x1b[4;2H', vt)
  826. cursor(3, 1, state)
  827. push('\b', vt)
  828. cursor(3, 0, state)
  829. push('\b', vt)
  830. cursor(3, 0, state)
  831. -- Backspace cancels phantom
  832. push('\x1b[4;80H', vt)
  833. cursor(3, 79, state)
  834. push('X', vt)
  835. cursor(3, 79, state)
  836. push('\b', vt)
  837. cursor(3, 78, state)
  838. -- HT bounded by righthand edge
  839. push('\x1b[1;78H', vt)
  840. cursor(0, 77, state)
  841. push('\t', vt)
  842. cursor(0, 79, state)
  843. push('\t', vt)
  844. cursor(0, 79, state)
  845. reset(state, nil)
  846. -- Index
  847. push('ABC\x1bD', vt)
  848. cursor(1, 3, state)
  849. -- Reverse Index
  850. push('\x1bM', vt)
  851. cursor(0, 3, state)
  852. -- Newline
  853. push('\x1bE', vt)
  854. cursor(1, 0, state)
  855. reset(state, nil)
  856. -- Cursor Forward
  857. push('\x1b[B', vt)
  858. cursor(1, 0, state)
  859. push('\x1b[3B', vt)
  860. cursor(4, 0, state)
  861. push('\x1b[0B', vt)
  862. cursor(5, 0, state)
  863. -- Cursor Down
  864. push('\x1b[C', vt)
  865. cursor(5, 1, state)
  866. push('\x1b[3C', vt)
  867. cursor(5, 4, state)
  868. push('\x1b[0C', vt)
  869. cursor(5, 5, state)
  870. -- Cursor Up
  871. push('\x1b[A', vt)
  872. cursor(4, 5, state)
  873. push('\x1b[3A', vt)
  874. cursor(1, 5, state)
  875. push('\x1b[0A', vt)
  876. cursor(0, 5, state)
  877. -- Cursor Backward
  878. push('\x1b[D', vt)
  879. cursor(0, 4, state)
  880. push('\x1b[3D', vt)
  881. cursor(0, 1, state)
  882. push('\x1b[0D', vt)
  883. cursor(0, 0, state)
  884. -- Cursor Next Line
  885. push(' ', vt)
  886. cursor(0, 3, state)
  887. push('\x1b[E', vt)
  888. cursor(1, 0, state)
  889. push(' ', vt)
  890. cursor(1, 3, state)
  891. push('\x1b[2E', vt)
  892. cursor(3, 0, state)
  893. push('\x1b[0E', vt)
  894. cursor(4, 0, state)
  895. -- Cursor Previous Line
  896. push(' ', vt)
  897. cursor(4, 3, state)
  898. push('\x1b[F', vt)
  899. cursor(3, 0, state)
  900. push(' ', vt)
  901. cursor(3, 3, state)
  902. push('\x1b[2F', vt)
  903. cursor(1, 0, state)
  904. push('\x1b[0F', vt)
  905. cursor(0, 0, state)
  906. -- Cursor Horizonal Absolute
  907. push('\n', vt)
  908. cursor(1, 0, state)
  909. push('\x1b[20G', vt)
  910. cursor(1, 19, state)
  911. push('\x1b[G', vt)
  912. cursor(1, 0, state)
  913. -- Cursor Position
  914. push('\x1b[10;5H', vt)
  915. cursor(9, 4, state)
  916. push('\x1b[8H', vt)
  917. cursor(7, 0, state)
  918. push('\x1b[H', vt)
  919. cursor(0, 0, state)
  920. -- Cursor Position cancels phantom
  921. push('\x1b[10;78H', vt)
  922. cursor(9, 77, state)
  923. push('ABC', vt)
  924. cursor(9, 79, state)
  925. push('\x1b[10;80H', vt)
  926. push('C', vt)
  927. cursor(9, 79, state)
  928. push('X', vt)
  929. cursor(10, 1, state)
  930. reset(state, nil)
  931. -- Bounds Checking
  932. push('\x1b[A', vt)
  933. cursor(0, 0, state)
  934. push('\x1b[D', vt)
  935. cursor(0, 0, state)
  936. push('\x1b[25;80H', vt)
  937. cursor(24, 79, state)
  938. push('\x1b[B', vt)
  939. cursor(24, 79, state)
  940. push('\x1b[C', vt)
  941. cursor(24, 79, state)
  942. push('\x1b[E', vt)
  943. cursor(24, 0, state)
  944. push('\x1b[H', vt)
  945. cursor(0, 0, state)
  946. push('\x1b[F', vt)
  947. cursor(0, 0, state)
  948. push('\x1b[999G', vt)
  949. cursor(0, 79, state)
  950. push('\x1b[99;99H', vt)
  951. cursor(24, 79, state)
  952. reset(state, nil)
  953. -- Horizontal Position Absolute
  954. push('\x1b[5`', vt)
  955. cursor(0, 4, state)
  956. -- Horizontal Position Relative
  957. push('\x1b[3a', vt)
  958. cursor(0, 7, state)
  959. -- Horizontal Position Backward
  960. push('\x1b[3j', vt)
  961. cursor(0, 4, state)
  962. -- Horizontal and Vertical Position
  963. push('\x1b[3;3f', vt)
  964. cursor(2, 2, state)
  965. -- Vertical Position Absolute
  966. push('\x1b[5d', vt)
  967. cursor(4, 2, state)
  968. -- Vertical Position Relative
  969. push('\x1b[2e', vt)
  970. cursor(6, 2, state)
  971. -- Vertical Position Backward
  972. push('\x1b[2k', vt)
  973. cursor(4, 2, state)
  974. reset(state, nil)
  975. -- Horizontal Tab
  976. push('\t', vt)
  977. cursor(0, 8, state)
  978. push(' ', vt)
  979. cursor(0, 11, state)
  980. push('\t', vt)
  981. cursor(0, 16, state)
  982. push(' ', vt)
  983. cursor(0, 23, state)
  984. push('\t', vt)
  985. cursor(0, 24, state)
  986. push(' ', vt)
  987. cursor(0, 32, state)
  988. push('\t', vt)
  989. cursor(0, 40, state)
  990. -- Cursor Horizontal Tab
  991. push('\x1b[I', vt)
  992. cursor(0, 48, state)
  993. push('\x1b[2I', vt)
  994. cursor(0, 64, state)
  995. -- Cursor Backward Tab
  996. push('\x1b[Z', vt)
  997. cursor(0, 56, state)
  998. push('\x1b[2Z', vt)
  999. cursor(0, 40, state)
  1000. end)
  1001. itp('12state_scroll', function()
  1002. local vt = init()
  1003. local state = wantstate(vt, { s = true })
  1004. -- Linefeed
  1005. push(string.rep('\n', 24), vt)
  1006. cursor(24, 0, state)
  1007. push('\n', vt)
  1008. expect('scrollrect 0..25,0..80 => +1,+0')
  1009. cursor(24, 0, state)
  1010. reset(state, nil)
  1011. -- Index
  1012. push('\x1b[25H', vt)
  1013. push('\x1bD', vt)
  1014. expect('scrollrect 0..25,0..80 => +1,+0')
  1015. reset(state, nil)
  1016. -- Reverse Index
  1017. push('\x1bM', vt)
  1018. expect('scrollrect 0..25,0..80 => -1,+0')
  1019. reset(state, nil)
  1020. -- Linefeed in DECSTBM
  1021. push('\x1b[1;10r', vt)
  1022. cursor(0, 0, state)
  1023. push(string.rep('\n', 9), vt)
  1024. cursor(9, 0, state)
  1025. push('\n', vt)
  1026. expect('scrollrect 0..10,0..80 => +1,+0')
  1027. cursor(9, 0, state)
  1028. -- Linefeed outside DECSTBM
  1029. push('\x1b[20H', vt)
  1030. cursor(19, 0, state)
  1031. push('\n', vt)
  1032. cursor(20, 0, state)
  1033. -- Index in DECSTBM
  1034. push('\x1b[9;10r', vt)
  1035. push('\x1b[10H', vt)
  1036. push('\x1bM', vt)
  1037. cursor(8, 0, state)
  1038. push('\x1bM', vt)
  1039. expect('scrollrect 8..10,0..80 => -1,+0')
  1040. -- Reverse Index in DECSTBM
  1041. push('\x1b[25H', vt)
  1042. cursor(24, 0, state)
  1043. push('\n', vt)
  1044. -- no scrollrect
  1045. cursor(24, 0, state)
  1046. -- Linefeed in DECSTBM+DECSLRM
  1047. push('\x1b[?69h', vt)
  1048. push('\x1b[3;10r\x1b[10;40s', vt)
  1049. push('\x1b[10;10H\n', vt)
  1050. expect('scrollrect 2..10,9..40 => +1,+0')
  1051. -- IND/RI in DECSTBM+DECSLRM
  1052. push('\x1bD', vt)
  1053. expect('scrollrect 2..10,9..40 => +1,+0')
  1054. push('\x1b[3;10H\x1bM', vt)
  1055. expect('scrollrect 2..10,9..40 => -1,+0')
  1056. -- DECRQSS on DECSTBM
  1057. push('\x1bP$qr\x1b\\', vt)
  1058. expect_output('\x1bP1$r3;10r\x1b\\')
  1059. -- DECRQSS on DECSLRM
  1060. push('\x1bP$qs\x1b\\', vt)
  1061. expect_output('\x1bP1$r10;40s\x1b\\')
  1062. -- Setting invalid DECSLRM with !DECVSSM is still rejected
  1063. push('\x1b[?69l\x1b[;0s\x1b[?69h', vt)
  1064. reset(state, nil)
  1065. -- Scroll Down
  1066. push('\x1b[S', vt)
  1067. expect('scrollrect 0..25,0..80 => +1,+0')
  1068. cursor(0, 0, state)
  1069. push('\x1b[2S', vt)
  1070. expect('scrollrect 0..25,0..80 => +2,+0')
  1071. cursor(0, 0, state)
  1072. push('\x1b[100S', vt)
  1073. expect('scrollrect 0..25,0..80 => +25,+0')
  1074. -- Scroll Up
  1075. push('\x1b[T', vt)
  1076. expect('scrollrect 0..25,0..80 => -1,+0')
  1077. cursor(0, 0, state)
  1078. push('\x1b[2T', vt)
  1079. expect('scrollrect 0..25,0..80 => -2,+0')
  1080. cursor(0, 0, state)
  1081. push('\x1b[100T', vt)
  1082. expect('scrollrect 0..25,0..80 => -25,+0')
  1083. -- SD/SU in DECSTBM
  1084. push('\x1b[5;20r', vt)
  1085. push('\x1b[S', vt)
  1086. expect('scrollrect 4..20,0..80 => +1,+0')
  1087. push('\x1b[T', vt)
  1088. expect('scrollrect 4..20,0..80 => -1,+0')
  1089. reset(state, nil)
  1090. -- SD/SU in DECSTBM+DECSLRM
  1091. push('\x1b[?69h', vt)
  1092. push('\x1b[3;10r\x1b[10;40s', vt)
  1093. cursor(0, 0, state)
  1094. push('\x1b[3;10H', vt)
  1095. cursor(2, 9, state)
  1096. push('\x1b[S', vt)
  1097. expect('scrollrect 2..10,9..40 => +1,+0')
  1098. push('\x1b[?69l', vt)
  1099. push('\x1b[S', vt)
  1100. expect('scrollrect 2..10,0..80 => +1,+0')
  1101. -- Invalid boundaries
  1102. reset(state, nil)
  1103. push('\x1b[100;105r\x1bD', vt)
  1104. push('\x1b[5;2r\x1bD', vt)
  1105. reset(state, nil)
  1106. state = wantstate(vt, { m = true, e = true })
  1107. -- Scroll Down move+erase emulation
  1108. push('\x1b[S', vt)
  1109. expect('moverect 1..25,0..80 -> 0..24,0..80\nerase 24..25,0..80')
  1110. cursor(0, 0, state)
  1111. push('\x1b[2S', vt)
  1112. expect('moverect 2..25,0..80 -> 0..23,0..80\nerase 23..25,0..80')
  1113. cursor(0, 0, state)
  1114. -- Scroll Up move+erase emulation
  1115. push('\x1b[T', vt)
  1116. expect('moverect 0..24,0..80 -> 1..25,0..80\nerase 0..1,0..80')
  1117. cursor(0, 0, state)
  1118. push('\x1b[2T', vt)
  1119. expect('moverect 0..23,0..80 -> 2..25,0..80\nerase 0..2,0..80')
  1120. cursor(0, 0, state)
  1121. -- DECSTBM resets cursor position
  1122. push('\x1b[5;5H', vt)
  1123. cursor(4, 4, state)
  1124. push('\x1b[r', vt)
  1125. cursor(0, 0, state)
  1126. end)
  1127. itp('13state_edit', function()
  1128. local vt = init()
  1129. local state = wantstate(vt, { s = true, e = true, b = true })
  1130. -- ICH
  1131. reset(state, nil)
  1132. expect('erase 0..25,0..80')
  1133. cursor(0, 0, state)
  1134. push('ACD', vt)
  1135. push('\x1b[2D', vt)
  1136. cursor(0, 1, state)
  1137. push('\x1b[@', vt)
  1138. expect('scrollrect 0..1,1..80 => +0,-1')
  1139. cursor(0, 1, state)
  1140. push('B', vt)
  1141. cursor(0, 2, state)
  1142. push('\x1b[3@', vt)
  1143. expect('scrollrect 0..1,2..80 => +0,-3')
  1144. -- ICH with DECSLRM
  1145. push('\x1b[?69h', vt)
  1146. push('\x1b[;50s', vt)
  1147. push('\x1b[20G\x1b[@', vt)
  1148. expect('scrollrect 0..1,19..50 => +0,-1')
  1149. -- ICH outside DECSLRM
  1150. push('\x1b[70G\x1b[@', vt)
  1151. -- nothing happens
  1152. -- DCH
  1153. reset(state, nil)
  1154. expect('erase 0..25,0..80')
  1155. cursor(0, 0, state)
  1156. push('ABBC', vt)
  1157. push('\x1b[3D', vt)
  1158. cursor(0, 1, state)
  1159. push('\x1b[P', vt)
  1160. expect('scrollrect 0..1,1..80 => +0,+1')
  1161. cursor(0, 1, state)
  1162. push('\x1b[3P', vt)
  1163. expect('scrollrect 0..1,1..80 => +0,+3')
  1164. cursor(0, 1, state)
  1165. -- DCH with DECSLRM
  1166. push('\x1b[?69h', vt)
  1167. push('\x1b[;50s', vt)
  1168. push('\x1b[20G\x1b[P', vt)
  1169. expect('scrollrect 0..1,19..50 => +0,+1')
  1170. -- DCH outside DECSLRM
  1171. push('\x1b[70G\x1b[P', vt)
  1172. -- nothing happens
  1173. -- ECH
  1174. reset(state, nil)
  1175. expect('erase 0..25,0..80')
  1176. cursor(0, 0, state)
  1177. push('ABC', vt)
  1178. push('\x1b[2D', vt)
  1179. cursor(0, 1, state)
  1180. push('\x1b[X', vt)
  1181. expect('erase 0..1,1..2')
  1182. cursor(0, 1, state)
  1183. push('\x1b[3X', vt)
  1184. expect('erase 0..1,1..4')
  1185. cursor(0, 1, state)
  1186. -- ECH more columns than there are should be bounded
  1187. push('\x1b[100X', vt)
  1188. expect('erase 0..1,1..80')
  1189. -- IL
  1190. reset(state, nil)
  1191. expect('erase 0..25,0..80')
  1192. cursor(0, 0, state)
  1193. push('A\r\nC', vt)
  1194. cursor(1, 1, state)
  1195. push('\x1b[L', vt)
  1196. expect('scrollrect 1..25,0..80 => -1,+0')
  1197. -- TODO(libvterm): ECMA-48 says we should move to line home, but neither xterm nor xfce4-terminal do this
  1198. cursor(1, 1, state)
  1199. push('\rB', vt)
  1200. cursor(1, 1, state)
  1201. push('\x1b[3L', vt)
  1202. expect('scrollrect 1..25,0..80 => -3,+0')
  1203. -- IL with DECSTBM
  1204. push('\x1b[5;15r', vt)
  1205. push('\x1b[5H\x1b[L', vt)
  1206. expect('scrollrect 4..15,0..80 => -1,+0')
  1207. -- IL outside DECSTBM
  1208. push('\x1b[20H\x1b[L', vt)
  1209. -- nothing happens
  1210. -- IL with DECSTBM+DECSLRM
  1211. push('\x1b[?69h', vt)
  1212. push('\x1b[10;50s', vt)
  1213. push('\x1b[5;10H\x1b[L', vt)
  1214. expect('scrollrect 4..15,9..50 => -1,+0')
  1215. -- DL
  1216. reset(state, nil)
  1217. expect('erase 0..25,0..80')
  1218. cursor(0, 0, state)
  1219. push('A\r\nB\r\nB\r\nC', vt)
  1220. cursor(3, 1, state)
  1221. push('\x1b[2H', vt)
  1222. cursor(1, 0, state)
  1223. push('\x1b[M', vt)
  1224. expect('scrollrect 1..25,0..80 => +1,+0')
  1225. cursor(1, 0, state)
  1226. push('\x1b[3M', vt)
  1227. expect('scrollrect 1..25,0..80 => +3,+0')
  1228. cursor(1, 0, state)
  1229. -- DL with DECSTBM
  1230. push('\x1b[5;15r', vt)
  1231. push('\x1b[5H\x1b[M', vt)
  1232. expect('scrollrect 4..15,0..80 => +1,+0')
  1233. -- DL outside DECSTBM
  1234. push('\x1b[20H\x1b[M', vt)
  1235. -- nothing happens
  1236. -- DL with DECSTBM+DECSLRM
  1237. push('\x1b[?69h', vt)
  1238. push('\x1b[10;50s', vt)
  1239. push('\x1b[5;10H\x1b[M', vt)
  1240. expect('scrollrect 4..15,9..50 => +1,+0')
  1241. -- DECIC
  1242. reset(state, nil)
  1243. expect('erase 0..25,0..80')
  1244. push("\x1b[20G\x1b[5'}", vt)
  1245. expect('scrollrect 0..25,19..80 => +0,-5')
  1246. -- DECIC with DECSTBM+DECSLRM
  1247. push('\x1b[?69h', vt)
  1248. push('\x1b[4;20r\x1b[20;60s', vt)
  1249. push("\x1b[4;20H\x1b[3'}", vt)
  1250. expect('scrollrect 3..20,19..60 => +0,-3')
  1251. -- DECIC outside DECSLRM
  1252. push("\x1b[70G\x1b['}", vt)
  1253. -- nothing happens
  1254. -- DECDC
  1255. reset(state, nil)
  1256. expect('erase 0..25,0..80')
  1257. push("\x1b[20G\x1b[5'~", vt)
  1258. expect('scrollrect 0..25,19..80 => +0,+5')
  1259. -- DECDC with DECSTBM+DECSLRM
  1260. push('\x1b[?69h', vt)
  1261. push('\x1b[4;20r\x1b[20;60s', vt)
  1262. push("\x1b[4;20H\x1b[3'~", vt)
  1263. expect('scrollrect 3..20,19..60 => +0,+3')
  1264. -- DECDC outside DECSLRM
  1265. push("\x1b[70G\x1b['~", vt)
  1266. -- nothing happens
  1267. -- EL 0
  1268. reset(state, nil)
  1269. expect('erase 0..25,0..80')
  1270. cursor(0, 0, state)
  1271. push('ABCDE', vt)
  1272. push('\x1b[3D', vt)
  1273. cursor(0, 2, state)
  1274. push('\x1b[0K', vt)
  1275. expect('erase 0..1,2..80')
  1276. cursor(0, 2, state)
  1277. -- EL 1
  1278. reset(state, nil)
  1279. expect('erase 0..25,0..80')
  1280. cursor(0, 0, state)
  1281. push('ABCDE', vt)
  1282. push('\x1b[3D', vt)
  1283. cursor(0, 2, state)
  1284. push('\x1b[1K', vt)
  1285. expect('erase 0..1,0..3')
  1286. cursor(0, 2, state)
  1287. -- EL 2
  1288. reset(state, nil)
  1289. expect('erase 0..25,0..80')
  1290. cursor(0, 0, state)
  1291. push('ABCDE', vt)
  1292. push('\x1b[3D', vt)
  1293. cursor(0, 2, state)
  1294. push('\x1b[2K', vt)
  1295. expect('erase 0..1,0..80')
  1296. cursor(0, 2, state)
  1297. -- SEL
  1298. reset(state, nil)
  1299. expect('erase 0..25,0..80')
  1300. cursor(0, 0, state)
  1301. push('\x1b[11G', vt)
  1302. cursor(0, 10, state)
  1303. push('\x1b[?0K', vt)
  1304. expect('erase 0..1,10..80 selective')
  1305. cursor(0, 10, state)
  1306. push('\x1b[?1K', vt)
  1307. expect('erase 0..1,0..11 selective')
  1308. cursor(0, 10, state)
  1309. push('\x1b[?2K', vt)
  1310. expect('erase 0..1,0..80 selective')
  1311. cursor(0, 10, state)
  1312. -- ED 0
  1313. reset(state, nil)
  1314. expect('erase 0..25,0..80')
  1315. cursor(0, 0, state)
  1316. push('\x1b[2;2H', vt)
  1317. cursor(1, 1, state)
  1318. push('\x1b[0J', vt)
  1319. expect('erase 1..2,1..80\nerase 2..25,0..80')
  1320. cursor(1, 1, state)
  1321. -- ED 1
  1322. reset(state, nil)
  1323. expect('erase 0..25,0..80')
  1324. cursor(0, 0, state)
  1325. push('\x1b[2;2H', vt)
  1326. cursor(1, 1, state)
  1327. push('\x1b[1J', vt)
  1328. expect('erase 0..1,0..80\nerase 1..2,0..2')
  1329. cursor(1, 1, state)
  1330. -- ED 2
  1331. reset(state, nil)
  1332. expect('erase 0..25,0..80')
  1333. cursor(0, 0, state)
  1334. push('\x1b[2;2H', vt)
  1335. cursor(1, 1, state)
  1336. push('\x1b[2J', vt)
  1337. expect('erase 0..25,0..80')
  1338. cursor(1, 1, state)
  1339. -- ED 3
  1340. push('\x1b[3J', vt)
  1341. expect('sb_clear')
  1342. -- SED
  1343. reset(state, nil)
  1344. expect('erase 0..25,0..80')
  1345. push('\x1b[5;5H', vt)
  1346. cursor(4, 4, state)
  1347. push('\x1b[?0J', vt)
  1348. expect('erase 4..5,4..80 selective\nerase 5..25,0..80 selective')
  1349. cursor(4, 4, state)
  1350. push('\x1b[?1J', vt)
  1351. expect('erase 0..4,0..80 selective\nerase 4..5,0..5 selective')
  1352. cursor(4, 4, state)
  1353. push('\x1b[?2J', vt)
  1354. expect('erase 0..25,0..80 selective')
  1355. cursor(4, 4, state)
  1356. -- DECRQSS on DECSCA
  1357. push('\x1b[2"q', vt)
  1358. push('\x1bP$q"q\x1b\\', vt)
  1359. expect_output('\x1bP1$r2"q\x1b\\')
  1360. state = wantstate(vt, { m = true, e = true, b = true })
  1361. expect('erase 0..25,0..80') -- TODO(dundargoc): strange, this should not be needed according to the original code
  1362. -- ICH move+erase emuation
  1363. reset(state, nil)
  1364. expect('erase 0..25,0..80')
  1365. cursor(0, 0, state)
  1366. push('ACD', vt)
  1367. push('\x1b[2D', vt)
  1368. cursor(0, 1, state)
  1369. push('\x1b[@', vt)
  1370. expect('moverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2')
  1371. cursor(0, 1, state)
  1372. push('B', vt)
  1373. cursor(0, 2, state)
  1374. push('\x1b[3@', vt)
  1375. expect('moverect 0..1,2..77 -> 0..1,5..80\nerase 0..1,2..5')
  1376. -- DCH move+erase emulation
  1377. reset(state, nil)
  1378. expect('erase 0..25,0..80')
  1379. cursor(0, 0, state)
  1380. push('ABBC', vt)
  1381. push('\x1b[3D', vt)
  1382. cursor(0, 1, state)
  1383. push('\x1b[P', vt)
  1384. expect('moverect 0..1,2..80 -> 0..1,1..79\nerase 0..1,79..80')
  1385. cursor(0, 1, state)
  1386. push('\x1b[3P', vt)
  1387. expect('moverect 0..1,4..80 -> 0..1,1..77\nerase 0..1,77..80')
  1388. cursor(0, 1, state)
  1389. end)
  1390. itp('14state_encoding', function()
  1391. local vt = init()
  1392. vterm.vterm_set_utf8(vt, false)
  1393. local state = wantstate(vt, { g = true })
  1394. -- Default
  1395. reset(state, nil)
  1396. push('#', vt)
  1397. expect('putglyph 23 1 0,0')
  1398. -- Designate G0=UK
  1399. reset(state, nil)
  1400. push('\x1b(A', vt)
  1401. push('#', vt)
  1402. expect('putglyph a3 1 0,0')
  1403. -- Designate G0=DEC drawing
  1404. reset(state, nil)
  1405. push('\x1b(0', vt)
  1406. push('a', vt)
  1407. expect('putglyph 2592 1 0,0')
  1408. -- Designate G1 + LS1
  1409. reset(state, nil)
  1410. push('\x1b)0', vt)
  1411. push('a', vt)
  1412. expect('putglyph 61 1 0,0')
  1413. push('\x0e', vt)
  1414. push('a', vt)
  1415. expect('putglyph 2592 1 0,1')
  1416. -- LS0
  1417. push('\x0f', vt)
  1418. push('a', vt)
  1419. expect('putglyph 61 1 0,2')
  1420. -- Designate G2 + LS2
  1421. push('\x1b*0', vt)
  1422. push('a', vt)
  1423. expect('putglyph 61 1 0,3')
  1424. push('\x1bn', vt)
  1425. push('a', vt)
  1426. expect('putglyph 2592 1 0,4')
  1427. push('\x0f', vt)
  1428. push('a', vt)
  1429. expect('putglyph 61 1 0,5')
  1430. -- Designate G3 + LS3
  1431. push('\x1b+0', vt)
  1432. push('a', vt)
  1433. expect('putglyph 61 1 0,6')
  1434. push('\x1bo', vt)
  1435. push('a', vt)
  1436. expect('putglyph 2592 1 0,7')
  1437. push('\x0f', vt)
  1438. push('a', vt)
  1439. expect('putglyph 61 1 0,8')
  1440. -- SS2
  1441. push('a\x8eaa', vt)
  1442. expect('putglyph 61 1 0,9\nputglyph 2592 1 0,10\nputglyph 61 1 0,11')
  1443. -- SS3
  1444. push('a\x8faa', vt)
  1445. expect('putglyph 61 1 0,12\nputglyph 2592 1 0,13\nputglyph 61 1 0,14')
  1446. -- LS1R
  1447. reset(state, nil)
  1448. push('\x1b~', vt)
  1449. push('\xe1', vt)
  1450. expect('putglyph 61 1 0,0')
  1451. push('\x1b)0', vt)
  1452. push('\xe1', vt)
  1453. expect('putglyph 2592 1 0,1')
  1454. -- LS2R
  1455. reset(state, nil)
  1456. push('\x1b}', vt)
  1457. push('\xe1', vt)
  1458. expect('putglyph 61 1 0,0')
  1459. push('\x1b*0', vt)
  1460. push('\xe1', vt)
  1461. expect('putglyph 2592 1 0,1')
  1462. -- LS3R
  1463. reset(state, nil)
  1464. push('\x1b|', vt)
  1465. push('\xe1', vt)
  1466. expect('putglyph 61 1 0,0')
  1467. push('\x1b+0', vt)
  1468. push('\xe1', vt)
  1469. expect('putglyph 2592 1 0,1')
  1470. vterm.vterm_set_utf8(vt, true)
  1471. -- U+0108 == c4 88
  1472. reset(state, nil)
  1473. push('\x1b(B', vt)
  1474. push('AB\xc4\x88D', vt)
  1475. expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 108 1 0,2\nputglyph 44 1 0,3')
  1476. end)
  1477. itp('15state_mode', function()
  1478. local vt = init()
  1479. local state = wantstate(vt, { g = true, m = true, e = true })
  1480. -- Insert/Replace Mode
  1481. reset(state, nil)
  1482. expect('erase 0..25,0..80')
  1483. cursor(0, 0, state)
  1484. push('AC\x1b[DB', vt)
  1485. expect('putglyph 41 1 0,0\nputglyph 43 1 0,1\nputglyph 42 1 0,1')
  1486. push('\x1b[4h', vt)
  1487. push('\x1b[G', vt)
  1488. push('AC\x1b[DB', vt)
  1489. expect(
  1490. 'moverect 0..1,0..79 -> 0..1,1..80\nerase 0..1,0..1\nputglyph 41 1 0,0\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 43 1 0,1\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 42 1 0,1'
  1491. )
  1492. -- Insert mode only happens once for UTF-8 combining
  1493. push('e', vt)
  1494. expect('moverect 0..1,2..79 -> 0..1,3..80\nerase 0..1,2..3\nputglyph 65 1 0,2')
  1495. push('\xCC\x81', vt)
  1496. expect('putglyph 65,301 1 0,2')
  1497. -- Newline/Linefeed mode
  1498. reset(state, nil)
  1499. expect('erase 0..25,0..80')
  1500. cursor(0, 0, state)
  1501. push('\x1b[5G\n', vt)
  1502. cursor(1, 4, state)
  1503. push('\x1b[20h', vt)
  1504. push('\x1b[5G\n', vt)
  1505. cursor(2, 0, state)
  1506. -- DEC origin mode
  1507. reset(state, nil)
  1508. expect('erase 0..25,0..80')
  1509. cursor(0, 0, state)
  1510. push('\x1b[5;15r', vt)
  1511. push('\x1b[H', vt)
  1512. cursor(0, 0, state)
  1513. push('\x1b[3;3H', vt)
  1514. cursor(2, 2, state)
  1515. push('\x1b[?6h', vt)
  1516. push('\x1b[H', vt)
  1517. cursor(4, 0, state)
  1518. push('\x1b[3;3H', vt)
  1519. cursor(6, 2, state)
  1520. -- DECRQM on DECOM
  1521. push('\x1b[?6h', vt)
  1522. push('\x1b[?6$p', vt)
  1523. expect_output('\x1b[?6;1$y')
  1524. push('\x1b[?6l', vt)
  1525. push('\x1b[?6$p', vt)
  1526. expect_output('\x1b[?6;2$y')
  1527. -- Origin mode with DECSLRM
  1528. push('\x1b[?6h', vt)
  1529. push('\x1b[?69h', vt)
  1530. push('\x1b[20;60s', vt)
  1531. push('\x1b[H', vt)
  1532. cursor(4, 19, state)
  1533. push('\x1b[?69l', vt)
  1534. -- Origin mode bounds cursor to scrolling region
  1535. push('\x1b[H', vt)
  1536. push('\x1b[10A', vt)
  1537. cursor(4, 0, state)
  1538. push('\x1b[20B', vt)
  1539. cursor(14, 0, state)
  1540. -- Origin mode without scroll region
  1541. push('\x1b[?6l', vt)
  1542. push('\x1b[r\x1b[?6h', vt)
  1543. cursor(0, 0, state)
  1544. end)
  1545. itp('16state_resize', function()
  1546. local vt = init()
  1547. local state = wantstate(vt, { g = true })
  1548. -- Placement
  1549. reset(state, nil)
  1550. push('AB\x1b[79GCDE', vt)
  1551. expect(
  1552. 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 1,0'
  1553. )
  1554. -- Resize
  1555. reset(state, nil)
  1556. resize(27, 85, vt)
  1557. push('AB\x1b[79GCDE', vt)
  1558. expect(
  1559. 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 0,80'
  1560. )
  1561. cursor(0, 81, state)
  1562. -- Resize without reset
  1563. resize(28, 90, vt)
  1564. cursor(0, 81, state)
  1565. push('FGHI', vt)
  1566. expect('putglyph 46 1 0,81\nputglyph 47 1 0,82\nputglyph 48 1 0,83\nputglyph 49 1 0,84')
  1567. cursor(0, 85, state)
  1568. -- Resize shrink moves cursor
  1569. resize(25, 80, vt)
  1570. cursor(0, 79, state)
  1571. -- Resize grow doesn't cancel phantom
  1572. reset(state, nil)
  1573. push('\x1b[79GAB', vt)
  1574. expect('putglyph 41 1 0,78\nputglyph 42 1 0,79')
  1575. cursor(0, 79, state)
  1576. resize(30, 100, vt)
  1577. cursor(0, 80, state)
  1578. push('C', vt)
  1579. expect('putglyph 43 1 0,80')
  1580. cursor(0, 81, state)
  1581. end)
  1582. itp('17state_mouse', function()
  1583. local vt = init()
  1584. local state = wantstate(vt, { p = true })
  1585. -- DECRQM on with mouse off
  1586. push('\x1b[?1000$p', vt)
  1587. expect_output('\x1b[?1000;2$y')
  1588. push('\x1b[?1002$p', vt)
  1589. expect_output('\x1b[?1002;2$y')
  1590. push('\x1b[?1003$p', vt)
  1591. expect_output('\x1b[?1003;2$y')
  1592. -- Mouse in simple button report mode
  1593. reset(state, nil)
  1594. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1595. push('\x1b[?1000h', vt)
  1596. expect('settermprop 8 1')
  1597. -- Press 1
  1598. mousemove(0, 0, vt)
  1599. mousebtn('d', 1, vt)
  1600. expect_output('\x1b[M\x20\x21\x21')
  1601. -- Release 1
  1602. mousebtn('u', 1, vt)
  1603. expect_output('\x1b[M\x23\x21\x21')
  1604. -- Ctrl-Press 1
  1605. mousebtn('d', 1, vt, { C = true })
  1606. expect_output('\x1b[M\x30\x21\x21')
  1607. mousebtn('u', 1, vt, { C = true })
  1608. expect_output('\x1b[M\x33\x21\x21')
  1609. -- Button 2
  1610. mousebtn('d', 2, vt)
  1611. expect_output('\x1b[M\x21\x21\x21')
  1612. mousebtn('u', 2, vt)
  1613. expect_output('\x1b[M\x23\x21\x21')
  1614. -- Position
  1615. mousemove(10, 20, vt)
  1616. mousebtn('d', 1, vt)
  1617. expect_output('\x1b[M\x20\x35\x2b')
  1618. mousebtn('u', 1, vt)
  1619. expect_output('\x1b[M\x23\x35\x2b')
  1620. mousemove(10, 21, vt)
  1621. -- no output
  1622. -- Wheel events
  1623. mousebtn('d', 4, vt)
  1624. expect_output('\x1b[M\x60\x36\x2b')
  1625. mousebtn('d', 4, vt)
  1626. expect_output('\x1b[M\x60\x36\x2b')
  1627. mousebtn('d', 5, vt)
  1628. expect_output('\x1b[M\x61\x36\x2b')
  1629. mousebtn('d', 6, vt)
  1630. expect_output('\x1b[M\x62\x36\x2b')
  1631. mousebtn('d', 7, vt)
  1632. expect_output('\x1b[M\x63\x36\x2b')
  1633. -- DECRQM on mouse button mode
  1634. push('\x1b[?1000$p', vt)
  1635. expect_output('\x1b[?1000;1$y')
  1636. push('\x1b[?1002$p', vt)
  1637. expect_output('\x1b[?1002;2$y')
  1638. push('\x1b[?1003$p', vt)
  1639. expect_output('\x1b[?1003;2$y')
  1640. -- Drag events
  1641. reset(state, nil)
  1642. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1643. push('\x1b[?1002h', vt)
  1644. expect('settermprop 8 2')
  1645. mousemove(5, 5, vt)
  1646. mousebtn('d', 1, vt)
  1647. expect_output('\x1b[M\x20\x26\x26')
  1648. mousemove(5, 6, vt)
  1649. expect_output('\x1b[M\x40\x27\x26')
  1650. mousemove(6, 6, vt)
  1651. expect_output('\x1b[M\x40\x27\x27')
  1652. mousemove(6, 6, vt)
  1653. -- no output
  1654. mousebtn('u', 1, vt)
  1655. expect_output('\x1b[M\x23\x27\x27')
  1656. mousemove(6, 7, vt)
  1657. -- no output
  1658. -- DECRQM on mouse drag mode
  1659. push('\x1b[?1000$p', vt)
  1660. expect_output('\x1b[?1000;2$y')
  1661. push('\x1b[?1002$p', vt)
  1662. expect_output('\x1b[?1002;1$y')
  1663. push('\x1b[?1003$p', vt)
  1664. expect_output('\x1b[?1003;2$y')
  1665. -- Non-drag motion events
  1666. push('\x1b[?1003h', vt)
  1667. expect('settermprop 8 3')
  1668. mousemove(6, 8, vt)
  1669. expect_output('\x1b[M\x43\x29\x27')
  1670. -- DECRQM on mouse motion mode
  1671. push('\x1b[?1000$p', vt)
  1672. expect_output('\x1b[?1000;2$y')
  1673. push('\x1b[?1002$p', vt)
  1674. expect_output('\x1b[?1002;2$y')
  1675. push('\x1b[?1003$p', vt)
  1676. expect_output('\x1b[?1003;1$y')
  1677. -- Bounds checking
  1678. mousemove(300, 300, vt)
  1679. expect_output('\x1b[M\x43\xff\xff')
  1680. mousebtn('d', 1, vt)
  1681. expect_output('\x1b[M\x20\xff\xff')
  1682. mousebtn('u', 1, vt)
  1683. expect_output('\x1b[M\x23\xff\xff')
  1684. -- DECRQM on standard encoding mode
  1685. push('\x1b[?1005$p', vt)
  1686. expect_output('\x1b[?1005;2$y')
  1687. push('\x1b[?1006$p', vt)
  1688. expect_output('\x1b[?1006;2$y')
  1689. push('\x1b[?1015$p', vt)
  1690. expect_output('\x1b[?1015;2$y')
  1691. -- UTF-8 extended encoding mode
  1692. -- 300 + 32 + 1 = 333 = U+014d = \xc5\x8d
  1693. push('\x1b[?1005h', vt)
  1694. mousebtn('d', 1, vt)
  1695. expect_output('\x1b[M\x20\xc5\x8d\xc5\x8d')
  1696. mousebtn('u', 1, vt)
  1697. expect_output('\x1b[M\x23\xc5\x8d\xc5\x8d')
  1698. -- DECRQM on UTF-8 extended encoding mode
  1699. push('\x1b[?1005$p', vt)
  1700. expect_output('\x1b[?1005;1$y')
  1701. push('\x1b[?1006$p', vt)
  1702. expect_output('\x1b[?1006;2$y')
  1703. push('\x1b[?1015$p', vt)
  1704. expect_output('\x1b[?1015;2$y')
  1705. -- SGR extended encoding mode
  1706. push('\x1b[?1006h', vt)
  1707. mousebtn('d', 1, vt)
  1708. expect_output('\x1b[<0;301;301M')
  1709. mousebtn('u', 1, vt)
  1710. expect_output('\x1b[<0;301;301m')
  1711. -- DECRQM on SGR extended encoding mode
  1712. push('\x1b[?1005$p', vt)
  1713. expect_output('\x1b[?1005;2$y')
  1714. push('\x1b[?1006$p', vt)
  1715. expect_output('\x1b[?1006;1$y')
  1716. push('\x1b[?1015$p', vt)
  1717. expect_output('\x1b[?1015;2$y')
  1718. -- rxvt extended encoding mode
  1719. push('\x1b[?1015h', vt)
  1720. mousebtn('d', 1, vt)
  1721. expect_output('\x1b[0;301;301M')
  1722. mousebtn('u', 1, vt)
  1723. expect_output('\x1b[3;301;301M')
  1724. -- DECRQM on rxvt extended encoding mode
  1725. push('\x1b[?1005$p', vt)
  1726. expect_output('\x1b[?1005;2$y')
  1727. push('\x1b[?1006$p', vt)
  1728. expect_output('\x1b[?1006;2$y')
  1729. push('\x1b[?1015$p', vt)
  1730. expect_output('\x1b[?1015;1$y')
  1731. -- Mouse disabled reports nothing
  1732. reset(state, nil)
  1733. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1734. mousemove(0, 0, vt)
  1735. mousebtn('d', 1, vt)
  1736. mousebtn('u', 1, vt)
  1737. -- DECSM can set multiple modes at once
  1738. push('\x1b[?1002;1006h', vt)
  1739. expect('settermprop 8 2')
  1740. mousebtn('d', 1, vt)
  1741. expect_output('\x1b[<0;1;1M')
  1742. end)
  1743. itp('18state_termprops', function()
  1744. local vt = init()
  1745. local state = wantstate(vt, { p = true })
  1746. reset(state, nil)
  1747. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1748. -- Cursor visibility
  1749. push('\x1b[?25h', vt)
  1750. expect('settermprop 1 true')
  1751. push('\x1b[?25$p', vt)
  1752. expect_output('\x1b[?25;1$y')
  1753. push('\x1b[?25l', vt)
  1754. expect('settermprop 1 false')
  1755. push('\x1b[?25$p', vt)
  1756. expect_output('\x1b[?25;2$y')
  1757. -- Cursor blink
  1758. push('\x1b[?12h', vt)
  1759. expect('settermprop 2 true')
  1760. push('\x1b[?12$p', vt)
  1761. expect_output('\x1b[?12;1$y')
  1762. push('\x1b[?12l', vt)
  1763. expect('settermprop 2 false')
  1764. push('\x1b[?12$p', vt)
  1765. expect_output('\x1b[?12;2$y')
  1766. -- Cursor shape
  1767. push('\x1b[3 q', vt)
  1768. expect('settermprop 2 true\nsettermprop 7 2')
  1769. -- Title
  1770. push('\x1b]2;Here is my title\a', vt)
  1771. expect('settermprop 4 ["Here is my title"]')
  1772. -- Title split write
  1773. push('\x1b]2;Here is', vt)
  1774. expect('settermprop 4 ["Here is"')
  1775. push(' another title\a', vt)
  1776. expect('settermprop 4 " another title"]')
  1777. end)
  1778. itp('20state_wrapping', function()
  1779. local vt = init()
  1780. local state = wantstate(vt, { g = true, m = true })
  1781. -- 79th Column
  1782. push('\x1b[75G', vt)
  1783. push(string.rep('A', 5), vt)
  1784. expect(
  1785. 'putglyph 41 1 0,74\nputglyph 41 1 0,75\nputglyph 41 1 0,76\nputglyph 41 1 0,77\nputglyph 41 1 0,78'
  1786. )
  1787. cursor(0, 79, state)
  1788. -- 80th Column Phantom
  1789. push('A', vt)
  1790. expect('putglyph 41 1 0,79')
  1791. cursor(0, 79, state)
  1792. -- Line Wraparound
  1793. push('B', vt)
  1794. expect('putglyph 42 1 1,0')
  1795. cursor(1, 1, state)
  1796. -- Line Wraparound during combined write
  1797. push('\x1b[78G', vt)
  1798. push('BBBCC', vt)
  1799. expect(
  1800. 'putglyph 42 1 1,77\nputglyph 42 1 1,78\nputglyph 42 1 1,79\nputglyph 43 1 2,0\nputglyph 43 1 2,1'
  1801. )
  1802. cursor(2, 2, state)
  1803. -- DEC Auto Wrap Mode
  1804. reset(state, nil)
  1805. push('\x1b[?7l', vt)
  1806. push('\x1b[75G', vt)
  1807. push(string.rep('D', 6), vt)
  1808. expect(
  1809. 'putglyph 44 1 0,74\nputglyph 44 1 0,75\nputglyph 44 1 0,76\nputglyph 44 1 0,77\nputglyph 44 1 0,78\nputglyph 44 1 0,79'
  1810. )
  1811. cursor(0, 79, state)
  1812. push('D', vt)
  1813. expect('putglyph 44 1 0,79')
  1814. cursor(0, 79, state)
  1815. push('\x1b[?7h', vt)
  1816. -- 80th column causes linefeed on wraparound
  1817. push('\x1b[25;78HABC', vt)
  1818. expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79')
  1819. cursor(24, 79, state)
  1820. push('D', vt)
  1821. expect('moverect 1..25,0..80 -> 0..24,0..80\nputglyph 44 1 24,0')
  1822. -- 80th column phantom linefeed phantom cancelled by explicit cursor move
  1823. push('\x1b[25;78HABC', vt)
  1824. expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79')
  1825. cursor(24, 79, state)
  1826. push('\x1b[25;1HD', vt)
  1827. expect('putglyph 44 1 24,0')
  1828. end)
  1829. itp('21state_tabstops', function()
  1830. local vt = init()
  1831. local state = wantstate(vt, { g = true })
  1832. -- Initial
  1833. reset(state, nil)
  1834. push('\tX', vt)
  1835. expect('putglyph 58 1 0,8')
  1836. push('\tX', vt)
  1837. expect('putglyph 58 1 0,16')
  1838. cursor(0, 17, state)
  1839. -- HTS
  1840. push('\x1b[5G\x1bH', vt)
  1841. push('\x1b[G\tX', vt)
  1842. expect('putglyph 58 1 0,4')
  1843. cursor(0, 5, state)
  1844. -- TBC 0
  1845. push('\x1b[9G\x1b[g', vt)
  1846. push('\x1b[G\tX\tX', vt)
  1847. expect('putglyph 58 1 0,4\nputglyph 58 1 0,16')
  1848. cursor(0, 17, state)
  1849. -- TBC 3
  1850. push('\x1b[3g\x1b[50G\x1bH\x1b[G', vt)
  1851. cursor(0, 0, state)
  1852. push('\tX', vt)
  1853. expect('putglyph 58 1 0,49')
  1854. cursor(0, 50, state)
  1855. -- Tabstops after resize
  1856. reset(state, nil)
  1857. resize(30, 100, vt)
  1858. -- Should be 100/8 = 12 tabstops
  1859. push('\tX', vt)
  1860. expect('putglyph 58 1 0,8')
  1861. push('\tX', vt)
  1862. expect('putglyph 58 1 0,16')
  1863. push('\tX', vt)
  1864. expect('putglyph 58 1 0,24')
  1865. push('\tX', vt)
  1866. expect('putglyph 58 1 0,32')
  1867. push('\tX', vt)
  1868. expect('putglyph 58 1 0,40')
  1869. push('\tX', vt)
  1870. expect('putglyph 58 1 0,48')
  1871. push('\tX', vt)
  1872. expect('putglyph 58 1 0,56')
  1873. push('\tX', vt)
  1874. expect('putglyph 58 1 0,64')
  1875. push('\tX', vt)
  1876. expect('putglyph 58 1 0,72')
  1877. push('\tX', vt)
  1878. expect('putglyph 58 1 0,80')
  1879. push('\tX', vt)
  1880. expect('putglyph 58 1 0,88')
  1881. push('\tX', vt)
  1882. expect('putglyph 58 1 0,96')
  1883. cursor(0, 97, state)
  1884. end)
  1885. itp('22state_save', function()
  1886. local vt = init()
  1887. local state = wantstate(vt, { p = true })
  1888. reset(state, nil)
  1889. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1890. -- Set up state
  1891. push('\x1b[2;2H', vt)
  1892. cursor(1, 1, state)
  1893. push('\x1b[1m', vt)
  1894. pen('bold', true, state)
  1895. -- Save
  1896. push('\x1b[?1048h', vt)
  1897. -- Change state
  1898. push('\x1b[5;5H', vt)
  1899. cursor(4, 4, state)
  1900. push('\x1b[4 q', vt)
  1901. expect('settermprop 2 false\nsettermprop 7 2')
  1902. push('\x1b[22;4m', vt)
  1903. pen('bold', false, state)
  1904. pen('underline', 1, state)
  1905. -- Restore
  1906. push('\x1b[?1048l', vt)
  1907. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1908. cursor(1, 1, state)
  1909. pen('bold', true, state)
  1910. pen('underline', 0, state)
  1911. -- Save/restore using DECSC/DECRC
  1912. push('\x1b[2;2H\x1b7', vt)
  1913. cursor(1, 1, state)
  1914. push('\x1b[5;5H', vt)
  1915. cursor(4, 4, state)
  1916. push('\x1b8', vt)
  1917. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1918. cursor(1, 1, state)
  1919. -- Save twice, restore twice happens on both edge transitions
  1920. push('\x1b[2;10H\x1b[?1048h\x1b[6;10H\x1b[?1048h', vt)
  1921. push('\x1b[H', vt)
  1922. cursor(0, 0, state)
  1923. push('\x1b[?1048l', vt)
  1924. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1925. cursor(5, 9, state)
  1926. push('\x1b[H', vt)
  1927. cursor(0, 0, state)
  1928. push('\x1b[?1048l', vt)
  1929. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  1930. cursor(5, 9, state)
  1931. end)
  1932. itp('25state_input', function()
  1933. local vt = init()
  1934. local state = wantstate(vt)
  1935. -- Unmodified ASCII
  1936. inchar(41, vt)
  1937. expect('output 29')
  1938. inchar(61, vt)
  1939. expect('output 3d')
  1940. -- Ctrl modifier on ASCII letters
  1941. inchar(41, vt, { C = true })
  1942. expect('output 1b,5b,34,31,3b,35,75')
  1943. inchar(61, vt, { C = true })
  1944. expect('output 1b,5b,36,31,3b,35,75')
  1945. -- Alt modifier on ASCII letters
  1946. inchar(41, vt, { A = true })
  1947. expect('output 1b,29')
  1948. inchar(61, vt, { A = true })
  1949. expect('output 1b,3d')
  1950. -- Ctrl-Alt modifier on ASCII letters
  1951. inchar(41, vt, { C = true, A = true })
  1952. expect('output 1b,5b,34,31,3b,37,75')
  1953. inchar(61, vt, { C = true, A = true })
  1954. expect('output 1b,5b,36,31,3b,37,75')
  1955. -- Special handling of Ctrl-I
  1956. inchar(49, vt)
  1957. expect('output 31')
  1958. inchar(69, vt)
  1959. expect('output 45')
  1960. inchar(49, vt, { C = true })
  1961. expect('output 1b,5b,34,39,3b,35,75')
  1962. inchar(69, vt, { C = true })
  1963. expect('output 1b,5b,36,39,3b,35,75')
  1964. inchar(49, vt, { A = true })
  1965. expect('output 1b,31')
  1966. inchar(69, vt, { A = true })
  1967. expect('output 1b,45')
  1968. inchar(49, vt, { A = true, C = true })
  1969. expect('output 1b,5b,34,39,3b,37,75')
  1970. inchar(69, vt, { A = true, C = true })
  1971. expect('output 1b,5b,36,39,3b,37,75')
  1972. -- Special handling of Space
  1973. inchar(20, vt)
  1974. expect('output 14')
  1975. inchar(20, vt, { S = true })
  1976. expect('output 14')
  1977. inchar(20, vt, { C = true })
  1978. expect('output 1b,5b,32,30,3b,35,75')
  1979. inchar(20, vt, { C = true, S = true })
  1980. expect('output 1b,5b,32,30,3b,35,75')
  1981. inchar(20, vt, { A = true })
  1982. expect('output 1b,14')
  1983. inchar(20, vt, { S = true, A = true })
  1984. expect('output 1b,14')
  1985. inchar(20, vt, { C = true, A = true })
  1986. expect('output 1b,5b,32,30,3b,37,75')
  1987. inchar(20, vt, { S = true, C = true, A = true })
  1988. expect('output 1b,5b,32,30,3b,37,75')
  1989. -- Cursor keys in reset (cursor) mode
  1990. inkey('up', vt)
  1991. expect_output('\x1b[A')
  1992. inkey('up', vt, { S = true })
  1993. expect_output('\x1b[1;2A')
  1994. inkey('up', vt, { C = true })
  1995. expect_output('\x1b[1;5A')
  1996. inkey('up', vt, { S = true, C = true })
  1997. expect_output('\x1b[1;6A')
  1998. inkey('up', vt, { A = true })
  1999. expect_output('\x1b[1;3A')
  2000. inkey('up', vt, { S = true, A = true })
  2001. expect_output('\x1b[1;4A')
  2002. inkey('up', vt, { C = true, A = true })
  2003. expect_output('\x1b[1;7A')
  2004. inkey('up', vt, { S = true, C = true, A = true })
  2005. expect_output('\x1b[1;8A')
  2006. -- Cursor keys in application mode
  2007. push('\x1b[?1h', vt)
  2008. -- Plain "Up" should be SS3 A now
  2009. inkey('up', vt)
  2010. expect_output('\x1bOA')
  2011. -- Modified keys should still use CSI
  2012. inkey('up', vt, { S = true })
  2013. expect_output('\x1b[1;2A')
  2014. inkey('up', vt, { C = true })
  2015. expect_output('\x1b[1;5A')
  2016. -- Shift-Tab should be different
  2017. inkey('tab', vt)
  2018. expect_output('\x09')
  2019. inkey('tab', vt, { S = true })
  2020. expect_output('\x1b[Z')
  2021. inkey('tab', vt, { C = true })
  2022. expect_output('\x1b[9;5u')
  2023. inkey('tab', vt, { A = true })
  2024. expect_output('\x1b\x09')
  2025. inkey('tab', vt, { C = true, A = true })
  2026. expect_output('\x1b[9;7u')
  2027. -- Enter in linefeed mode
  2028. inkey('enter', vt)
  2029. expect_output('\x0d')
  2030. -- Enter in newline mode
  2031. push('\x1b[20h', vt)
  2032. inkey('enter', vt)
  2033. expect_output('\x0d\x0a')
  2034. -- Unmodified F1 is SS3 P
  2035. inkey('f1', vt)
  2036. expect_output('\x1bOP')
  2037. -- Modified F1 is CSI P
  2038. inkey('f1', vt, { S = true })
  2039. expect_output('\x1b[1;2P')
  2040. inkey('f1', vt, { A = true })
  2041. expect_output('\x1b[1;3P')
  2042. inkey('f1', vt, { C = true })
  2043. expect_output('\x1b[1;5P')
  2044. -- Keypad in DECKPNM
  2045. inkey('kp0', vt)
  2046. expect_output('0')
  2047. -- Keypad in DECKPAM
  2048. push('\x1b=', vt)
  2049. inkey('kp0', vt)
  2050. expect_output('\x1bOp')
  2051. -- Bracketed paste mode off
  2052. vterm.vterm_keyboard_start_paste(vt)
  2053. vterm.vterm_keyboard_end_paste(vt)
  2054. -- Bracketed paste mode on
  2055. push('\x1b[?2004h', vt)
  2056. vterm.vterm_keyboard_start_paste(vt)
  2057. expect_output('\x1b[200~')
  2058. vterm.vterm_keyboard_end_paste(vt)
  2059. expect_output('\x1b[201~')
  2060. -- Focus reporting disabled
  2061. vterm.vterm_state_focus_in(state)
  2062. vterm.vterm_state_focus_out(state)
  2063. -- Focus reporting enabled
  2064. state = wantstate(vt, { p = true })
  2065. push('\x1b[?1004h', vt)
  2066. expect('settermprop 9 true')
  2067. vterm.vterm_state_focus_in(state)
  2068. expect_output('\x1b[I')
  2069. vterm.vterm_state_focus_out(state)
  2070. expect_output('\x1b[O')
  2071. end)
  2072. itp('26state_query', function()
  2073. local vt = init()
  2074. local state = wantstate(vt)
  2075. -- DA
  2076. reset(state, nil)
  2077. push('\x1b[c', vt)
  2078. expect_output('\x1b[?1;2c')
  2079. -- XTVERSION
  2080. reset(state, nil)
  2081. push('\x1b[>q', vt)
  2082. expect_output('\x1bP>|libvterm(0.3)\x1b\\')
  2083. -- DSR
  2084. reset(state, nil)
  2085. push('\x1b[5n', vt)
  2086. expect_output('\x1b[0n')
  2087. -- CPR
  2088. push('\x1b[6n', vt)
  2089. expect_output('\x1b[1;1R')
  2090. push('\x1b[10;10H\x1b[6n', vt)
  2091. expect_output('\x1b[10;10R')
  2092. -- DECCPR
  2093. push('\x1b[?6n', vt)
  2094. expect_output('\x1b[?10;10R')
  2095. -- DECRQSS on DECSCUSR
  2096. push('\x1b[3 q', vt)
  2097. push('\x1bP$q q\x1b\\', vt)
  2098. expect_output('\x1bP1$r3 q\x1b\\')
  2099. -- DECRQSS on SGR
  2100. push('\x1b[1;5;7m', vt)
  2101. push('\x1bP$qm\x1b\\', vt)
  2102. expect_output('\x1bP1$r1;5;7m\x1b\\')
  2103. -- DECRQSS on SGR ANSI colours
  2104. push('\x1b[0;31;42m', vt)
  2105. push('\x1bP$qm\x1b\\', vt)
  2106. expect_output('\x1bP1$r31;42m\x1b\\')
  2107. -- DECRQSS on SGR ANSI hi-bright colours
  2108. push('\x1b[0;93;104m', vt)
  2109. push('\x1bP$qm\x1b\\', vt)
  2110. expect_output('\x1bP1$r93;104m\x1b\\')
  2111. -- DECRQSS on SGR 256-palette colours
  2112. push('\x1b[0;38:5:56;48:5:78m', vt)
  2113. push('\x1bP$qm\x1b\\', vt)
  2114. expect_output('\x1bP1$r38:5:56;48:5:78m\x1b\\')
  2115. -- DECRQSS on SGR RGB8 colours
  2116. push('\x1b[0;38:2:24:68:112;48:2:13:57:101m', vt)
  2117. push('\x1bP$qm\x1b\\', vt)
  2118. expect_output('\x1bP1$r38:2:24:68:112;48:2:13:57:101m\x1b\\')
  2119. -- S8C1T on DSR
  2120. push('\x1b G', vt)
  2121. push('\x1b[5n', vt)
  2122. expect_output('\x9b0n')
  2123. push('\x1b F', vt)
  2124. end)
  2125. itp('27state_reset', function()
  2126. local vt = init()
  2127. local state = wantstate(vt)
  2128. reset(state, nil)
  2129. -- RIS homes cursor
  2130. push('\x1b[5;5H', vt)
  2131. cursor(4, 4, state)
  2132. state = wantstate(vt, { m = true })
  2133. push('\x1bc', vt)
  2134. cursor(0, 0, state)
  2135. wantstate(vt)
  2136. -- RIS cancels scrolling region
  2137. push('\x1b[5;10r', vt)
  2138. wantstate(vt, { s = true })
  2139. push('\x1bc\x1b[25H\n', vt)
  2140. expect('scrollrect 0..25,0..80 => +1,+0')
  2141. wantstate(vt)
  2142. -- RIS erases screen
  2143. push('ABCDE', vt)
  2144. state = wantstate(vt, { e = true })
  2145. push('\x1bc', vt)
  2146. expect('erase 0..25,0..80')
  2147. wantstate(vt)
  2148. -- RIS clears tabstops
  2149. push('\x1b[5G\x1bH\x1b[G\t', vt)
  2150. cursor(0, 4, state)
  2151. push('\x1bc\t', vt)
  2152. cursor(0, 8, state)
  2153. end)
  2154. itp('28state_dbl_wh', function()
  2155. local vt = init()
  2156. local state = wantstate(vt, { g = true })
  2157. -- Single Width, Single Height
  2158. reset(state, nil)
  2159. push('\x1b#5', vt)
  2160. push('Hello', vt)
  2161. expect(
  2162. 'putglyph 48 1 0,0\nputglyph 65 1 0,1\nputglyph 6c 1 0,2\nputglyph 6c 1 0,3\nputglyph 6f 1 0,4'
  2163. )
  2164. -- Double Width, Single Height
  2165. reset(state, nil)
  2166. push('\x1b#6', vt)
  2167. push('Hello', vt)
  2168. expect(
  2169. 'putglyph 48 1 0,0 dwl\nputglyph 65 1 0,1 dwl\nputglyph 6c 1 0,2 dwl\nputglyph 6c 1 0,3 dwl\nputglyph 6f 1 0,4 dwl'
  2170. )
  2171. cursor(0, 5, state)
  2172. push('\x1b[40GAB', vt)
  2173. expect('putglyph 41 1 0,39 dwl\nputglyph 42 1 1,0')
  2174. cursor(1, 1, state)
  2175. -- Double Height
  2176. reset(state, nil)
  2177. push('\x1b#3', vt)
  2178. push('Hello', vt)
  2179. expect(
  2180. 'putglyph 48 1 0,0 dwl dhl-top\nputglyph 65 1 0,1 dwl dhl-top\nputglyph 6c 1 0,2 dwl dhl-top\nputglyph 6c 1 0,3 dwl dhl-top\nputglyph 6f 1 0,4 dwl dhl-top'
  2181. )
  2182. cursor(0, 5, state)
  2183. push('\r\n\x1b#4', vt)
  2184. push('Hello', vt)
  2185. expect(
  2186. 'putglyph 48 1 1,0 dwl dhl-bottom\nputglyph 65 1 1,1 dwl dhl-bottom\nputglyph 6c 1 1,2 dwl dhl-bottom\nputglyph 6c 1 1,3 dwl dhl-bottom\nputglyph 6f 1 1,4 dwl dhl-bottom'
  2187. )
  2188. cursor(1, 5, state)
  2189. -- Double Width scrolling
  2190. reset(state, nil)
  2191. push('\x1b[20H\x1b#6ABC', vt)
  2192. expect('putglyph 41 1 19,0 dwl\nputglyph 42 1 19,1 dwl\nputglyph 43 1 19,2 dwl')
  2193. push('\x1b[25H\n', vt)
  2194. push('\x1b[19;4HDE', vt)
  2195. expect('putglyph 44 1 18,3 dwl\nputglyph 45 1 18,4 dwl')
  2196. push('\x1b[H\x1bM', vt)
  2197. push('\x1b[20;6HFG', vt)
  2198. expect('putglyph 46 1 19,5 dwl\nputglyph 47 1 19,6 dwl')
  2199. end)
  2200. itp('29state_fallback', function()
  2201. local vt = init()
  2202. local state = wantstate(vt, { f = true })
  2203. reset(state, nil)
  2204. -- Unrecognised control
  2205. push('\x03', vt)
  2206. expect('control 03')
  2207. -- Unrecognised CSI
  2208. push('\x1b[?15;2z', vt)
  2209. expect('csi 7a L=3f 15,2')
  2210. -- Unrecognised OSC
  2211. push('\x1b]27;Something\x1b\\', vt)
  2212. expect('osc [27;Something]')
  2213. -- Unrecognised DCS
  2214. push('\x1bPz123\x1b\\', vt)
  2215. expect('dcs [z123]')
  2216. -- Unrecognised APC
  2217. push('\x1b_z123\x1b\\', vt)
  2218. expect('apc [z123]')
  2219. -- Unrecognised PM
  2220. push('\x1b^z123\x1b\\', vt)
  2221. expect('pm [z123]')
  2222. -- Unrecognised SOS
  2223. push('\x1bXz123\x1b\\', vt)
  2224. expect('sos [z123]')
  2225. end)
  2226. itp('30state_pen', function()
  2227. local vt = init()
  2228. local state = wantstate(vt)
  2229. -- Reset
  2230. push('\x1b[m', vt)
  2231. pen('bold', false, state)
  2232. pen('underline', 0, state)
  2233. pen('italic', false, state)
  2234. pen('blink', false, state)
  2235. pen('reverse', false, state)
  2236. pen('font', 0, state)
  2237. -- TODO(dundargoc): fix
  2238. -- ?pen foreground = rgb(240,240,240,is_default_fg)
  2239. -- ?pen background = rgb(0,0,0,is_default_bg)
  2240. -- Bold
  2241. push('\x1b[1m', vt)
  2242. pen('bold', true, state)
  2243. push('\x1b[22m', vt)
  2244. pen('bold', false, state)
  2245. push('\x1b[1m\x1b[m', vt)
  2246. pen('bold', false, state)
  2247. -- Underline
  2248. push('\x1b[4m', vt)
  2249. pen('underline', 1, state)
  2250. push('\x1b[21m', vt)
  2251. pen('underline', 2, state)
  2252. push('\x1b[24m', vt)
  2253. pen('underline', 0, state)
  2254. push('\x1b[4m\x1b[4:0m', vt)
  2255. pen('underline', 0, state)
  2256. push('\x1b[4:1m', vt)
  2257. pen('underline', 1, state)
  2258. push('\x1b[4:2m', vt)
  2259. pen('underline', 2, state)
  2260. push('\x1b[4:3m', vt)
  2261. pen('underline', 3, state)
  2262. push('\x1b[4m\x1b[m', vt)
  2263. pen('underline', 0, state)
  2264. -- Italic
  2265. push('\x1b[3m', vt)
  2266. pen('italic', true, state)
  2267. push('\x1b[23m', vt)
  2268. pen('italic', false, state)
  2269. push('\x1b[3m\x1b[m', vt)
  2270. pen('italic', false, state)
  2271. -- Blink
  2272. push('\x1b[5m', vt)
  2273. pen('blink', true, state)
  2274. push('\x1b[25m', vt)
  2275. pen('blink', false, state)
  2276. push('\x1b[5m\x1b[m', vt)
  2277. pen('blink', false, state)
  2278. -- Reverse
  2279. push('\x1b[7m', vt)
  2280. pen('reverse', true, state)
  2281. push('\x1b[27m', vt)
  2282. pen('reverse', false, state)
  2283. push('\x1b[7m\x1b[m', vt)
  2284. pen('reverse', false, state)
  2285. -- Font Selection
  2286. push('\x1b[11m', vt)
  2287. pen('font', 1, state)
  2288. push('\x1b[19m', vt)
  2289. pen('font', 9, state)
  2290. push('\x1b[10m', vt)
  2291. pen('font', 0, state)
  2292. push('\x1b[11m\x1b[m', vt)
  2293. pen('font', 0, state)
  2294. -- TODO(dundargoc): fix
  2295. -- Foreground
  2296. -- push "\x1b[31m"
  2297. -- ?pen foreground = idx(1)
  2298. -- push "\x1b[32m"
  2299. -- ?pen foreground = idx(2)
  2300. -- push "\x1b[34m"
  2301. -- ?pen foreground = idx(4)
  2302. -- push "\x1b[91m"
  2303. -- ?pen foreground = idx(9)
  2304. -- push "\x1b[38:2:10:20:30m"
  2305. -- ?pen foreground = rgb(10,20,30)
  2306. -- push "\x1b[38:5:1m"
  2307. -- ?pen foreground = idx(1)
  2308. -- push "\x1b[39m"
  2309. -- ?pen foreground = rgb(240,240,240,is_default_fg)
  2310. --
  2311. -- Background
  2312. -- push "\x1b[41m"
  2313. -- ?pen background = idx(1)
  2314. -- push "\x1b[42m"
  2315. -- ?pen background = idx(2)
  2316. -- push "\x1b[44m"
  2317. -- ?pen background = idx(4)
  2318. -- push "\x1b[101m"
  2319. -- ?pen background = idx(9)
  2320. -- push "\x1b[48:2:10:20:30m"
  2321. -- ?pen background = rgb(10,20,30)
  2322. -- push "\x1b[48:5:1m"
  2323. -- ?pen background = idx(1)
  2324. -- push "\x1b[49m"
  2325. -- ?pen background = rgb(0,0,0,is_default_bg)
  2326. --
  2327. -- Bold+ANSI colour == highbright
  2328. -- push "\x1b[m\x1b[1;37m"
  2329. -- ?pen bold = on
  2330. -- ?pen foreground = idx(15)
  2331. -- push "\x1b[m\x1b[37;1m"
  2332. -- ?pen bold = on
  2333. -- ?pen foreground = idx(15)
  2334. --
  2335. -- Super/Subscript
  2336. -- push "\x1b[73m"
  2337. -- ?pen small = on
  2338. -- ?pen baseline = raise
  2339. -- push "\x1b[74m"
  2340. -- ?pen small = on
  2341. -- ?pen baseline = lower
  2342. -- push "\x1b[75m"
  2343. -- ?pen small = off
  2344. -- ?pen baseline = normal
  2345. --
  2346. -- DECSTR resets pen attributes
  2347. -- push "\x1b[1;4m"
  2348. -- ?pen bold = on
  2349. -- ?pen underline = 1
  2350. -- push "\x1b[!p"
  2351. -- ?pen bold = off
  2352. -- ?pen underline = 0
  2353. end)
  2354. itp('31state_rep', function()
  2355. local vt = init()
  2356. local state = wantstate(vt, { g = true })
  2357. -- REP no argument
  2358. reset(state, nil)
  2359. push('a\x1b[b', vt)
  2360. expect('putglyph 61 1 0,0\nputglyph 61 1 0,1')
  2361. -- REP zero (zero should be interpreted as one)
  2362. reset(state, nil)
  2363. push('a\x1b[0b', vt)
  2364. expect('putglyph 61 1 0,0\nputglyph 61 1 0,1')
  2365. -- REP lowercase a times two
  2366. reset(state, nil)
  2367. push('a\x1b[2b', vt)
  2368. expect('putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2')
  2369. -- REP with UTF-8 1 char
  2370. -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
  2371. reset(state, nil)
  2372. push('\xC3\xA9\x1b[b', vt)
  2373. expect('putglyph e9 1 0,0\nputglyph e9 1 0,1')
  2374. -- REP with UTF-8 wide char
  2375. -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
  2376. reset(state, nil)
  2377. push('\xEF\xBC\x90\x1b[b', vt)
  2378. expect('putglyph ff10 2 0,0\nputglyph ff10 2 0,2')
  2379. -- REP with UTF-8 combining character
  2380. reset(state, nil)
  2381. push('e\xCC\x81\x1b[b', vt)
  2382. expect('putglyph 65,301 1 0,0\nputglyph 65,301 1 0,1')
  2383. -- REP till end of line
  2384. reset(state, nil)
  2385. push('a\x1b[1000bb', vt)
  2386. expect(
  2387. 'putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2\nputglyph 61 1 0,3\nputglyph 61 1 0,4\nputglyph 61 1 0,5\nputglyph 61 1 0,6\nputglyph 61 1 0,7\nputglyph 61 1 0,8\nputglyph 61 1 0,9\nputglyph 61 1 0,10\nputglyph 61 1 0,11\nputglyph 61 1 0,12\nputglyph 61 1 0,13\nputglyph 61 1 0,14\nputglyph 61 1 0,15\nputglyph 61 1 0,16\nputglyph 61 1 0,17\nputglyph 61 1 0,18\nputglyph 61 1 0,19\nputglyph 61 1 0,20\nputglyph 61 1 0,21\nputglyph 61 1 0,22\nputglyph 61 1 0,23\nputglyph 61 1 0,24\nputglyph 61 1 0,25\nputglyph 61 1 0,26\nputglyph 61 1 0,27\nputglyph 61 1 0,28\nputglyph 61 1 0,29\nputglyph 61 1 0,30\nputglyph 61 1 0,31\nputglyph 61 1 0,32\nputglyph 61 1 0,33\nputglyph 61 1 0,34\nputglyph 61 1 0,35\nputglyph 61 1 0,36\nputglyph 61 1 0,37\nputglyph 61 1 0,38\nputglyph 61 1 0,39\nputglyph 61 1 0,40\nputglyph 61 1 0,41\nputglyph 61 1 0,42\nputglyph 61 1 0,43\nputglyph 61 1 0,44\nputglyph 61 1 0,45\nputglyph 61 1 0,46\nputglyph 61 1 0,47\nputglyph 61 1 0,48\nputglyph 61 1 0,49\nputglyph 61 1 0,50\nputglyph 61 1 0,51\nputglyph 61 1 0,52\nputglyph 61 1 0,53\nputglyph 61 1 0,54\nputglyph 61 1 0,55\nputglyph 61 1 0,56\nputglyph 61 1 0,57\nputglyph 61 1 0,58\nputglyph 61 1 0,59\nputglyph 61 1 0,60\nputglyph 61 1 0,61\nputglyph 61 1 0,62\nputglyph 61 1 0,63\nputglyph 61 1 0,64\nputglyph 61 1 0,65\nputglyph 61 1 0,66\nputglyph 61 1 0,67\nputglyph 61 1 0,68\nputglyph 61 1 0,69\nputglyph 61 1 0,70\nputglyph 61 1 0,71\nputglyph 61 1 0,72\nputglyph 61 1 0,73\nputglyph 61 1 0,74\nputglyph 61 1 0,75\nputglyph 61 1 0,76\nputglyph 61 1 0,77\nputglyph 61 1 0,78\nputglyph 61 1 0,79\nputglyph 62 1 1,0'
  2388. )
  2389. end)
  2390. itp('32state_flow', function()
  2391. local vt = init()
  2392. local state = wantstate(vt)
  2393. -- Many of these test cases inspired by
  2394. -- https://blueprints.launchpad.net/libvterm/+spec/reflow-cases
  2395. -- Spillover text marks continuation on second line
  2396. reset(state, nil)
  2397. push(string.rep('A', 100), vt)
  2398. push('\r\n', vt)
  2399. lineinfo(0, {}, state)
  2400. lineinfo(1, { cont = true }, state)
  2401. -- CRLF in column 80 does not mark continuation
  2402. reset(state, nil)
  2403. push(string.rep('B', 80), vt)
  2404. push('\r\n', vt)
  2405. push(string.rep('B', 20), vt)
  2406. push('\r\n', vt)
  2407. lineinfo(0, {}, state)
  2408. lineinfo(1, {}, state)
  2409. -- EL cancels continuation of following line
  2410. reset(state, nil)
  2411. push(string.rep('D', 100), vt)
  2412. lineinfo(1, { cont = true }, state)
  2413. push('\x1bM\x1b[79G\x1b[K', vt)
  2414. lineinfo(1, {}, state)
  2415. end)
  2416. itp('40state_selection', function()
  2417. local vt = init()
  2418. wantstate(vt)
  2419. -- Set clipboard; final chunk len 4
  2420. push('\x1b]52;c;SGVsbG8s\x1b\\', vt)
  2421. expect('selection-set mask=0001 [Hello,]')
  2422. -- Set clipboard; final chunk len 3
  2423. push('\x1b]52;c;SGVsbG8sIHc=\x1b\\', vt)
  2424. expect('selection-set mask=0001 [Hello, w]')
  2425. -- Set clipboard; final chunk len 2
  2426. push('\x1b]52;c;SGVsbG8sIHdvcmxkCg==\x1b\\', vt)
  2427. expect('selection-set mask=0001 [Hello, world\n]')
  2428. -- Set clipboard; split between chunks
  2429. push('\x1b]52;c;SGVs', vt)
  2430. expect('selection-set mask=0001 [Hel')
  2431. push('bG8s\x1b\\', vt)
  2432. expect('selection-set mask=0001 lo,]')
  2433. -- Set clipboard; split within chunk
  2434. push('\x1b]52;c;SGVsbG', vt)
  2435. expect('selection-set mask=0001 [Hel')
  2436. push('8s\x1b\\', vt)
  2437. expect('selection-set mask=0001 lo,]')
  2438. -- Set clipboard; empty first chunk
  2439. push('\x1b]52;c;', vt)
  2440. push('SGVsbG8s\x1b\\', vt)
  2441. expect('selection-set mask=0001 [Hello,]')
  2442. -- Set clipboard; empty final chunk
  2443. push('\x1b]52;c;SGVsbG8s', vt)
  2444. expect('selection-set mask=0001 [Hello,')
  2445. push('\x1b\\', vt)
  2446. expect('selection-set mask=0001 ]')
  2447. -- Set clipboard; longer than buffer
  2448. push('\x1b]52;c;' .. string.rep('LS0t', 10) .. '\x1b\\', vt)
  2449. expect('selection-set mask=0001 [---------------\nselection-set mask=0001 ---------------]')
  2450. -- Clear clipboard
  2451. push('\x1b]52;c;\x1b\\', vt)
  2452. expect('selection-set mask=0001 []')
  2453. -- Set invalid data clears and ignores
  2454. push('\x1b]52;c;SGVs*SGVsbG8s\x1b\\', vt)
  2455. expect('selection-set mask=0001 []')
  2456. -- Query clipboard
  2457. push('\x1b]52;c;?\x1b\\', vt)
  2458. expect('selection-query mask=0001')
  2459. -- TODO(dundargoc): fix
  2460. -- Send clipboard; final chunk len 4
  2461. -- SELECTION 1 ["Hello,"]
  2462. -- output "\x1b]52;c;"
  2463. -- output "SGVsbG8s"
  2464. -- output "\x1b\\"
  2465. --
  2466. -- Send clipboard; final chunk len 3
  2467. -- SELECTION 1 ["Hello, w"]
  2468. -- output "\x1b]52;c;"
  2469. -- output "SGVsbG8s"
  2470. -- output "IHc=\x1b\\"
  2471. --
  2472. -- Send clipboard; final chunk len 2
  2473. -- SELECTION 1 ["Hello, world\n"]
  2474. -- output "\x1b]52;c;"
  2475. -- output "SGVsbG8sIHdvcmxk"
  2476. -- output "Cg==\x1b\\"
  2477. --
  2478. -- Send clipboard; split between chunks
  2479. -- SELECTION 1 ["Hel"
  2480. -- output "\x1b]52;c;"
  2481. -- output "SGVs"
  2482. -- SELECTION 1 "lo,"]
  2483. -- output "bG8s"
  2484. -- output "\x1b\\"
  2485. --
  2486. -- Send clipboard; split within chunk
  2487. -- SELECTION 1 ["Hello"
  2488. -- output "\x1b]52;c;"
  2489. -- output "SGVs"
  2490. -- SELECTION 1 ","]
  2491. -- output "bG8s"
  2492. -- output "\x1b\\"
  2493. end)
  2494. itp('60screen_ascii', function()
  2495. local vt = init()
  2496. local screen = wantscreen(vt, { a = true, c = true })
  2497. -- Get
  2498. reset(nil, screen)
  2499. push('ABC', vt)
  2500. expect('movecursor 0,3')
  2501. screen_chars(0, 0, 1, 3, 'ABC', screen)
  2502. screen_chars(0, 0, 1, 80, 'ABC', screen)
  2503. screen_text(0, 0, 1, 3, '41,42,43', screen)
  2504. screen_text(0, 0, 1, 80, '41,42,43', screen)
  2505. screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2506. screen_cell(0, 1, '{42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2507. screen_cell(0, 2, '{43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2508. screen_row(0, 'ABC', screen)
  2509. screen_eol(0, 0, 0, screen)
  2510. screen_eol(0, 2, 0, screen)
  2511. screen_eol(0, 3, 1, screen)
  2512. push('\x1b[H', vt)
  2513. expect('movecursor 0,0')
  2514. screen_row(0, 'ABC', screen)
  2515. screen_text(0, 0, 1, 80, '41,42,43', screen)
  2516. push('E', vt)
  2517. expect('movecursor 0,1')
  2518. screen_row(0, 'EBC', screen)
  2519. screen_text(0, 0, 1, 80, '45,42,43', screen)
  2520. screen = wantscreen(vt, { a = true })
  2521. -- Erase
  2522. reset(nil, screen)
  2523. push('ABCDE\x1b[H\x1b[K', vt)
  2524. -- TODO(dundargoc): fix
  2525. -- screen_row(0, '', screen)
  2526. screen_text(0, 0, 1, 80, '', screen)
  2527. -- Copycell
  2528. reset(nil, screen)
  2529. push('ABC\x1b[H\x1b[@', vt)
  2530. push('1', vt)
  2531. screen_row(0, '1ABC', screen)
  2532. reset(nil, screen)
  2533. push('ABC\x1b[H\x1b[P', vt)
  2534. screen_chars(0, 0, 1, 1, 'B', screen)
  2535. screen_chars(0, 1, 1, 2, 'C', screen)
  2536. screen_chars(0, 0, 1, 80, 'BC', screen)
  2537. -- Space padding
  2538. reset(nil, screen)
  2539. push('Hello\x1b[CWorld', vt)
  2540. screen_row(0, 'Hello World', screen)
  2541. screen_text(0, 0, 1, 80, '48,65,6c,6c,6f,20,57,6f,72,6c,64', screen)
  2542. -- Linefeed padding
  2543. reset(nil, screen)
  2544. push('Hello\r\nWorld', vt)
  2545. screen_chars(0, 0, 2, 80, 'Hello\nWorld', screen)
  2546. screen_text(0, 0, 2, 80, '48,65,6c,6c,6f,0a,57,6f,72,6c,64', screen)
  2547. -- Altscreen
  2548. reset(nil, screen)
  2549. push('P', vt)
  2550. screen_row(0, 'P', screen)
  2551. -- TODO(dundargoc): fix
  2552. -- push('\x1b[?1049h', vt)
  2553. -- screen_row(0, '', screen)
  2554. -- push('\x1b[2K\x1b[HA', vt)
  2555. -- screen_row(0, 'A', screen)
  2556. -- push('\x1b[?1049l', vt)
  2557. -- screen_row(0, 'P', screen)
  2558. end)
  2559. itp('61screen_unicode', function()
  2560. local vt = init()
  2561. local screen = wantscreen(vt)
  2562. -- Single width UTF-8
  2563. -- U+00C1 = C3 81 name: LATIN CAPITAL LETTER A WITH ACUTE
  2564. -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE
  2565. reset(nil, screen)
  2566. push('\xC3\x81\xC3\xA9', vt)
  2567. screen_row(0, 'Áé', screen)
  2568. screen_text(0, 0, 1, 80, 'c3,81,c3,a9', screen)
  2569. screen_cell(0, 0, '{c1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2570. -- Wide char
  2571. -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO
  2572. reset(nil, screen)
  2573. push('0123\x1b[H', vt)
  2574. push('\xEF\xBC\x90', vt)
  2575. screen_row(0, '023', screen)
  2576. screen_text(0, 0, 1, 80, 'ef,bc,90,32,33', screen)
  2577. screen_cell(0, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2578. -- Combining char
  2579. -- U+0301 = CC 81 name: COMBINING ACUTE
  2580. reset(nil, screen)
  2581. push('0123\x1b[H', vt)
  2582. push('e\xCC\x81', vt)
  2583. screen_row(0, 'é123', screen)
  2584. screen_text(0, 0, 1, 80, '65,cc,81,31,32,33', screen)
  2585. screen_cell(0, 0, '{65,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2586. -- 10 combining accents should not crash
  2587. reset(nil, screen)
  2588. push('e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A', vt)
  2589. screen_cell(
  2590. 0,
  2591. 0,
  2592. '{65,301,302,303,304,305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
  2593. screen
  2594. )
  2595. -- 40 combining accents in two split writes of 20 should not crash
  2596. reset(nil, screen)
  2597. push(
  2598. 'e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81',
  2599. vt
  2600. )
  2601. push(
  2602. '\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81',
  2603. vt
  2604. )
  2605. screen_cell(
  2606. 0,
  2607. 0,
  2608. '{65,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
  2609. screen
  2610. )
  2611. -- Outputing CJK doublewidth in 80th column should wraparound to next line and not crash"
  2612. reset(nil, screen)
  2613. push('\x1b[80G\xEF\xBC\x90', vt)
  2614. screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2615. screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2616. end)
  2617. pending('62screen_damage', function() end)
  2618. itp('63screen_resize', function()
  2619. local vt = init()
  2620. local state = wantstate(vt)
  2621. local screen = wantscreen(vt)
  2622. -- Resize wider preserves cells
  2623. reset(state, screen)
  2624. resize(25, 80, vt)
  2625. push('AB\r\nCD', vt)
  2626. screen_chars(0, 0, 1, 80, 'AB', screen)
  2627. screen_chars(1, 0, 2, 80, 'CD', screen)
  2628. resize(25, 100, vt)
  2629. screen_chars(0, 0, 1, 100, 'AB', screen)
  2630. screen_chars(1, 0, 2, 100, 'CD', screen)
  2631. -- Resize wider allows print in new area
  2632. reset(state, screen)
  2633. resize(25, 80, vt)
  2634. push('AB\x1b[79GCD', vt)
  2635. screen_chars(0, 0, 1, 2, 'AB', screen)
  2636. screen_chars(0, 78, 1, 80, 'CD', screen)
  2637. resize(25, 100, vt)
  2638. screen_chars(0, 0, 1, 2, 'AB', screen)
  2639. screen_chars(0, 78, 1, 80, 'CD', screen)
  2640. push('E', vt)
  2641. screen_chars(0, 78, 1, 81, 'CDE', screen)
  2642. -- Resize shorter with blanks just truncates
  2643. reset(state, screen)
  2644. resize(25, 80, vt)
  2645. push('Top\x1b[10HLine 10', vt)
  2646. screen_row(0, 'Top', screen)
  2647. screen_row(9, 'Line 10', screen)
  2648. cursor(9, 7, state)
  2649. resize(20, 80, vt)
  2650. screen_row(0, 'Top', screen)
  2651. screen_row(9, 'Line 10', screen)
  2652. cursor(9, 7, state)
  2653. -- Resize shorter with content must scroll
  2654. reset(state, screen)
  2655. resize(25, 80, vt)
  2656. push('Top\x1b[25HLine 25\x1b[15H', vt)
  2657. screen_row(0, 'Top', screen)
  2658. screen_row(24, 'Line 25', screen)
  2659. cursor(14, 0, state)
  2660. screen = wantscreen(vt, { b = true })
  2661. resize(20, 80, vt)
  2662. expect(
  2663. 'sb_pushline 80 = 54 6F 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
  2664. )
  2665. -- TODO(dundargoc): fix or remove
  2666. -- screen_row( 0 , "",screen)
  2667. screen_row(19, 'Line 25', screen)
  2668. cursor(9, 0, state)
  2669. -- Resize shorter does not lose line with cursor
  2670. -- See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088
  2671. reset(state, screen)
  2672. wantscreen(vt)
  2673. resize(25, 80, vt)
  2674. screen = wantscreen(vt, { b = true })
  2675. push('\x1b[24HLine 24\r\nLine 25\r\n', vt)
  2676. expect('sb_pushline 80 =')
  2677. screen_row(23, 'Line 25', screen)
  2678. cursor(24, 0, state)
  2679. resize(24, 80, vt)
  2680. expect('sb_pushline 80 =')
  2681. screen_row(22, 'Line 25', screen)
  2682. cursor(23, 0, state)
  2683. -- Resize shorter does not send the cursor to a negative row
  2684. -- See also https://github.com/vim/vim/pull/6141
  2685. reset(state, screen)
  2686. wantscreen(vt)
  2687. resize(25, 80, vt)
  2688. screen = wantscreen(vt, { b = true })
  2689. push('\x1b[24HLine 24\r\nLine 25\x1b[H', vt)
  2690. cursor(0, 0, state)
  2691. resize(20, 80, vt)
  2692. expect(
  2693. 'sb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
  2694. )
  2695. cursor(0, 0, state)
  2696. -- Resize taller attempts to pop scrollback
  2697. reset(state, screen)
  2698. screen = wantscreen(vt)
  2699. resize(25, 80, vt)
  2700. push('Line 1\x1b[25HBottom\x1b[15H', vt)
  2701. screen_row(0, 'Line 1', screen)
  2702. screen_row(24, 'Bottom', screen)
  2703. cursor(14, 0, state)
  2704. screen = wantscreen(vt, { b = true })
  2705. resize(30, 80, vt)
  2706. expect('sb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80')
  2707. screen_row(0, 'ABCDE', screen)
  2708. screen_row(5, 'Line 1', screen)
  2709. screen_row(29, 'Bottom', screen)
  2710. cursor(19, 0, state)
  2711. screen = wantscreen(vt)
  2712. -- Resize can operate on altscreen
  2713. reset(state, screen)
  2714. screen = wantscreen(vt, { a = true })
  2715. resize(25, 80, vt)
  2716. push('Main screen\x1b[?1049h\x1b[HAlt screen', vt)
  2717. resize(30, 80, vt)
  2718. screen_row(0, 'Alt screen', screen)
  2719. push('\x1b[?1049l', vt)
  2720. screen_row(0, 'Main screen', screen)
  2721. end)
  2722. itp('64screen_pen', function()
  2723. local vt = init()
  2724. local screen = wantscreen(vt)
  2725. reset(nil, screen)
  2726. -- Plain
  2727. push('A', vt)
  2728. screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2729. -- Bold
  2730. push('\x1b[1mB', vt)
  2731. screen_cell(0, 1, '{42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2732. -- Italic
  2733. push('\x1b[3mC', vt)
  2734. screen_cell(0, 2, '{43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2735. -- Underline
  2736. push('\x1b[4mD', vt)
  2737. screen_cell(0, 3, '{44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2738. -- Reset
  2739. push('\x1b[mE', vt)
  2740. screen_cell(0, 4, '{45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2741. -- Font
  2742. push('\x1b[11mF\x1b[m', vt)
  2743. screen_cell(0, 5, '{46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2744. -- Foreground
  2745. push('\x1b[31mG\x1b[m', vt)
  2746. screen_cell(0, 6, '{47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen)
  2747. -- Background
  2748. push('\x1b[42mH\x1b[m', vt)
  2749. screen_cell(0, 7, '{48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)', screen)
  2750. -- Super/subscript
  2751. push('x\x1b[74m0\x1b[73m2\x1b[m', vt)
  2752. screen_cell(0, 8, '{78} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2753. screen_cell(0, 9, '{30} width=1 attrs={S_} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2754. screen_cell(0, 10, '{32} width=1 attrs={S^} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2755. -- EL sets only colours to end of line, not other attrs
  2756. push('\x1b[H\x1b[7;33;44m\x1b[K', vt)
  2757. screen_cell(0, 0, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
  2758. screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
  2759. -- DECSCNM xors reverse for entire screen
  2760. push('R\x1b[?5h', vt)
  2761. screen_cell(0, 0, '{52} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
  2762. screen_cell(1, 0, '{} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2763. push('\x1b[?5$p', vt)
  2764. expect_output('\x1b[?5;1$y')
  2765. push('\x1b[?5l', vt)
  2766. screen_cell(0, 0, '{52} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen)
  2767. screen_cell(1, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2768. -- TODO(dundargoc): fix
  2769. -- push('\x1b[?5$p')
  2770. -- expect_output('\x1b[?5;2$y')
  2771. -- Set default colours
  2772. reset(nil, screen)
  2773. push('ABC\x1b[31mDEF\x1b[m', vt)
  2774. screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2775. screen_cell(0, 3, '{44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen)
  2776. -- TODO(dundargoc): fix
  2777. -- SETDEFAULTCOL rgb(252,253,254)
  2778. -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(252,253,254) bg=rgb(0,0,0)
  2779. -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)
  2780. -- SETDEFAULTCOL rgb(250,250,250) rgb(10,20,30)
  2781. -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(250,250,250) bg=rgb(10,20,30)
  2782. -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(10,20,30)
  2783. end)
  2784. itp('65screen_protect', function()
  2785. local vt = init()
  2786. local screen = wantscreen(vt)
  2787. -- Selective erase
  2788. reset(nil, screen)
  2789. push('A\x1b[1"qB\x1b["qC', vt)
  2790. screen_row(0, 'ABC', screen)
  2791. push('\x1b[G\x1b[?J', vt)
  2792. screen_row(0, ' B', screen)
  2793. -- Non-selective erase
  2794. reset(nil, screen)
  2795. push('A\x1b[1"qB\x1b["qC', vt)
  2796. screen_row(0, 'ABC', screen)
  2797. -- TODO(dundargoc): fix
  2798. -- push('\x1b[G\x1b[J', vt)
  2799. -- screen_row(0, '', screen)
  2800. end)
  2801. itp('66screen_extent', function()
  2802. local vt = init()
  2803. local screen = wantscreen(vt)
  2804. -- Bold extent
  2805. reset(nil, screen)
  2806. push('AB\x1b[1mCD\x1b[mE', vt)
  2807. screen_attrs_extent(0, 0, '0,0-1,1', screen)
  2808. screen_attrs_extent(0, 1, '0,0-1,1', screen)
  2809. screen_attrs_extent(0, 2, '0,2-1,3', screen)
  2810. screen_attrs_extent(0, 3, '0,2-1,3', screen)
  2811. screen_attrs_extent(0, 4, '0,4-1,79', screen)
  2812. end)
  2813. itp('67screen_dbl_wh', function()
  2814. local vt = init()
  2815. local screen = wantscreen(vt)
  2816. reset(nil, screen)
  2817. -- Single Width, Single Height
  2818. reset(nil, screen)
  2819. push('\x1b#5', vt)
  2820. push('abcde', vt)
  2821. screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2822. -- Double Width, Single Height
  2823. reset(nil, screen)
  2824. push('\x1b#6', vt)
  2825. push('abcde', vt)
  2826. screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2827. -- Double Height
  2828. reset(nil, screen)
  2829. push('\x1b#3', vt)
  2830. push('abcde', vt)
  2831. push('\r\n\x1b#4', vt)
  2832. push('abcde', vt)
  2833. screen_cell(0, 0, '{61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2834. screen_cell(
  2835. 1,
  2836. 0,
  2837. '{61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)',
  2838. screen
  2839. )
  2840. -- Late change
  2841. reset(nil, screen)
  2842. push('abcde', vt)
  2843. screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2844. push('\x1b#6', vt)
  2845. screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2846. -- DWL doesn't spill over on scroll
  2847. reset(nil, screen)
  2848. push('\x1b[25H\x1b#6Final\r\n', vt)
  2849. screen_cell(23, 0, '{46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2850. screen_cell(24, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
  2851. end)
  2852. itp('68screen_termprops', function()
  2853. local vt = init()
  2854. local screen = wantscreen(vt, { p = true })
  2855. reset(nil, screen)
  2856. expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1')
  2857. -- Cursor visibility
  2858. push('\x1b[?25h', vt)
  2859. expect('settermprop 1 true')
  2860. push('\x1b[?25l', vt)
  2861. expect('settermprop 1 false')
  2862. -- Title
  2863. push('\x1b]2;Here is my title\a', vt)
  2864. expect('settermprop 4 ["Here is my title"]')
  2865. end)
  2866. itp('69screen_pushline', function()
  2867. local vt = init()
  2868. -- Run these tests on a much smaller default screen, so debug output is nowhere near as noisy
  2869. resize(5, 10, vt)
  2870. local state = wantstate(vt)
  2871. local screen = wantscreen(vt, { r = true })
  2872. reset(state, screen)
  2873. -- Resize wider reflows wide lines
  2874. reset(state, screen)
  2875. push(string.rep('A', 12), vt)
  2876. screen_row(0, 'AAAAAAAAAA', screen, vt.cols)
  2877. screen_row(1, 'AA', screen, vt.cols)
  2878. lineinfo(1, { cont = true }, state)
  2879. cursor(1, 2, state)
  2880. resize(5, 15, vt)
  2881. screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols)
  2882. -- TODO(dundargoc): fix
  2883. -- screen_row(1, '', screen, vt.cols)
  2884. lineinfo(1, {}, state)
  2885. cursor(0, 12, state)
  2886. resize(5, 20, vt)
  2887. screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols)
  2888. -- TODO(dundargoc): fix
  2889. -- screen_row( 1 ,'',screen, vt.cols)
  2890. lineinfo(1, {}, state)
  2891. cursor(0, 12, state)
  2892. -- Resize narrower can create continuation lines
  2893. reset(state, screen)
  2894. resize(5, 10, vt)
  2895. push('ABCDEFGHI', vt)
  2896. screen_row(0, 'ABCDEFGHI', screen, vt.cols)
  2897. -- TODO(dundargoc): fix
  2898. -- screen_row( 1 , "",screen, vt.cols)
  2899. lineinfo(1, {}, state)
  2900. cursor(0, 9, state)
  2901. resize(5, 8, vt)
  2902. -- TODO(dundargoc): fix
  2903. -- screen_row( 0 , "ABCDEFGH",screen,vt.cols)
  2904. screen_row(1, 'I', screen, vt.cols)
  2905. lineinfo(1, { cont = true }, state)
  2906. cursor(1, 1, state)
  2907. resize(5, 6, vt)
  2908. screen_row(0, 'ABCDEF', screen, vt.cols)
  2909. screen_row(1, 'GHI', screen, vt.cols)
  2910. lineinfo(1, { cont = true }, state)
  2911. cursor(1, 3, state)
  2912. -- Shell wrapped prompt behaviour
  2913. reset(state, screen)
  2914. resize(5, 10, vt)
  2915. push('PROMPT GOES HERE\r\n> \r\n\r\nPROMPT GOES HERE\r\n> ', vt)
  2916. screen_row(0, '> ', screen, vt.cols)
  2917. -- TODO(dundargoc): fix
  2918. -- screen_row( 1 , "",screen,vt.cols)
  2919. screen_row(2, 'PROMPT GOE', screen, vt.cols)
  2920. screen_row(3, 'S HERE', screen, vt.cols)
  2921. lineinfo(3, { cont = true }, state)
  2922. screen_row(4, '> ', screen, vt.cols)
  2923. cursor(4, 2, state)
  2924. resize(5, 11, vt)
  2925. screen_row(0, '> ', screen, vt.cols)
  2926. -- TODO(dundargoc): fix
  2927. -- screen_row( 1 , "",screen,vt.cols)
  2928. screen_row(2, 'PROMPT GOES', screen, vt.cols)
  2929. screen_row(3, ' HERE', screen, vt.cols)
  2930. lineinfo(3, { cont = true }, state)
  2931. screen_row(4, '> ', screen, vt.cols)
  2932. cursor(4, 2, state)
  2933. resize(5, 12, vt)
  2934. screen_row(0, '> ', screen, vt.cols)
  2935. -- TODO(dundargoc): fix
  2936. -- screen_row( 1 , "",screen,vt.cols)
  2937. screen_row(2, 'PROMPT GOES ', screen, vt.cols)
  2938. screen_row(3, 'HERE', screen, vt.cols)
  2939. lineinfo(3, { cont = true }, state)
  2940. screen_row(4, '> ', screen, vt.cols)
  2941. cursor(4, 2, state)
  2942. resize(5, 16, vt)
  2943. screen_row(0, '> ', screen, vt.cols)
  2944. -- TODO(dundargoc): fix
  2945. -- screen_row( 1 , "",screen,vt.cols)
  2946. -- screen_row( 2 , "PROMPT GOES HERE",screen,vt.cols)
  2947. lineinfo(3, {}, state)
  2948. screen_row(3, '> ', screen, vt.cols)
  2949. cursor(3, 2, state)
  2950. -- Cursor goes missing
  2951. -- For more context: https://github.com/neovim/neovim/pull/21124
  2952. reset(state, screen)
  2953. resize(5, 5, vt)
  2954. resize(3, 1, vt)
  2955. push('\x1b[2;1Habc\r\n\x1b[H', vt)
  2956. resize(1, 1, vt)
  2957. cursor(0, 0, state)
  2958. end)
  2959. pending('90vttest_01-movement-1', function() end)
  2960. pending('90vttest_01-movement-2', function() end)
  2961. itp('90vttest_01-movement-3', function()
  2962. -- Test of cursor-control characters inside ESC sequences
  2963. local vt = init()
  2964. local state = wantstate(vt)
  2965. local screen = wantscreen(vt)
  2966. reset(state, screen)
  2967. push('A B C D E F G H I', vt)
  2968. push('\x0d\x0a', vt)
  2969. push('A\x1b[2\bCB\x1b[2\bCC\x1b[2\bCD\x1b[2\bCE\x1b[2\bCF\x1b[2\bCG\x1b[2\bCH\x1b[2\bCI', vt)
  2970. push('\x0d\x0a', vt)
  2971. push(
  2972. 'A \x1b[\x0d2CB\x1b[\x0d4CC\x1b[\x0d6CD\x1b[\x0d8CE\x1b[\x0d10CF\x1b[\x0d12CG\x1b[\x0d14CH\x1b[\x0d16CI',
  2973. vt
  2974. )
  2975. push('\x0d\x0a', vt)
  2976. push(
  2977. 'A \x1b[1\x0bAB \x1b[1\x0bAC \x1b[1\x0bAD \x1b[1\x0bAE \x1b[1\x0bAF \x1b[1\x0bAG \x1b[1\x0bAH \x1b[1\x0bAI \x1b[1\x0bA',
  2978. vt
  2979. )
  2980. -- Output
  2981. for i = 0, 2 do
  2982. screen_row(i, 'A B C D E F G H I', screen)
  2983. end
  2984. screen_row(3, 'A B C D E F G H I ', screen)
  2985. cursor(3, 18, state)
  2986. end)
  2987. itp('90vttest_01-movement-4', function()
  2988. -- Test of leading zeroes in ESC sequences
  2989. local vt = init()
  2990. local screen = wantscreen(vt)
  2991. reset(nil, screen)
  2992. push('\x1b[00000000004;000000001HT', vt)
  2993. push('\x1b[00000000004;000000002Hh', vt)
  2994. push('\x1b[00000000004;000000003Hi', vt)
  2995. push('\x1b[00000000004;000000004Hs', vt)
  2996. push('\x1b[00000000004;000000005H ', vt)
  2997. push('\x1b[00000000004;000000006Hi', vt)
  2998. push('\x1b[00000000004;000000007Hs', vt)
  2999. push('\x1b[00000000004;000000008H ', vt)
  3000. push('\x1b[00000000004;000000009Ha', vt)
  3001. push('\x1b[00000000004;0000000010H ', vt)
  3002. push('\x1b[00000000004;0000000011Hc', vt)
  3003. push('\x1b[00000000004;0000000012Ho', vt)
  3004. push('\x1b[00000000004;0000000013Hr', vt)
  3005. push('\x1b[00000000004;0000000014Hr', vt)
  3006. push('\x1b[00000000004;0000000015He', vt)
  3007. push('\x1b[00000000004;0000000016Hc', vt)
  3008. push('\x1b[00000000004;0000000017Ht', vt)
  3009. push('\x1b[00000000004;0000000018H ', vt)
  3010. push('\x1b[00000000004;0000000019Hs', vt)
  3011. push('\x1b[00000000004;0000000020He', vt)
  3012. push('\x1b[00000000004;0000000021Hn', vt)
  3013. push('\x1b[00000000004;0000000022Ht', vt)
  3014. push('\x1b[00000000004;0000000023He', vt)
  3015. push('\x1b[00000000004;0000000024Hn', vt)
  3016. push('\x1b[00000000004;0000000025Hc', vt)
  3017. push('\x1b[00000000004;0000000026He', vt)
  3018. -- Output
  3019. screen_row(3, 'This is a correct sentence', screen)
  3020. end)
  3021. pending('90vttest_02-screen-1', function() end)
  3022. pending('90vttest_02-screen-2', function() end)
  3023. itp('90vttest_02-screen-3', function()
  3024. -- Origin mode
  3025. local vt = init()
  3026. local screen = wantscreen(vt)
  3027. reset(nil, screen)
  3028. push('\x1b[?6h', vt)
  3029. push('\x1b[23;24r', vt)
  3030. push('\n', vt)
  3031. push('Bottom', vt)
  3032. push('\x1b[1;1H', vt)
  3033. push('Above', vt)
  3034. -- Output
  3035. screen_row(22, 'Above', screen)
  3036. screen_row(23, 'Bottom', screen)
  3037. end)
  3038. itp('90vttest_02-screen-4', function()
  3039. -- Origin mode (2)
  3040. local vt = init()
  3041. local screen = wantscreen(vt)
  3042. reset(nil, screen)
  3043. push('\x1b[?6l', vt)
  3044. push('\x1b[23;24r', vt)
  3045. push('\x1b[24;1H', vt)
  3046. push('Bottom', vt)
  3047. push('\x1b[1;1H', vt)
  3048. push('Top', vt)
  3049. -- Output
  3050. screen_row(23, 'Bottom', screen)
  3051. screen_row(0, 'Top', screen)
  3052. end)
  3053. itp('Mouse reporting should not break by idempotent DECSM 1002', function()
  3054. -- Regression test for https://bugs.launchpad.net/libvterm/+bug/1640917
  3055. -- Related: https://github.com/neovim/neovim/issues/5583
  3056. local vt = init()
  3057. wantstate(vt, {})
  3058. push('\x1b[?1002h', vt)
  3059. mousemove(0, 0, vt)
  3060. mousebtn('d', 1, vt)
  3061. expect_output('\x1b[M\x20\x21\x21')
  3062. mousemove(1, 0, vt)
  3063. expect_output('\x1b[M\x40\x21\x22')
  3064. push('\x1b[?1002h', vt)
  3065. mousemove(2, 0, vt)
  3066. expect_output('\x1b[M\x40\x21\x23')
  3067. end)
  3068. end)