vterm_spec.lua 105 KB

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