Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file indentPrinter.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276(**************************************************************************)(* *)(* Copyright 2012,2013 OCamlPro *)(* *)(* All rights reserved.This file is distributed under the terms of the *)(* GNU Lesser General Public License version 2.1 with linking *)(* exception. *)(* *)(* TypeRex is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* Lesser GNU General Public License for more details. *)(* *)(**************************************************************************)openCompatopenPosopenNstreamopenApprox_lexeropenUtiltypeoutput_elt=Newline|Indentofint|Whitespaceofstring|Textofstringtype'aoutput_kind=|Numericof(int->'a->'a)|Printof(string->'a->'a)|Extendedof(IndentBlock.t->output_elt->'a->'a)type'aoutput={debug:bool;config:IndentConfig.t;(* Returns true on the lines that should be reindented *)in_lines:int->bool;adaptive:bool;indent_empty:bool;kind:'aoutput_kind;}letstd_output={debug=false;config=IndentConfig.default;in_lines=(fun_->true);adaptive=true;indent_empty=false;kind=Print(funs()->print_endlines);}(* utility functions *)letpr_stringoutputblocktextusr=matchoutput.kindwith|Numeric_->usr|Printf->ftextusr|Extendedf->fblock(Texttext)usrletpr_whitespaceoutputblocktextusr=matchoutput.kindwith|Numeric_->usr|Printf->ftextusr|Extendedf->fblock(Whitespacetext)usrletpr_nloutputblockusr=matchoutput.kindwith|Numeric_->usr|Printpr->pr"\n"usr|Extendedpr->prblockNewlineusr(* indent functions *)typeindentKind=Normal|Empty(* empty line: depending on options, don't indent
or try to guess expected indent. *)|Padded(* for comment continuations: indent the first
line as the following ones*)|Fixedofint(* indent to this value, ignoring the block *)letwarn_tabs=reftrue(* must be called exactly once for each line, in order *)(* let line_debug_counter = ref 0 *)letprint_indentoutputlineblank?(kind=Normal)blockusr=(* assert (incr line_debug_counter; line = !line_debug_counter); *)ifoutput.in_lineslinethenletindent=matchkindwith|Normal->IndentBlock.indentblock|Empty->ifoutput.indent_emptythenIndentBlock.guess_indentlineblockelse0|Padded->IndentBlock.indentblock+IndentBlock.paddingblock|Fixedn->ninmatchoutput.kindwith|Numericpr->prindentusr|Printpr->pr(String.makeindent' ')usr|Extendedpr->prblock(Indentindent)usrelse(if!warn_tabs&&String.containsblank'\t'then(warn_tabs:=false;prerr_endline"Warning: ocp-indent input contains indentation by tabs, \
partial indent will be unreliable.");matchoutput.kindwith|Numeric_->usr|Printpr->prblankusr|Extendedpr->prblock(Whitespaceblank)usr)letprint_tokenoutputblocktokusr=letorig_start_column=IndentBlock.original_columnblockinletstart_column=IndentBlock.offsetblockin(* Handle multi-line tokens (strings, comments) *)letrecprint_extra_lineslinepadlast?(item_cont=false)linesusr=matchlineswith|[]->usr|text::next_lines->letusr=usr|>pr_nloutputblockinifnot(output.in_linesline)thenusr|>print_indentoutputline""block|>pr_stringoutputblocktext|>print_extra_lines(line+1)padtextnext_lineselseifString.trimtext=""&&tok.token<>OCAMLDOC_VERBthenusr|>print_indentoutputline""~kind:Emptyblock|>print_extra_lines(line+1)padtextnext_lineselseletorig_line_indent=count_leading_spacestextinletorig_offset=orig_line_indent-orig_start_columninlettext=String.subtextorig_line_indent(String.lengthtext-orig_line_indent)inletindent_value,item_cont=matchpadwith|None->orig_line_indent,false|Somepad->matchtok.tokenwith|STRING_->ifends_with_escapelastthenifis_prefix"\""text||is_prefix"\\ "textthenstart_column,item_contelsestart_column+pad,item_contelseorig_line_indent,item_cont|COMMENT|COMMENTCONT->letis_item=is_prefix"- "text&¬(is_prefix"- :"text)inletn=ifis_prefix"*"textthen1elseifnotis_item&&item_contthenpad+2elsepadinletitem_cont=is_item||item_cont&&text<>""inletn=ifoutput.config.IndentConfig.i_strict_comments||is_itemthennelsemaxorig_offsetninletn=ifnext_lines=[]&&text="*)"then0elseninstart_column+n,item_cont|QUOTATIONopening->ifis_prefix"{"openingthenorig_line_indent,item_contelse(start_column+ifnext_lines=[]&&text=">>"then0elsemaxorig_offsetpad),item_cont|_->start_column+maxorig_offsetpad,item_continusr|>print_indentoutputline""~kind:(Fixedindent_value)block|>pr_stringoutputblocktext|>print_extra_lines(line+1)pad~item_conttextnext_linesinletline=Region.start_linetok.regioninlettext,next_lines=ifline=Region.end_linetok.regionthen(Lazy.forcetok.substr),[]elsematchstring_split'\n'(Lazy.forcetok.substr)with|[]->assertfalse|hd::tl->hd,tlinletpad=ifnext_lines=[]thenNoneelsematchtok.tokenwith|STRING_->(matchString.trimtextwith|"\""|"\"\\"->None|_->Some1(* length of '"' *))|COMMENT->(matchString.trimtextwith|"(*"whennotoutput.config.IndentConfig.i_strict_comments->None|_->Some(IndentBlock.paddingblock))|COMMENTCONT->Some(IndentBlock.paddingblock)|OCAMLDOC_VERB->None|QUOTATIONopening->letoplen=String.lengthopeninginlettextlen=String.lengthtextinifoplen=textlenthenNoneelseSome(oplen+count_leading_spaces(String.subtextoplen(textlen-oplen-1)))|_->Some2inusr|>pr_stringoutputblocktext|>print_extra_lines(line+1)padtextnext_lines(* [block] is the current indentation block
[stream] is the token stream *)letrecloopoutputblockstreamusr=matchNstream.nextstreamwith|None->usr(* End of file *)|Some(t,stream)->letline=Region.start_linet.regioninletlast_line=line-t.newlinesin(* handle leading blanks (output other lines right now, whitespace in
front of the current token and on the same line is handled later) *)letblank,usr=letrecindent_betweenlineblanksusr=matchblankswith|[]->assertfalse|bl::[]->bl,usr|>pr_nloutputblock|bl::blanks->usr|>pr_nloutputblock|>print_indentoutputlinebl~kind:Emptyblock|>indent_between(line+1)blanksinletblanks=string_split'\n'(Lazy.forcet.between)inmatchblankswith|[]->assertfalse|bl::[]->bl,usr(* no newline *)|bl::blanks->usr|>(iflast_line=0thenprint_indentoutput1""~kind:Emptyblockelsefunusr->usr)|>pr_whitespaceoutputblockbl|>indent_between(last_line+1)blanksin(* Compute block and indent *)letblock=IndentBlock.updateoutput.configblockstreamtin(* Update block according to the indent in the file if before the
handled region *)letblock=ifoutput.adaptive&¬(output.in_linesline)thenIndentBlock.reverseblockelseblockinifoutput.debugthenIndentBlock.dumpblock;(* Handle token *)letat_line_start=t.newlines>0inletusr=ifat_line_startthenletkind=matcht.tokenwith|COMMENTwhenis_prefix"(*\n"(Lazy.forcet.substr)->Fixed(String.lengthblank)|OCAMLDOC_VERB->Padded|EOF->Empty|COMMENTCONTwhen(Lazy.forcet.substr<>"*)")->Padded|_->Normalinusr|>print_indentoutputlineblank~kindblockelseusr|>pr_whitespaceoutputblockblankinletusr=usr|>print_tokenoutputblocktinmatcht.tokenwithEOF->usr|_->usr|>loopoutputblockstreamletproceedoutputstreamblockusr=usr|>loopoutputblockstream