Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lTerm_edit.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503(*
* lTerm_edit.ml
* -------------
* Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of Lambda-Term.
*)letpervasives_compare=compareopenZed_editopenLTerm_keyopenLTerm_geomopenLwt_react(* +-----------------------------------------------------------------+
| Actions |
+-----------------------------------------------------------------+ *)typeaction=|ZedofZed_edit.action|Start_macro|Stop_macro|Cancel_macro|Play_macro|Insert_macro_counter|Set_macro_counter|Add_macro_counter|Customof(unit->unit)letdoc_of_action=function|Zedaction->Zed_edit.doc_of_actionaction|Start_macro->"start a new macro."|Stop_macro->"end the current macro."|Cancel_macro->"cancel the current macro."|Play_macro->"play the last recorded macro."|Insert_macro_counter->"insert the current value of the macro counter."|Set_macro_counter->"sets the value of the macro counter."|Add_macro_counter->"adds a value to the macro counter."|Custom_->"programmer defined action."letactions=[Start_macro,"start-macro";Stop_macro,"stop-macro";Cancel_macro,"cancel-macro";Play_macro,"play-macro";Insert_macro_counter,"insert-macro-counter";Set_macro_counter,"set-macro-counter";Add_macro_counter,"add-macro-counter";]letactions_to_names=Array.of_list(List.sort(fun(a1,_)(a2,_)->pervasives_comparea1a2)actions)letnames_to_actions=Array.of_list(List.sort(fun(_,n1)(_,n2)->pervasives_comparen1n2)actions)letaction_of_namex=letrecloopab=ifa=bthenZed(Zed_edit.action_of_namex)elseletc=(a+b)/2inletaction,name=Array.unsafe_getnames_to_actionscinmatchpervasives_comparexnamewith|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_namescinmatchpervasives_comparexactionwith|dwhend<0->loopac|dwhend>0->loop(c+1)b|_->nameinmatchxwith|Zedx->Zed_edit.name_of_actionx|Custom_->"custom"|_->loop0(Array.lengthactions_to_names)moduleBindings=Zed_input.Make(LTerm_key)letbindings=refBindings.emptyletbindseqactions=bindings:=Bindings.addseqactions!bindingsletunbindseq=bindings:=Bindings.removeseq!bindingslet()=bind[{control=false;meta=false;shift=false;code=Left}][ZedPrev_char];bind[{control=false;meta=false;shift=false;code=Right}][ZedNext_char];bind[{control=false;meta=false;shift=false;code=Up}][ZedPrev_line];bind[{control=false;meta=false;shift=false;code=Down}][ZedNext_line];bind[{control=false;meta=false;shift=false;code=Home}][ZedGoto_bol];bind[{control=false;meta=false;shift=false;code=End}][ZedGoto_eol];bind[{control=false;meta=false;shift=false;code=Insert}][ZedSwitch_erase_mode];bind[{control=false;meta=false;shift=false;code=Delete}][ZedDelete_next_char];bind[{control=false;meta=false;shift=false;code=Enter}][ZedNewline];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char' ')}][ZedSet_mark];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'a')}][ZedGoto_bol];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'e')}][ZedGoto_eol];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'd')}][ZedDelete_next_char];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'h')}][ZedDelete_prev_char];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'k')}][ZedKill_next_line];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'u')}][ZedKill_prev_line];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'n')}][ZedNext_line];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'p')}][ZedPrev_line];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'w')}][ZedKill];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'y')}][ZedYank];bind[{control=false;meta=false;shift=false;code=Backspace}][ZedDelete_prev_char];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'w')}][ZedCopy];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'c')}][ZedCapitalize_word];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'l')}][ZedLowercase_word];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'u')}][ZedUppercase_word];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'b')}][ZedPrev_word];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'f')}][ZedNext_word];bind[{control=false;meta=true;shift=false;code=Right}][ZedNext_word];bind[{control=false;meta=true;shift=false;code=Left}][ZedPrev_word];bind[{control=true;meta=false;shift=false;code=Right}][ZedNext_word];bind[{control=true;meta=false;shift=false;code=Left}][ZedPrev_word];bind[{control=false;meta=true;shift=false;code=Backspace}][ZedKill_prev_word];bind[{control=false;meta=true;shift=false;code=Delete}][ZedKill_prev_word];bind[{control=true;meta=false;shift=false;code=Delete}][ZedKill_next_word];bind[{control=false;meta=true;shift=false;code=Char(Uchar.of_char'd')}][ZedKill_next_word];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'_')}][ZedUndo];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=false;meta=false;shift=false;code=Char(Uchar.of_char'(')}][Start_macro];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=false;meta=false;shift=false;code=Char(Uchar.of_char')')}][Stop_macro];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=false;meta=false;shift=false;code=Char(Uchar.of_char'e')}][Play_macro];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'g')}][Cancel_macro];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=true;meta=false;shift=false;code=Char(Uchar.of_char'k')};{control=false;meta=false;shift=false;code=Tab}][Insert_macro_counter];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=true;meta=false;shift=false;code=Char(Uchar.of_char'k')};{control=true;meta=false;shift=false;code=Char(Uchar.of_char'a')}][Add_macro_counter];bind[{control=true;meta=false;shift=false;code=Char(Uchar.of_char'x')};{control=true;meta=false;shift=false;code=Char(Uchar.of_char'k')};{control=true;meta=false;shift=false;code=Char(Uchar.of_char'c')}][Set_macro_counter](* +-----------------------------------------------------------------+
| Widgets |
+-----------------------------------------------------------------+ *)letclipboard=Zed_edit.new_clipboard()letmacro=Zed_macro.create[]letdummy_engine=Zed_edit.create()letdummy_cursor=Zed_edit.new_cursordummy_engineletdummy_context=Zed_edit.contextdummy_enginedummy_cursorletnewline=Zed_char.unsafe_of_uChar(Uchar.of_char'\n')classscrollable=objectinheritLTerm_widget.scrollablemethod!calculate_rangepage_sizedocument_size=(document_size-page_size/2)endletdefault_match_word__=Noneclassedit?(clipboard=clipboard)?(macro=macro)?(size={cols=1;rows=1})()=letlocale,set_locale=S.createNoneinobject(self)inheritLTerm_widget.t"edit"assupervalvscroll=newscrollablemethodvscroll=vscrollmethodclipboard=clipboardmethodmacro=macromethod!can_focus=truevalmutableengine=dummy_enginemethodengine=enginevalmutablecursor=dummy_cursormethodcursor=cursorvalmutablecontext=dummy_contextmethodcontext=contextmethodtext=Zed_rope.to_string(Zed_edit.textengine)valmutablestyle=LTerm_style.nonevalmutablemarked_style=LTerm_style.nonevalmutablecurrent_line_style=LTerm_style.nonemethod!update_resources=letrc=self#resource_classandresources=self#resourcesinstyle<-LTerm_resources.get_stylercresources;marked_style<-LTerm_resources.get_style(rc^".marked")resources;current_line_style<-LTerm_resources.get_style(rc^".current-line")resourcesmethodeditable_pos_len=truemethodmatch_word=default_match_wordmethodlocale=S.valuelocalemethodset_localelocale=set_localelocalevalmutableevent=E.nevervalmutableresolver=Nonevalmutablelocal_bindings=Bindings.emptymethodbindkeysactions=local_bindings<-Bindings.addkeysactionslocal_bindingsvalmutableshift_width=0valmutablestart=0valmutablestart_line=0valmutablesize=sizemethod!size_request=sizemethodprivateupdate_window_position=letline_set=Zed_edit.linesengineinletline_count=Zed_lines.countline_setinletcursor_offset=Zed_cursor.get_positioncursorinletcursor_line=Zed_lines.line_indexline_setcursor_offsetinletcursor_column=cursor_offset-Zed_lines.line_startline_setcursor_lineinletcolumn_display=Zed_lines.force_widthline_set(Zed_lines.line_startline_setcursor_line)cursor_columnin(*** check cursor position is in view *)(* Horizontal check *)ifcolumn_display<shift_width||column_display>=shift_width+size.colsthenbeginshift_width<-max0(column_display-size.cols/2);end;(* Vertical check *)letstart_line'=Zed_lines.line_indexline_setstartinletstart_line'=ifcursor_line<start_line'||cursor_line>=start_line'+size.rowsthenbegin(*let start_line' = max 0 (cursor_line - size.rows / 2) in*)letline_count=Zed_lines.countline_setinletstart_line'=minline_count(max0(cursor_line-size.rows/2))instart<-Zed_lines.line_startline_setstart_line';start_line'endelsestart_line'in(* document size *)ifstart_line<>start_line'thenbeginstart_line<-start_line';vscroll#set_offset~trigger_callback:falsestart_lineend;vscroll#set_document_size(line_count+1);()initializerengine<-(Zed_edit.create~editable:(funposlen->self#editableposlen)?match_word:(ifself#match_word==default_match_wordthenNoneelseSomeself#match_word)~clipboard~locale());cursor<-Zed_edit.new_cursorengine;context<-Zed_edit.contextenginecursor;Zed_edit.set_dataengine(self:>edit);event<-E.map(fun_->self#update_window_position;self#queue_draw)(Zed_edit.updateengine[cursor]);self#on_event(function|LTerm_event.Keykey->beginletres=matchresolverwith|Someres->res|None->Bindings.resolver[Bindings.pack(funx->x)local_bindings;Bindings.pack(funx->x)!bindings]inmatchBindings.resolvekeyreswith|Bindings.Acceptedactions->resolver<-None;letrecexec=function|Customf::actions->Zed_macro.addmacro(Customf);f();execactions|Zedaction::actions->Zed_macro.addmacro(Zedaction);Zed_edit.get_actionactioncontext;execactions|Start_macro::actions->Zed_macro.set_recordingmacrotrue;execactions|Stop_macro::actions->Zed_macro.set_recordingmacrofalse;execactions|Cancel_macro::actions->Zed_macro.cancelmacro;execactions|Play_macro::actions->Zed_macro.cancelmacro;exec(Zed_macro.contentsmacro@actions)|Insert_macro_counter::actions->Zed_macro.addmacroInsert_macro_counter;Zed_edit.insertcontext(Zed_rope.of_string(Zed_string.unsafe_of_utf8(string_of_int(Zed_macro.get_countermacro))));Zed_macro.add_countermacro1;execactions|(Add_macro_counter|Set_macro_counter)::actions->execactions|[]->trueinexecactions|Bindings.Continueres->resolver<-Someres;true|Bindings.Rejected->ifresolver=Nonethenmatchkeywith|{control=false;meta=false;shift=false;code=Charch}->Zed_edit.insert_charcontextch;true|_->falseelsebeginresolver<-None;falseendend|_->false)method!set_allocationrect=size<-size_of_rectrect;super#set_allocationrect;vscroll#set_page_sizesize.rows;start<-0;shift_width<-0;start_line<-0;self#update_window_positioninitializervscroll#on_offset_change(funn->(* find what line the cursor is currently on. *)letline_set=Zed_edit.linesengineinletcursor_offset=Zed_cursor.get_positioncursorinletcursor_line=Zed_lines.line_indexline_setcursor_offsetinstart_line<-n;start<-Zed_lines.line_startline_setstart_line;ifcursor_line<start_linethenbeginletd=start_line-cursor_lineinZed_edit.move_linecontextd(* first row *)endelseifcursor_line>=start_line+size.rowsthenbeginletline_count=Zed_lines.countline_setinletline=max0(min(line_count+1)(start_line+size.rows-1))in(* last row *)letd=line-cursor_lineinZed_edit.move_linecontextdend;self#queue_draw;)method!drawctx_focused=letopenLTerm_drawinletsize=LTerm_draw.sizectxinletline_set=Zed_edit.linesengineinletcursor_offset=Zed_cursor.get_positioncursorinletcursor_line=Zed_lines.line_indexline_setcursor_offsetinletcursor_column=cursor_offset-Zed_lines.line_startline_setcursor_linein(*** Drawing ***)(* Initialises points with the text style and spaces. *)fillctx(Zed_char.unsafe_of_char' ');fill_stylectxstyle;(*** Text drawing ***)letrecdraw_linerowcolzip=ifZed_rope.Zip.at_eoszipthendraw_eoi(row+1)elseletchar,zip=Zed_rope.Zip.nextzipinifchar=newlinethenbeginletrow=row+1inifrow<size.rowsthenbegin_linerowzipendelsebeginifcol>size.colsthenbeginletrow=row+1inifrow<size.rowsthenskip_eolrowzipendelsebegindraw_charctxrowcolchar;draw_linerow(col+(Zed_char.widthchar))zipendendandskip_eolrowzip=ifZed_rope.Zip.at_eoszipthendraw_eoi(row+1)elseletchar,zip=Zed_rope.Zip.nextzipinifchar=newlinethenbegin_linerowzipelseskip_eolrowzipandskip_bolrowzipremaining=ifremaining<=0thendraw_linerow(-remaining)zipelseifZed_rope.Zip.at_eoszipthendraw_eoi(row+1)elseletchar,zip=Zed_rope.Zip.nextzipinifchar=newlinethenbeginletrow=row+1inifrow<size.rowsthenbegin_linerowzipendelseskip_bolrowzip(remaining-(Zed_char.widthchar))andbegin_linerowzip=ifZed_rope.Zip.at_eoszipthendraw_eoirowelseifshift_width<>0thenbeginskip_bolrowzipshift_widthendelsedraw_linerow0zipanddraw_eoi_row=()inlettext=Zed_edit.textengineinbegin_line0(Zed_rope.Zip.make_ftextstart);(* Colorize the current line. *)forcol=0tosize.cols-1doset_style(pointctx(cursor_line-start_line)col)current_line_styledone;(* Colorize the selection if needed *)ifZed_edit.get_selectionenginethenbeginletsel_offset=Zed_cursor.get_position(Zed_edit.markengine)inletsel_line=Zed_lines.line_indexline_setsel_offsetinletsel_column=sel_offset-Zed_lines.line_startline_setsel_lineinletline_a,column_a,line_b,column_b=ifsel_offset<cursor_offsetthen(sel_line,sel_column,cursor_line,cursor_column)else(cursor_line,cursor_column,sel_line,sel_column)inletline_a,column_a=ifline_a<start_linethen(start_line,0)else(line_a,column_a)inletline_b,column_b=ifline_b>=start_line+size.rowsthen(start_line+size.rows-1,size.cols-1)else(line_b,column_b)inifline_a<start_line+size.rows&&line_b>=start_linethenbeginletline_a=line_a-start_lineandline_b=line_b-start_lineinletcolumn_a=column_aandcolumn_b=column_binifline_a=line_bthenforcolumn=column_atocolumn_b-1doset_style(pointctxline_acolumn)marked_styledoneelsebeginforcolumn=column_atosize.cols-1doset_style(pointctxline_acolumn)marked_styledone;forline=line_a+1toline_b-1doforcolumn=0tosize.cols-1doset_style(pointctxlinecolumn)marked_styledonedone;forcolumn=0tocolumn_b-1doset_style(pointctxline_bcolumn)marked_styledoneendendendmethod!cursor_position=letline_set=Zed_edit.linesengineinletcursor_offset=Zed_cursor.get_positioncursorinletcursor_line=Zed_lines.line_indexline_setcursor_offsetinletline_start=Zed_lines.line_startline_setcursor_lineinletstart_line=Zed_lines.line_indexline_setstartinletcol=Zed_lines.force_widthline_setline_start(cursor_offset-line_start)-shift_widthinSome{row=cursor_line-start_line;col}end