123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812(*
* interpret.ml
* -----------
* Copyright : (c) 2019 - 2020, ZAN DoYe <zandoye@gmail.com>
* Licence : MIT
*
* This file is a part of mew_vi.
*)openVi_actionopenEdit_actionopenReactmoduleMake(Concurrent:Mew.Concurrent.S)=structmoduleMsgBox=Concurrent.MsgBoxmoduleThread=Concurrent.Threadlet(>>=)=Thread.bindmoduleRegister=structtypet=stringletcompare=String.comparetypecontent=|Seqofstring|Lineofstringletcompare_contentt1t2=matcht1,t2with|Seqs1,Seqs2->String.compares1s2|Lines1,Lines2->String.compares1s2|Seq_,Line_->1|Line_,Seq_->-1endmoduleRegisterMap=Map.Make(Register)typeregister=stringoptiontypecount=intoptiontypekeyseq=Modal.Key.tlistmoduleResolver=structtypet=config->status->keyseq->resultandconfig={mode:Mode.Name.tsignal;set_mode:?step:step->Mode.Name.t->unit;keyseq:keyseqsignal;set_keyseq:?step:step->keyseq->unit;mutableresolver_insert:t;mutableresolver_normal:t;mutableresolver_visual:t;mutableresolver_command:t;}andstatus={register:register;count:count;}andresult=|Acceptof(Edit_action.t*keyseq*Mode.Name.t)|Continueof(t*status*keyseq)|Rejectedofkeyseqletresolver_dummy=fun_config_statuskeyseq->Rejectedkeyseqletresolver_insert_config_statuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifkey.Key.control&&key.code=Char"["thenAccept(Vi[Motion(Left,1);ChangeModeNormal],tl,Mode.Name.Normal)elseifkey.code=EscapethenAccept(Vi[Motion(Left,1);ChangeModeNormal],tl,Mode.Name.Normal)elseAccept(Bypass[key],tl,Mode.Name.Insert)moduleCommon=structletget_countstatus=matchstatus.countwith|Somecount->count|None->1letget_registerstatus=matchstatus.registerwith|None|Some"\'"->"\""|Somereg->reglettry_countcontinuationconfigstatuskeyseq=letget_countnumseq=matchnumseqwith|""->status.count|_->letnum=int_of_stringnumseqinmatchstatus.countwith|Somecount->Some(count*num)|None->Somenuminletrecother_numnumseqconfigstatuskeyseq=matchkeyseqwith|[]->Rejectedkeyseq|key::tl->matchkey.Key.codewith|Charcode->ifString.lengthcode=1&&code>="0"&&code<="9"&¬(key.Key.control||key.Key.meta||key.Key.shift)thenletresolver=other_num(numseq^code)inContinue(resolver,status,tl)elsecontinuationconfig{statuswithcount=(get_countnumseq)}keyseq|Escape->Rejectedtl|_->continuationconfig{statuswithcount=get_countnumseq}keyseqinletfirst_num()=matchkeyseqwith|[]->Rejectedkeyseq|key::tl->matchkey.Key.codewith|Charcode->ifString.lengthcode=1&¬(key.Key.control||key.Key.meta||key.Key.shift)thenifcode>="1"&&code<="9"thenletresolver=other_numcodeinContinue(resolver,status,tl)elsecontinuationconfig{statuswithcount=get_count""}keyseqelsecontinuationconfig{statuswithcount=get_count""}keyseq|Escape->Rejectedtl|_->continuationconfigstatuskeyseqinfirst_num()lettry_registernext_modecontinuationconfigstatuskeyseq=letget_register_configstatuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charcode->letresolver=continuationinContinue(resolver,{statuswithregister=Somecode},tl)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charcode->ifcode="\""thenContinue(get_register,status,tl)elsecontinuationconfigstatuskeyseq|_->RejectedkeyseqelseAccept(Bypass[key],tl,next_mode)lettry_motionnext_modeconfigstatuskeyseq=lettry_motion_g_configstatuskeyseq=letcount=get_countstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"e"->Accept(Vi[Motion(Word_back_end,count)],tl,next_mode)|Char"E"->Accept(Vi[Motion(WORD_back_end,count)],tl,next_mode)|Char"g"->Accept(matchstatus.countwith|None->Vi[Motion(GotoLine_first,count)],tl,next_mode|Somecount->Vi[Motion(GotoLine,(count-1))],tl,next_mode)|_->RejectedkeyseqelseAccept(Bypass[key],tl,next_mode)inlettry_motion_occurence?(backward=false)_configstatuskeyseq=letcount=get_countstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charchr->ifbackwardthenAccept(Vi[Motion(Occurrence_inline_backchr,count)],tl,next_mode)elseAccept(Vi[Motion(Occurrence_inlinechr,count)],tl,next_mode)|_->RejectedkeyseqelseAccept(Bypass[key],tl,next_mode)inlettry_motion_occurence_till?(backward=false)_configstatuskeyseq=letcount=get_countstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charchr->ifbackwardthenAccept(Vi[Motion(Occurrence_inline_till_backchr,count)],tl,next_mode)elseAccept(Vi[Motion(Occurrence_inline_tillchr,count)],tl,next_mode)|_->RejectedkeyseqelseAccept(Bypass[key],tl,next_mode)inlettry_motion_n_configstatuskeyseq=letcount=get_countstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"h"->Accept(Vi[Motion(Left,count)],tl,next_mode)|Char"l"->Accept(Vi[Motion(Right,count)],tl,next_mode)|Char"j"->Accept(Vi[Motion(Downward,count)],tl,next_mode)|Char"k"->Accept(Vi[Motion(Upward,count)],tl,next_mode)|Char"0"->Accept(Vi[Motion(Line_FirstChar,count)],tl,next_mode)|Char"$"->Accept(Vi[Motion(Line_LastChar,count)],tl,next_mode)|Char"^"->Accept(Vi[Motion(Line_FirstNonBlank,count)],tl,next_mode)|Char"w"->Accept(Vi[Motion(Word,count)],tl,next_mode)|Char"W"->Accept(Vi[Motion(WORD,count)],tl,next_mode)|Char"b"->Accept(Vi[Motion(Word_back,count)],tl,next_mode)|Char"B"->Accept(Vi[Motion(WORD_back,count)],tl,next_mode)|Char"e"->Accept(Vi[Motion(Word_end,count)],tl,next_mode)|Char"E"->Accept(Vi[Motion(WORD_end,count)],tl,next_mode)|Char"G"->Accept(matchstatus.countwith|None->Vi[Motion(GotoLine_last,count)],tl,next_mode|Somecount->Vi[Motion(GotoLine,(count-1))],tl,next_mode)|Char"g"->letresolver=try_motion_ginContinue(resolver,status,tl)|Char"f"->letbackward=falseinletresolver=try_motion_occurence~backwardinContinue(resolver,status,tl)|Char"F"->letbackward=trueinletresolver=try_motion_occurence~backwardinContinue(resolver,status,tl)|Char"t"->letbackward=falseinletresolver=try_motion_occurence_till~backwardinContinue(resolver,status,tl)|Char"T"->letbackward=trueinletresolver=try_motion_occurence_till~backwardinContinue(resolver,status,tl)|Char"%"->Accept(Vi[Motion(Match,1)],tl,next_mode)|_->RejectedkeyseqelseAccept(Bypass[key],tl,next_mode)intry_counttry_motion_nconfigstatuskeyseqendmoduleNormal=structlettry_change_mode_config_statuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"i"->Accept(Vi[ChangeModeInsert],tl,Mode.Name.Insert)|Char"I"->Accept(Vi[Motion(Line_FirstNonBlank,1);ChangeModeInsert],tl,Mode.Name.Insert)|Char"a"->Accept(Vi[Motion(Right_nl,1);ChangeModeInsert],tl,Mode.Name.Insert)|Char"A"->Accept(Vi[Motion(Line_LastChar_nl,1);ChangeModeInsert],tl,Mode.Name.Insert)|Char"v"->Accept(Vi[ChangeModeVisual],tl,Mode.Name.Visual)|_->RejectedkeyseqelseRejectedkeyseqlettry_modifyconfigstatuskeyseq=letopenCommoninlettry_motion_n~action_configstatuskeyseq=letnext_mode=ifaction=`ChangethenMode.Name.InsertelseMode.Name.Normalinletmake_actionsstatustlmotion=letaction=letregister=get_registerstatusandcount=get_countstatusinmatchactionwith|`Change->Change(register,motion,count)|`Delete->Delete(register,motion,count)|`Yank->Yank(register,motion,count)inAccept(Vi[action],tl,next_mode)inlettry_motion_g_configstatuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"e"->make_actionsstatustlWord_back_end|Char"E"->make_actionsstatustlWORD_back_end|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inlettry_motion_quote?(inner=false)_configstatuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charchr->ifinnerthenmake_actionsstatustl(Quote_innerchr)elsemake_actionsstatustl(Quote_includechr)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inlettry_motion_object?(inner=false)_configstatuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"("|Char")"|Char"b"->ifinnerthenmake_actionsstatustlParenthesis_innerelsemake_actionsstatustlParenthesis_include|Char"["|Char"]"->ifinnerthenmake_actionsstatustlBracket_innerelsemake_actionsstatustlBracket_include|Char"<"|Char">"->ifinnerthenmake_actionsstatustlAngleBracket_innerelsemake_actionsstatustlAngleBracket_include|Char"{"|Char"}"->ifinnerthenmake_actionsstatustlBrace_innerelsemake_actionsstatustlBrace_include|Char"'"->ifinnerthenmake_actionsstatustl(Quote_inner"'")elsemake_actionsstatustl(Quote_include"'")|Char"\""->ifinnerthenmake_actionsstatustl(Quote_inner"\"")elsemake_actionsstatustl(Quote_include"\"")|Char"w"->ifinnerthenmake_actionsstatustlWord_innerelsemake_actionsstatustlWord_include|Char"W"->ifinnerthenmake_actionsstatustlWORD_innerelsemake_actionsstatustlWORD_include|Char"q"->letresolver=try_motion_quote~innerinContinue(resolver,status,tl)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inlettry_motion_occurence?(backward=false)_config_statuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charchr->ifbackwardthenmake_actionsstatustl(Occurrence_inline_backchr)elsemake_actionsstatustl(Occurrence_inlinechr)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inlettry_motion_occurence_till?(backward=false)_configstatuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Charchr->ifbackwardthenmake_actionsstatustl(Occurrence_inline_till_backchr)elsemake_actionsstatustl(Occurrence_inline_tillchr)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"h"->make_actionsstatustlLeft|Char"l"->make_actionsstatustlRight|Char"j"->make_actionsstatustlDownward|Char"k"->make_actionsstatustlUpward|Char"0"->make_actionsstatustlLine_FirstChar|Char"$"->make_actionsstatustlLine_LastChar|Char"^"->make_actionsstatustlLine_FirstNonBlank|Char"w"->make_actionsstatustlWord|Char"W"->make_actionsstatustlWORD|Char"b"->make_actionsstatustlWord_back|Char"B"->make_actionsstatustlWORD_back|Char"e"->make_actionsstatustlWord_end|Char"E"->make_actionsstatustlWORD_end|Char"g"->letresolver=try_motion_ginContinue(resolver,status,tl)|Char"d"->ifaction=`Deletethenmake_actionsstatustlLineelseRejectedkeyseq|Char"a"->letinner=falseinletresolver=try_motion_object~innerinContinue(resolver,status,tl)|Char"i"->letinner=trueinletresolver=try_motion_object~innerinContinue(resolver,status,tl)|Char"f"->letbackward=falseinletresolver=try_motion_occurence~backwardinContinue(resolver,status,tl)|Char"F"->letbackward=trueinletresolver=try_motion_occurence~backwardinContinue(resolver,status,tl)|Char"t"->letbackward=falseinletresolver=try_motion_occurence_till~backwardinContinue(resolver,status,tl)|Char"T"->letbackward=trueinletresolver=try_motion_occurence_till~backwardinContinue(resolver,status,tl)|Char"%"->make_actionsstatustlMatch|Char"y"->ifaction=`Yankthenmake_actionsstatustlLineelseRejectedkeyseq|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)inletdetermin_configstatuskeyseq=letcount=get_countstatusandregister=get_registerstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"u"->Accept(Vi[Undocount],tl,Mode.Name.Normal)|Char"p"->Accept(Vi[Paste_after(register,count)],tl,Mode.Name.Normal)|Char"P"->Accept(Vi[Paste_before(register,count)],tl,Mode.Name.Normal)|Char"d"->letresolver=Common.try_count(try_motion_n~action:`Delete)inContinue(resolver,status,tl)|Char"c"->letresolver=Common.try_count(try_motion_n~action:`Change)inContinue(resolver,status,tl)|Char"D"->Accept(Vi[Delete(register,Line_LastChar,count)],tl,Mode.Name.Normal)|Char"C"->Accept(Vi[Delete(register,Line_LastChar,count)],tl,Mode.Name.Insert)|Char"x"->Accept(Vi[Delete(register,Right,count)],tl,Mode.Name.Normal)|Char"s"->Accept(Vi[Delete(register,Right,count)],tl,Mode.Name.Insert)|Char"J"->Accept(Vi[(Joincount)],tl,Mode.Name.Normal)|Char"y"->letresolver=Common.try_count(try_motion_n~action:`Yank)inContinue(resolver,status,tl)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)indeterminconfigstatuskeyseqlettry_insert_configstatuskeyseq=letcount=Common.get_countstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"o"->Accept(Vi[Insert((Newline_below""),count)],tl,Mode.Name.Insert)|Char"O"->Accept(Vi[Insert((Newline_above""),count)],tl,Mode.Name.Insert)|_->RejectedkeyseqelseAccept(Bypass[key],tl,Mode.Name.Normal)lettry_motion_modify_insertconfigstatuskeyseq=matchCommon.try_motionMode.Name.Normalconfigstatuskeyseqwith|Rejectedkeyseq->letresolverconfigstatuskeyseq=matchtry_modifyconfigstatuskeyseqwith|Rejectedkeyseq->letresolver=try_insertinContinue(resolver,status,keyseq)|r->rinContinue(resolver,status,keyseq)|r->rletresolver_normalconfigstatuskeyseq=matchkeyseqwith|[]->Rejected[]|_->matchtry_change_modeconfigstatuskeyseqwith|Rejectedkeyseq->Common.try_registerMode.Name.Normal(Common.try_count(Common.try_registerMode.Name.Normaltry_motion_modify_insert))configstatuskeyseq|r->rendmoduleVisual=structlettry_change_mode_config_statuskeyseq=matchkeyseqwith|[]->Rejected[]|key::tl->ifkey.Key.control&&key.code=Char"["thenAccept(Vi[ChangeModeNormal],tl,Mode.Name.Normal)elseifkey.code=EscapethenAccept(Vi[ChangeModeNormal],tl,Mode.Name.Normal)elseifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"v"->Accept(Vi[ChangeModeNormal],tl,Mode.Name.Normal)|_->RejectedkeyseqelseRejectedkeyseqlettry_motion=Common.try_motionMode.Name.Visuallettry_modify_configstatuskeyseq=letregister=Common.get_registerstatusinmatchkeyseqwith|[]->Rejected[]|key::tl->ifnot(key.Key.control||key.Key.meta||key.Key.shift)thenmatchkey.Key.codewith|Char"c"|Char"s"->Accept(Vi[DeleteSelectedregister;ChangeModeInsert],tl,Mode.Name.Insert)|Char"d"|Char"x"->Accept(Vi[DeleteSelectedregister;ChangeModeNormal],tl,Mode.Name.Normal)|Char"y"->Accept(Vi[YankSelectedregister;ChangeModeNormal],tl,Mode.Name.Normal)|_->RejectedkeyseqelseRejectedkeyseqlettry_motion_modifyconfigstatuskeyseq=matchtry_motionconfigstatuskeyseqwith|Rejectedkeyseq->Continue(try_modify,status,keyseq)|r->rletresolver_visualconfigstatuskeyseq=matchkeyseqwith|[]->Rejected[]|_->matchtry_change_modeconfigstatuskeyseqwith|Rejectedkeyseq->Common.try_registerMode.Name.Visual(Common.try_counttry_motion_modify)configstatuskeyseq|r->rendletmake_config?(mode=Mode.Name.Insert)?(keyseq=[])?(resolver_insert=resolver_insert)?(resolver_normal=Normal.resolver_normal)?(resolver_visual=Visual.resolver_visual)?(resolver_command=resolver_dummy)()=letmode,set_mode=React.S.createmodeinletkeyseq,set_keyseq=React.S.createkeyseqin{mode;set_mode;keyseq;set_keyseq;resolver_insert;resolver_normal;resolver_visual;resolver_command;}letrecinterpret?resolver?(keyseq=[])configstatus(keyIn:Modal.Key.tMsgBox.t)(action:Edit_action.tMsgBox.t)()=letresolver=matchresolverwith|Someresolver->resolver|None->matchS.valueconfig.modewith|Mode.Name.Insert->config.resolver_insert|Mode.Name.Visual->config.resolver_visual|_->config.resolver_normalin(matchkeyseqwith|[]->MsgBox.getkeyIn>>=funkey->Thread.return[key]|_->Thread.returnkeyseq)>>=funkeyseq->matchresolverconfigstatuskeyseqwith|Accept(edit,keyseq,next_mode)->config.set_modenext_mode;MsgBox.putactionedit>>=interpretconfig{statuswithcount=None}~keyseqkeyInaction|Continue(resolver,status,keyseq)->interpretconfigstatus~resolver~keyseqkeyInaction()|Rejected_keyseq->MsgBox.putactionDummy>>=interpretconfig{statuswithcount=None}keyInactionendend