123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181(* Copyright (c) 2016-2017 David Kaloper Meršinjak. All rights reserved.
See LICENSE.md. *)openNottyexternalc_winsize:Unix.file_descr->int="caml_notty_winsize"[@@noalloc]externalwinch_number:unit->int="caml_notty_winch_number"[@@noalloc]letiterf=functionSomex->fx|_->()letvaluex=functionSomea->a|_->xletwinsizefd=matchc_winsizefdwith|0->None|wh->Some(whlsr16,whlsr1land0x7fff)modulePrivate=structletoncef=letv=lazy(f())infun()->Lazy.forcevletcap_for_fd=letopenCapinmatchSys.getenv"TERM"with|exceptionNot_found->fun_->dumb|(""|"dumb")->fun_->dumb|_->funfd->ifUnix.isattyfdthenansielsedumbletsetup_tcattr~nosigfd=letopenUnixintrylettc=tcgetattrfdinlettc1={tcwithc_icanon=false;c_echo=false}intcsetattrfdTCSANOW(ifnosigthen{tc1withc_isig=false;c_ixon=false}elsetc1);`Revert(once@@fun_->tcsetattrfdTCSANOWtc)withUnix_error(ENOTTY,_,_)->`Revertignoreletset_winch_handlerf=letsignum=winch_number()inletold_hdl=Sys.(signalsignum(Signal_handle(fun_->f())))in`Revert(once@@fun()->Sys.set_signalsignumold_hdl)moduleGen_output(O:sigtypefdtypekvaldef:fdvalto_fd:fd->Unix.file_descrvalwrite:fd->Buffer.t->kend)=structletscratch=lazy(Buffer.create4096)letoutput?cap?(fd=O.def)f=letcap=cap|>value(cap_for_fd(O.to_fdfd))inletbuf=Lazy.forcescratchinBuffer.resetbuf;fbufcapfd;O.writefdbufletoutput_image_size?cap?fdf=output?cap?fd@@funbufcapfd->letsize=winsize(O.to_fdfd)inleti=f(value(80,24)size)inletdim=matchsizewith|Some(w,_)->I.(w,heighti)|None->I.(widthi,heighti)inRender.to_bufferbufcap(0,0)dimiletshow_cursor?cap?fdx=output?cap?fd@@funbufcap_->Direct.show_cursorbufcapxletmove_cursor?cap?fdx=output?cap?fd@@funbufcap_->Direct.move_cursorbufcapxletoutput_image?cap?fdi=output_image_size?cap?fd(fun_->i)leteoli=I.(i<->void01)endendopenPrivatemoduleTerm=structmoduleWinch=structleth=Hashtbl.create3andid=ref0letaddfdf=letn=!idinset_winch_handler(fun()->Hashtbl.iter(fun_f->f())h)|>ignore;Hashtbl.addhn(fun()->winsizefd|>iterf);incrid;`Revert(fun()->Hashtbl.removehn)endmoduleInput=structtypet={fd:Unix.file_descr;flt:Unescape.t;ibuf:bytes;cleanup:unit->unit}letbsize=1024letcreate~nosigfd=letflt=Unescape.create()andibuf=Bytes.createbsizeand`Revertcleanup=setup_tcattr~nosigfdin{fd;flt;ibuf;cleanup}letreceventt=matchUnescape.nextt.fltwith|#Unescape.event|`Endasr->r|`Await->letn=Unix.readt.fdt.ibuf0bsizeinUnescape.inputt.fltt.ibuf0n;eventtendtypet={output:out_channel;trm:Tmachine.t;buf:Buffer.t;input:Input.t;fds:Unix.file_descr*Unix.file_descr;unwinch:(unit->unit)Lazy.t;mutablewinched:bool}letwritet=Buffer.cleart.buf;Tmachine.outputt.trmt.buf;Buffer.output_buffert.outputt.buf;flusht.outputletset_sizetdim=Tmachine.set_sizet.trmdimletrefresht=Tmachine.refresht.trm;writetletimagetimage=Tmachine.imaget.trmimage;writetletcursortcurs=Tmachine.cursort.trmcurs;writetletsizet=Tmachine.sizet.trmletreleaset=ifTmachine.releaset.trmthen(Lazy.forcet.unwinch();t.input.Input.cleanup();writet)letcreate?(dispose=true)?(nosig=true)?(mouse=true)?(bpaste=true)?(input=Unix.stdin)?(output=Unix.stdout)()=letrect={output=Unix.out_channel_of_descroutput;trm=Tmachine.create~mouse~bpaste(cap_for_fdinput);buf=Buffer.create4096;input=Input.create~nosiginput;fds=(input,output);winched=false;unwinch=lazy(let`Revertf=Winch.addoutput@@fundim->Buffer.resett.buf;t.winched<-true;set_sizetdiminf)}inwinsizeoutput|>iter(set_sizet);(Lazy.forcet.unwinch|>ignore)[@ocaml.warning"-5"];ifdisposethenat_exit(fun()->releaset);writet;tletrecevent=function|twhenTmachine.deadt.trm->`End|twhent.winched->t.winched<-false;`Resize(sizet)|t->Unix.(tryInput.eventt.inputwithUnix_error(EINTR,_,_)->eventt)letpendingt=not(Tmachine.deadt.trm)&&(t.winched||Unescape.pendingt.input.Input.flt)letfdst=t.fdsendincludeGen_output(structtypefd=out_channelandk=unitletdef=stdoutandto_fd=Unix.descr_of_out_channelandwrite=Buffer.output_bufferend)