1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078(*
* zed_edit.ml
* -----------
* Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of Zed, an editor engine.
*)openReact(* +-----------------------------------------------------------------+
| Types |
+-----------------------------------------------------------------+ *)typeclipboard={clipboard_get:unit->Zed_rope.t;clipboard_set:Zed_rope.t->unit;}type'at={mutabledata:'aoption;(* Custom data attached to the engine. *)mutabletext:Zed_rope.t;(* The contents of the engine. *)mutablelines:Zed_lines.t;(* The set of line position of [text]. *)changes:Zed_cursor.changesevent;send_changes:Zed_cursor.changes->unit;(* Changes of the contents. *)erase_mode:boolsignal;set_erase_mode:bool->unit;(* The current erase mode. *)editable:int->int->bool;(* The editable function of the engine. *)clipboard:clipboard;(* The clipboard for this engine. *)mutablemark:Zed_cursor.t;(* The cursor that points to the mark. *)selection:boolsignal;set_selection:bool->unit;(* The current selection state. *)match_word:Zed_rope.t->int->intoption;(* The function for matching words. *)locale:stringoptionsignal;(* The buffer's locale. *)undo:(Zed_rope.t*Zed_lines.t*int*int*int*int*int*int)array;(* The undo buffer. It is an array of element of the form [(text,
lines, pos, new_pos, added, removed, added_width, removed_width)]. *)undo_size:int;(* Size of the undo buffer. *)mutableundo_start:int;(* Position of the first used cell in the undo buffer. *)mutableundo_index:int;(* Position of the next available cell in the undo buffer. *)mutableundo_count:int;(* Number of used cell in the undo buffer. *)}(* +-----------------------------------------------------------------+
| Creation |
+-----------------------------------------------------------------+ *)letdummy_cursor=Zed_cursor.create0E.never(fun()->Zed_lines.empty)00letnew_clipboard()=letr=ref(Zed_rope.empty())in{clipboard_get=(fun()->!r);clipboard_set=(funx->r:=x)}letdefault_match_word=letrecloop_startsegmenterzip=matchZed_rope.Zip_raw.nextzipwith|exceptionZed_rope.Out_of_bounds->None|ch,zip->matchUuseg.addsegmenter(`Ucharch)with|`Await->loop_startsegmenterzip|`Uchar_|`End->None|`Boundary->loop_wordsegmenterzip~pos:0`Awaitandloop_wordsegmenterzipv~pos=matchUuseg.addsegmentervwith|`Boundary|`End->Somepos|`Uchar_->loop_wordsegmenterzip`Await~pos:(pos+1)|`Await->matchZed_rope.Zip_raw.nextzipwith|exceptionZed_rope.Out_of_bounds->Somepos|ch,zip->loop_wordsegmenterzip(`Ucharch)~posinfunropeidx->letzip=Zed_rope.Zip_raw.make_fropeidxinloop_start(Uuseg.create`Word)zipletcreate?(editable=fun_pos_len->true)?(move=(+))?clipboard?(match_word=default_match_word)?(locale=S.constNone)?(undo_size=1000)()=(* I'm not sure how to disable the unused warning with ocaml.warning and the
argument can't be removed as it's part of the interface *)let_=moveinletchanges,send_changes=E.create()inleterase_mode,set_erase_mode=S.createfalseinletselection,set_selection=S.createfalseinletclipboard=matchclipboardwith|Someclipboard->clipboard|None->new_clipboard()inletedit={data=None;text=Zed_rope.empty();lines=Zed_lines.empty;changes;send_changes;erase_mode;set_erase_mode;editable;clipboard;mark=dummy_cursor;selection;set_selection;match_word;locale;undo=Array.makeundo_size(Zed_rope.empty(),Zed_lines.empty,0,0,0,0,0,0);undo_size;undo_start=0;undo_index=0;undo_count=0;}inedit.mark<-Zed_cursor.create0changes(fun()->edit.lines)00;edit(* +-----------------------------------------------------------------+
| State |
+-----------------------------------------------------------------+ *)letget_dataengine=matchengine.datawith|Somedata->data|None->raiseNot_foundletset_dataenginedata=engine.data<-Somedataletclear_dataengine=engine.data<-Nonelettextengine=engine.textletlinesengine=engine.linesletchangesengine=engine.changesleterase_modeengine=engine.erase_modeletget_erase_modeengine=S.valueengine.erase_modeletset_erase_modeenginestate=engine.set_erase_modestateletmarkengine=engine.markletselectionengine=engine.selectionletget_selectionengine=S.valueengine.selectionletset_selectionenginestate=engine.set_selectionstateletget_lineei=lettxt=texteinletlines=lineseinletstart=Zed_lines.line_startlinesiinletstop=Zed_lines.line_stoplinesiinZed_rope.subtxtstart(stop-start)letupdateenginecursors=E.select(E.stampengine.changes()::E.stamp(S.changesengine.selection)()::E.stamp(S.changes(Zed_cursor.positionengine.mark))()::List.map(funcursor->E.stamp(S.changes(Zed_cursor.positioncursor))())cursors)(* +-----------------------------------------------------------------+
| Cursors |
+-----------------------------------------------------------------+ *)letnew_cursorengine=Zed_cursor.create(Zed_rope.lengthengine.text)engine.changes(fun()->engine.lines)00(* +-----------------------------------------------------------------+
| Actions |
+-----------------------------------------------------------------+ *)exceptionCannot_edittype'acontext={edit:'at;cursor:Zed_cursor.t;check:bool;}letcontext?(check=true)editcursor={edit;cursor;check}leteditctx=ctx.editletcursorctx=ctx.cursorletcheckctx=ctx.checkletwith_checkcheckctx={ctxwithcheck}letgotoctx?set_wanted_columnnew_position=Zed_cursor.gotoctx.cursor?set_wanted_columnnew_positionletset_positionctxnew_position=Zed_cursor.gotoctx.cursor~set_wanted_column:falsenew_positionletmovectx?set_wanted_columndelta=Zed_cursor.movectx.cursor?set_wanted_columndeltaletnext_line_nctxn=letindex=Zed_cursor.get_linectx.cursorinifindex+n>Zed_lines.countctx.edit.linesthengotoctx~set_wanted_column:false(Zed_rope.lengthctx.edit.text)elsebeginletstop=ifindex+n=Zed_lines.countctx.edit.linesthenZed_rope.lengthctx.edit.textelseZed_lines.line_startctx.edit.lines(index+n+1)-1inletwanted_idx=Zed_lines.get_idx_by_widthctx.edit.lines(index+n)(Zed_cursor.get_wanted_columnctx.cursor)ingotoctx~set_wanted_column:false(minwanted_idxstop)endletprev_line_nctxn=letindex=Zed_cursor.get_linectx.cursorinifindex-n<0thenbegingotoctx~set_wanted_column:false0endelsebeginletstop=Zed_lines.line_startctx.edit.lines(index-(n-1))-1inletwanted_idx=Zed_lines.get_idx_by_widthctx.edit.lines(index-n)(Zed_cursor.get_wanted_columnctx.cursor)ingotoctx~set_wanted_column:false(minwanted_idxstop)endletmove_linectxdelta=matchdeltawith|_whendelta<0->prev_line_nctx(-delta)|_whendelta>0->next_line_nctxdelta|_->()letpositionctx=Zed_cursor.get_positionctx.cursorletlinectx=Zed_cursor.get_linectx.cursorletcolumnctx=Zed_cursor.get_columnctx.cursorletcolumn_displayctx=Zed_cursor.get_column_displayctx.cursorletat_bolctx=Zed_cursor.get_columnctx.cursor=0letat_eolctx=letposition=Zed_cursor.get_positionctx.cursorinletindex=Zed_cursor.get_linectx.cursorinifindex=Zed_lines.countctx.edit.linesthenposition=Zed_rope.lengthctx.edit.textelseposition=Zed_lines.line_startctx.edit.lines(index+1)-1letat_botctx=Zed_cursor.get_positionctx.cursor=0letat_eotctx=Zed_cursor.get_positionctx.cursor=Zed_rope.lengthctx.edit.textletmodify{edit;_}textlinespositionnew_positionaddedremovedadded_widthremoved_width=ifedit.undo_size>0thenbeginedit.undo.(edit.undo_index)<-(text,lines,position,new_position,added,removed,added_width,removed_width);edit.undo_index<-(edit.undo_index+1)modedit.undo_size;ifedit.undo_count=edit.undo_sizethenedit.undo_start<-(edit.undo_start+1)modedit.undo_sizeelseedit.undo_count<-edit.undo_count+1end;edit.send_changes{position;added;removed;added_width;removed_width}letinsertctxrope=letposition=Zed_cursor.get_positionctx.cursorinifnotctx.check||ctx.edit.editableposition0thenbeginletlen=Zed_rope.lengthropeinlettext=ctx.edit.textandlines=ctx.edit.linesinifS.valuectx.edit.erase_modethenbeginlettext_len=Zed_rope.lengthctx.edit.textinifposition+len>text_lenthenbeginletorig_width=Zed_string.(aval_width(widthZed_rope.(to_string(subtextposition(text_len-position)))))inletcurr_width=Zed_string.(aval_width(widthZed_rope.(to_stringrope)))inctx.edit.text<-Zed_rope.replacetextposition(text_len-position)rope;ctx.edit.lines<-Zed_lines.replacectx.edit.linesposition(text_len-position)(Zed_lines.of_roperope);modifyctxtextlinespositionpositionlen(text_len-position)curr_widthorig_widthendelsebeginletorig_width=Zed_string.(aval_width(widthZed_rope.(to_string(subtextpositionlen))))inletcurr_width=Zed_string.(aval_width(widthZed_rope.(to_stringrope)))inctx.edit.text<-Zed_rope.replacetextpositionlenrope;ctx.edit.lines<-Zed_lines.replacectx.edit.linespositionlen(Zed_lines.of_roperope);modifyctxtextlinespositionpositionlenlencurr_widthorig_width;end;movectxlenendelsebeginletwidth_add=Zed_string.aval_width(Zed_string.width(Zed_rope.to_stringrope))inctx.edit.text<-Zed_rope.insertctx.edit.textpositionrope;ctx.edit.lines<-Zed_lines.insertctx.edit.linesposition(Zed_lines.of_roperope);modifyctxtextlinespositionpositionlen0width_add0;movectxlenendendelseraiseCannot_editletinsert_charctxch=ifZed_char.is_combining_markchthenletposition=Zed_cursor.get_positionctx.cursorinifnotctx.check||ctx.edit.editableposition0thenbeginlettext=ctx.edit.textandlines=ctx.edit.linesintryctx.edit.text<-Zed_rope.insert_uCharctx.edit.textpositionch;modifyctxtextlinespositionposition1100;movectx0;next_line_nctx0;with_->()endelseraiseCannot_editelseinsertctx(Zed_rope.of_string(fst(Zed_string.of_uChars[ch])))letinsert_no_erasectxrope=letposition=Zed_cursor.get_positionctx.cursorinifnotctx.check||ctx.edit.editableposition0thenbeginletlen=Zed_rope.lengthropeandtext=ctx.edit.textandlines=ctx.edit.linesinletwidth_add=Zed_string.aval_width(Zed_string.width(Zed_rope.to_stringrope))inctx.edit.text<-Zed_rope.inserttextpositionrope;ctx.edit.lines<-Zed_lines.insertctx.edit.linesposition(Zed_lines.of_roperope);modifyctxtextlinespositionpositionlen0width_add0;movectxlenendelseraiseCannot_editletremove_nextctxlen=letposition=Zed_cursor.get_positionctx.cursorinlettext_len=Zed_rope.lengthctx.edit.textinletlen=ifposition+len>text_lenthentext_len-positionelseleninifnotctx.check||ctx.edit.editablepositionlenthenbeginlettext=ctx.edit.textandlines=ctx.edit.linesinletwidth_remove=Zed_string.(aval_width(widthZed_rope.(to_string(subtextpositionlen))))inctx.edit.text<-Zed_rope.removetextpositionlen;ctx.edit.lines<-Zed_lines.removectx.edit.linespositionlen;modifyctxtextlinespositionposition0len0width_remove;endelseraiseCannot_editletremove_prevctxlen=letposition=Zed_cursor.get_positionctx.cursorinletlen=minpositionleninifnotctx.check||ctx.edit.editable(position-len)lenthenbeginlettext=ctx.edit.textandlines=ctx.edit.linesinletwidth_remove=Zed_string.(aval_width(widthZed_rope.(to_string(subtext(position-len)len))))inctx.edit.text<-Zed_rope.removetext(position-len)len;ctx.edit.lines<-Zed_lines.removectx.edit.lines(position-len)len;modifyctxtextlines(position-len)position0len0width_remove;endelseraiseCannot_editletremove=remove_nextletreplacectxlenrope=letposition=Zed_cursor.get_positionctx.cursorinlettext_len=Zed_rope.lengthctx.edit.textinletlen=ifposition+len>text_lenthentext_len-positionelseleninifnotctx.check||ctx.edit.editablepositionlenthenbeginletrope_len=Zed_rope.lengthropeandtext=ctx.edit.textandlines=ctx.edit.linesinletorig_width=Zed_string.(aval_width(widthZed_rope.(to_string(subtextpositionlen))))inletcurr_width=Zed_string.(aval_width(widthZed_rope.(to_stringrope)))inctx.edit.text<-Zed_rope.replacetextpositionlenrope;ctx.edit.lines<-Zed_lines.replacectx.edit.linespositionlen(Zed_lines.of_roperope);modifyctxtextlinespositionpositionrope_lenlencurr_widthorig_width;movectxrope_lenendelseraiseCannot_editletnewline_rope=Zed_rope.singleton(Zed_char.unsafe_of_char'\n')letnewlinectx=insertctxnewline_ropeletnext_charctx=ifnot(at_eotctx)thenmovectx1letprev_charctx=ifnot(at_botctx)thenmovectx(-1)letnext_linectx=letindex=Zed_cursor.get_linectx.cursorinifindex=Zed_lines.countctx.edit.linesthengotoctx~set_wanted_column:false(Zed_rope.lengthctx.edit.text)elsebeginletstop=ifindex+1=Zed_lines.countctx.edit.linesthenZed_rope.lengthctx.edit.textelseZed_lines.line_startctx.edit.lines(index+2)-1inletwanted_idx=Zed_lines.get_idx_by_widthctx.edit.lines(index+1)(Zed_cursor.get_wanted_columnctx.cursor)ingotoctx~set_wanted_column:false(minwanted_idxstop)endletprev_linectx=letindex=Zed_cursor.get_linectx.cursorinifindex=0thenbegingotoctx~set_wanted_column:false0endelsebeginletstop=Zed_lines.line_startctx.edit.linesindex-1inletwanted_idx=Zed_lines.get_idx_by_widthctx.edit.lines(index-1)(Zed_cursor.get_wanted_columnctx.cursor)ingotoctx~set_wanted_column:false(minwanted_idxstop)endletjoin_linectx=letis_spaceuchar=matchUucp.Gc.general_categoryucharwith|`Cc|`Zs|`Zl|`Zp|`Mn->true|_->falseinletis_not_spaceuchar=not(is_spaceuchar)inlettext=ctx.edit.textinletlines=linesctx.editinletlines_num=Zed_lines.countlinesinletindex=linectxinletposition=Zed_lines.line_stopctx.edit.linesindexinletlen=1inifindex<lines_numthenifnotctx.check||ctx.edit.editablepositionlenthenbeginletwidth_remove=1inifis_not_space(Zed_char.core(Zed_rope.gettext(position-1)))&&is_not_space(Zed_char.core(Zed_rope.gettext(position+1)))thenletspace=Zed_rope.of_string@@Zed_string.of_utf8" "inletlines_space=Zed_lines.of_ropespaceinctx.edit.text<-Zed_rope.replacetextpositionlenspace;ctx.edit.lines<-Zed_lines.replacectx.edit.linespositionlenlines_space;modifyctxtextlinespositionposition0000else(ctx.edit.text<-Zed_rope.removetextpositionlen;ctx.edit.lines<-Zed_lines.removectx.edit.linespositionlen;modifyctxtextlinespositionposition0len0width_remove)endelseraiseCannot_editletgoto_bolctx=gotoctx(Zed_lines.line_startctx.edit.lines(Zed_cursor.get_linectx.cursor))letgoto_eolctx=letindex=Zed_cursor.get_linectx.cursorinifindex=Zed_lines.countctx.edit.linesthengotoctx(Zed_rope.lengthctx.edit.text)elsegotoctx(Zed_lines.line_startctx.edit.lines(index+1)-1)letgoto_botctx=gotoctx0letgoto_eotctx=gotoctx(Zed_rope.lengthctx.edit.text)letdelete_next_charsctxn=ifnot(at_eotctx)thenbeginctx.edit.set_selectionfalse;remove_nextctxn;endletdelete_prev_charsctxn=ifnot(at_botctx)thenbeginctx.edit.set_selectionfalse;remove_prevctxn;endletkill_next_charsctxn=letposition=Zed_cursor.get_positionctx.cursorinletend_pos=min(position+n)(Zed_rope.lengthctx.edit.text)inletn=end_pos-positioninctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textpositionn);ctx.edit.set_selectionfalse;removectxnletkill_prev_charsctxn=letposition=Zed_cursor.get_positionctx.cursorinletstart=max0(position-n)inletn=position-startinctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textstartn);ctx.edit.set_selectionfalse;remove_prevctxnletdelete_next_charctx=ifnot(at_eotctx)thenbeginctx.edit.set_selectionfalse;remove_nextctx1endletdelete_prev_charctx=ifnot(at_botctx)thenbeginctx.edit.set_selectionfalse;remove_prevctx1endletdelete_next_linectx=ctx.edit.set_selectionfalse;letposition=Zed_cursor.get_positionctx.cursorinletindex=Zed_cursor.get_linectx.cursorinifindex=Zed_lines.countctx.edit.linesthenremove_nextctx(Zed_rope.lengthctx.edit.text-position)elseremove_nextctx(Zed_lines.line_startctx.edit.lines(index+1)-position)letdelete_prev_linectx=ctx.edit.set_selectionfalse;letposition=Zed_cursor.get_positionctx.cursorinletstart=Zed_lines.line_startctx.edit.lines(Zed_cursor.get_linectx.cursor)inremove_prevctx(position-start)letkill_next_linectx=letposition=Zed_cursor.get_positionctx.cursorinletindex=Zed_cursor.get_linectx.cursorinifindex=Zed_lines.countctx.edit.linesthenbeginctx.edit.clipboard.clipboard_set(Zed_rope.afterctx.edit.textposition);ctx.edit.set_selectionfalse;removectx(Zed_rope.lengthctx.edit.text-position)endelsebeginletlen=Zed_lines.line_startctx.edit.lines(index+1)-positioninctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textpositionlen);ctx.edit.set_selectionfalse;removectxlenendletkill_prev_linectx=letposition=Zed_cursor.get_positionctx.cursorinletstart=Zed_lines.line_startctx.edit.lines(Zed_cursor.get_linectx.cursor)inctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textstart(position-start));ctx.edit.set_selectionfalse;remove_prevctx(position-start)letswitch_erase_modectx=ctx.edit.set_erase_mode(not(S.valuectx.edit.erase_mode))letset_markctx=Zed_cursor.gotoctx.edit.mark(Zed_cursor.get_positionctx.cursor);ctx.edit.set_selectiontrueletgoto_markctx=gotoctx(Zed_cursor.get_positionctx.edit.mark)letcopyctx=ifS.valuectx.edit.selectionthenbeginleta=Zed_cursor.get_positionctx.cursorandb=Zed_cursor.get_positionctx.edit.markinleta=minabandb=maxabinctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.texta(b-a));ctx.edit.set_selectionfalseendletcopy_sequencectxstartlen=ctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textstartlen)letkillctx=ifS.valuectx.edit.selectionthenbeginleta=Zed_cursor.get_positionctx.cursorandb=Zed_cursor.get_positionctx.edit.markinleta=minabandb=maxabinctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.texta(b-a));ctx.edit.set_selectionfalse;gotoctxa;leta=Zed_cursor.get_positionctx.cursorinifa<=bthenremovectx(b-a)endletyankctx=ctx.edit.set_selectionfalse;insertctx(ctx.edit.clipboard.clipboard_get())letsearch_word_forwardctx=letlen=Zed_rope.lengthctx.edit.textinletrecloopidx=ifidx=lenthenNoneelsematchctx.edit.match_wordctx.edit.textidxwith|Someidx'->Some(idx,idx')|None->loop(idx+1)inloop(Zed_cursor.get_positionctx.cursor)letsearch_word_backwardctx=letrecloopidx=ifidx=-1thenNoneelsematchctx.edit.match_wordctx.edit.textidxwith|Someidx'->loop2(idx-1)(idx,idx')|None->loop(idx-1)andloop2idxresult=ifidx=-1thenSomeresultelsematchctx.edit.match_wordctx.edit.textidxwith|Someidx'->loop2(idx-1)(idx,idx')|None->Someresultinloop(Zed_cursor.get_positionctx.cursor-1)letcapitalize_wordctx=matchsearch_word_forwardctxwith|Some(idx1,idx2)->gotoctxidx1;ifZed_cursor.get_positionctx.cursor=idx1&&idx1<idx2thenbeginletstr=Zed_rope.subctx.edit.textidx1(idx2-idx1)inletch,str'=Zed_rope.breakstr1inreplacectx(Zed_rope.lengthstr)(Zed_rope.append(Zed_rope.uppercase?locale:(S.valuectx.edit.locale)ch)(Zed_rope.lowercase?locale:(S.valuectx.edit.locale)str'))end|None->()letlowercase_wordctx=matchsearch_word_forwardctxwith|Some(idx1,idx2)->gotoctxidx1;ifZed_cursor.get_positionctx.cursor=idx1thenbeginletstr=Zed_rope.subctx.edit.textidx1(idx2-idx1)inreplacectx(Zed_rope.lengthstr)(Zed_rope.lowercase?locale:(S.valuectx.edit.locale)str)end|None->()letuppercase_wordctx=matchsearch_word_forwardctxwith|Some(idx1,idx2)->gotoctxidx1;ifZed_cursor.get_positionctx.cursor=idx1thenbeginletstr=Zed_rope.subctx.edit.textidx1(idx2-idx1)inreplacectx(Zed_rope.lengthstr)(Zed_rope.uppercase?locale:(S.valuectx.edit.locale)str)end|None->()letnext_wordctx=matchsearch_word_forwardctxwith|Some(_idx1,idx2)->gotoctxidx2|None->gotoctx(Zed_rope.lengthctx.edit.text)letprev_wordctx=matchsearch_word_backwardctxwith|Some(idx1,_idx2)->gotoctxidx1|None->gotoctx0letdelete_next_wordctx=letposition=Zed_cursor.get_positionctx.cursorinletword_end=matchsearch_word_forwardctxwith|Some(_idx1,idx2)->idx2|None->Zed_rope.lengthctx.edit.textinremovectx(word_end-position)letdelete_prev_wordctx=letposition=Zed_cursor.get_positionctx.cursorinletstart=matchsearch_word_backwardctxwith|Some(idx1,_idx2)->idx1|None->0inremove_prevctx(position-start)letkill_next_wordctx=letposition=Zed_cursor.get_positionctx.cursorinletword_end=matchsearch_word_forwardctxwith|Some(_idx1,idx2)->idx2|None->Zed_rope.lengthctx.edit.textinctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textposition(word_end-position));ctx.edit.set_selectionfalse;removectx(word_end-position)letkill_prev_wordctx=letposition=Zed_cursor.get_positionctx.cursorinletstart=matchsearch_word_backwardctxwith|Some(idx1,_idx2)->idx1|None->0inctx.edit.clipboard.clipboard_set(Zed_rope.subctx.edit.textstart(position-start));ctx.edit.set_selectionfalse;remove_prevctx(position-start)letundo{check;edit;cursor}=ifedit.undo_count>0thenbeginletindex=ifedit.undo_index=0thenedit.undo_size-1elseedit.undo_index-1inlettext,lines,pos,new_pos,added,removed,added_width,removed_width=edit.undo.(index)inifnotcheck||edit.editableposaddedthenbeginedit.undo_count<-edit.undo_count-1;edit.undo_index<-index;edit.text<-text;edit.lines<-lines;edit.send_changes{position=pos;removed=added;added=removed;added_width=removed_width;removed_width=added_width};Zed_cursor.gotocursornew_posendelseraiseCannot_editend(* +-----------------------------------------------------------------+
| Action by names |
+-----------------------------------------------------------------+ *)typeaction=|InsertofZed_char.t|Insert_strofZed_string.t|Newline|Next_char|Prev_char|Next_line|Prev_line|Join_line|Set_posofint|Gotoofint|Goto_bol|Goto_eol|Goto_bot|Goto_eot|Delete_next_charsofint|Delete_prev_charsofint|Kill_next_charsofint|Kill_prev_charsofint|Delete_next_char|Delete_prev_char|Delete_next_line|Delete_prev_line|Kill_next_line|Kill_prev_line|Switch_erase_mode|Set_mark|Goto_mark|Copy|Kill|Yank|Capitalize_word|Lowercase_word|Uppercase_word|Next_word|Prev_word|Delete_next_word|Delete_prev_word|Kill_next_word|Kill_prev_word|Undoletget_action=function|Insertch->(functx->ifZed_char.lengthch=1theninsert_charctx(Zed_char.corech)elseinsertctx(Zed_rope.singletonch))|Insert_strstr->(functx->insertctx(Zed_rope.of_stringstr))|Newline->newline|Next_char->next_char|Prev_char->prev_char|Next_line->next_line|Prev_line->prev_line|Join_line->join_line|Set_posn->functx->set_positionctxn|Goton->functx->gotoctxn|Goto_bol->goto_bol|Goto_eol->goto_eol|Goto_bot->goto_bot|Goto_eot->goto_eot|Delete_next_charsn->(functx->delete_next_charsctxn)|Delete_prev_charsn->(functx->delete_prev_charsctxn)|Kill_next_charsn->(functx->kill_next_charsctxn)|Kill_prev_charsn->(functx->kill_prev_charsctxn)|Delete_next_char->delete_next_char|Delete_prev_char->delete_prev_char|Delete_next_line->delete_next_line|Delete_prev_line->delete_prev_line|Kill_next_line->kill_next_line|Kill_prev_line->kill_prev_line|Switch_erase_mode->switch_erase_mode|Set_mark->set_mark|Goto_mark->goto_mark|Copy->copy|Kill->kill|Yank->yank|Capitalize_word->capitalize_word|Lowercase_word->lowercase_word|Uppercase_word->uppercase_word|Next_word->next_word|Prev_word->prev_word|Delete_next_word->delete_next_word|Delete_prev_word->delete_prev_word|Kill_next_word->kill_next_word|Kill_prev_word->kill_prev_word|Undo->undoletdoc_of_action=function|Insert_->"insert the given character."|Insert_str_->"insert the given string."|Newline->"insert a newline character."|Next_char->"move the cursor to the next character."|Prev_char->"move the cursor to the previous character."|Next_line->"move the cursor to the next line."|Prev_line->"move the cursor to the previous line."|Join_line->"join two lines into one."|Set_pos_->"move the cursor to the position without poking wanted_column"|Goto_->"move the cursor to the position"|Goto_bol->"move the cursor to the beginning of the current line."|Goto_eol->"move the cursor to the end of the current line."|Goto_bot->"move the cursor to the beginning of the text."|Goto_eot->"move the cursor to the end of the text."|Delete_next_chars_->"delete several characters after the cursor."|Delete_prev_chars_->"delete several characters before the cursor."|Kill_next_chars_->"cut several characters after the cursor."|Kill_prev_chars_->"cut several characters before the cursor."|Delete_next_char->"delete the character after the cursor."|Delete_prev_char->"delete the character before the cursor."|Delete_next_line->"delete everything until the end of the current line."|Delete_prev_line->"delete everything until the beginning of the current line."|Kill_next_line->"cut everything until the end of the current line."|Kill_prev_line->"cut everything until the beginning of the current line."|Switch_erase_mode->"switch the current erasing mode."|Set_mark->"set the mark to the current position."|Goto_mark->"move the cursor to the mark."|Copy->"copy the current region to the clipboard."|Kill->"cut the current region to the clipboard."|Yank->"paste the contents of the clipboard at current position."|Capitalize_word->"capitalize the first word after the cursor."|Lowercase_word->"convert the first word after the cursor to lowercase."|Uppercase_word->"convert the first word after the cursor to uppercase."|Next_word->"move the cursor to the end of the next word."|Prev_word->"move the cursor to the beginning of the previous word."|Delete_next_word->"delete up until the next non-word character."|Delete_prev_word->"delete the word behind the cursor."|Kill_next_word->"cut up until the next non-word character."|Kill_prev_word->"cut the word behind the cursor."|Undo->"revert the last action."letactions=[Newline,"newline";Next_char,"next-char";Prev_char,"prev-char";Next_line,"next-line";Prev_line,"prev-line";Join_line,"join-line";Goto_bol,"goto-bol";Goto_eol,"goto-eol";Goto_bot,"goto-bot";Goto_eot,"goto-eot";Delete_next_char,"delete-next-char";Delete_prev_char,"delete-prev-char";Delete_next_line,"delete-next-line";Delete_prev_line,"delete-prev-line";Kill_next_line,"kill-next-line";Kill_prev_line,"kill-prev-line";Switch_erase_mode,"switch-erase-mode";Set_mark,"set-mark";Goto_mark,"goto-mark";Copy,"copy";Kill,"kill";Yank,"yank";Capitalize_word,"capitalize-word";Lowercase_word,"lowercase-word";Uppercase_word,"uppercase-word";Next_word,"next-word";Prev_word,"prev-word";Delete_next_word,"delete-next-word";Delete_prev_word,"delete-prev-word";Kill_next_word,"kill-next-word";Kill_prev_word,"kill-prev-word";Undo,"undo";]letactions_to_names=Array.of_list(List.sort(fun(a1,_)(a2,_)->comparea1a2)actions)letnames_to_actions=Array.of_list(List.sort(fun(_,n1)(_,n2)->comparen1n2)actions)letparse_insertx=ifZed_utf8.starts_withx"insert("&&Zed_utf8.ends_withx")"thenbeginletstr=String.subx7(String.lengthx-8)inifString.lengthstr=1&&Char.codestr.[0]<128thenInsert(Zed_char.unsafe_of_uChar(Uchar.of_charstr.[0]))elseifString.lengthstr>2&&str.[0]='U'&&str.[1]='+'thenletacc=ref0infori=2toString.lengthstr-1doletch=str.[i]inacc:=!acc*16+(matchchwith|'0'..'9'->Char.codech-Char.code'0'|'a'..'f'->Char.codech-Char.code'a'+10|'A'..'F'->Char.codech-Char.code'A'+10|_->raiseNot_found)done;tryInsert(Zed_char.unsafe_of_uChar(Uchar.of_int!acc))with_->raiseNot_foundelseraiseNot_foundendelseraiseNot_foundletparse_insert_strstr=ifZed_utf8.starts_withstr"insert_str("&&Zed_utf8.ends_withstr")"thenletstr=String.substr11(String.lengthstr-12)intryInsert_str(Zed_string.of_utf8str)with_->raiseNot_foundelseraiseNot_foundletparse_action_countactionact_namestr=letact_len=String.lengthact_nameinifZed_utf8.starts_withstr(act_name^"(")&&Zed_utf8.ends_withstr")"thenletstr=String.substr(act_len+1)(String.lengthstr-(act_len+2))intryaction(int_of_stringstr)with_->raiseNot_foundelseraiseNot_foundletparse_set_pos=parse_action_count(func->Set_posc)"set-pos"letparse_goto=parse_action_count(func->Gotoc)"goto"letparse_delete_next_chars=parse_action_count(func->Delete_next_charsc)"delete-next-chars"letparse_delete_prev_chars=parse_action_count(func->Delete_prev_charsc)"delete-prev-chars"letparse_kill_next_chars=parse_action_count(func->Kill_next_charsc)"kill-next-chars"letparse_kill_prev_chars=parse_action_count(func->Kill_prev_charsc)"kill-prev-chars"letparse_action_paramx=tryparse_insertxwithNot_found->tryparse_insert_strxwithNot_found->tryparse_set_posxwithNot_found->tryparse_gotoxwithNot_found->tryparse_delete_next_charsxwithNot_found->tryparse_delete_prev_charsxwithNot_found->tryparse_kill_next_charsxwithNot_found->parse_kill_prev_charsxletaction_of_namex=letrecloopab=ifa=bthenparse_action_paramxelseletc=(a+b)/2inletaction,name=Array.unsafe_getnames_to_actionscinmatchcomparexnamewith|dwhend<0->loopac|dwhend>0->loop(c+1)b|_->actioninloop0(Array.lengthnames_to_actions)letname_of_actionx=letrecloopab=ifa=bthenraiseNot_foundelseletc=(a+b)/2inletaction,name=Array.unsafe_getactions_to_namescinmatchcomparexactionwith|dwhend<0->loopac|dwhend>0->loop(c+1)b|_->nameinletopenPrintfinletparam_action_to_strnamec=sprintf"%s(%d)"namecinmatchxwith|Insertch->letcode=Uchar.to_int(Zed_char.corech)inifcode<=255thenletch=Char.chr(Uchar.to_int(Zed_char.corech))inmatchchwith|'a'..'z'|'A'..'Z'|'0'..'9'->sprintf"insert(%c)"ch|_->sprintf"insert(U+%02x)"codeelseifcode<=0xffffthensprintf"insert(U+%04x)"codeelsesprintf"insert(U+%06x)"code|Insert_strs->sprintf"insert-str(%s)"(Zed_string.to_utf8s)|Set_posc->param_action_to_str"set-pos"c|Gotoc->param_action_to_str"goto"c|Delete_next_charsc->param_action_to_str"delete-next-chars"c|Delete_prev_charsc->param_action_to_str"delete-prev-chars"c|Kill_next_charsc->param_action_to_str"kill-next-chars"c|Kill_prev_charsc->param_action_to_str"kill-prev-chars"c|_->loop0(Array.lengthactions_to_names)