123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128(**************************************************************************)(* *)(* Copyright 2012,2013 OCamlPro *)(* *)(* All rights reserved.This file is distributed under the terms of the *)(* GNU Lesser General Public License version 3.0 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. *)(* *)(**************************************************************************)openNstreamopenApprox_lexertypeoutput_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)usrletwarn_tabs=reftrueletprint_indent?(empty_line=false)outputlineblankblockusr=ifoutput.in_lineslinethenletindent=ifempty_linethenifoutput.indent_emptythenIndentBlock.guess_indentblockelse0elseIndentBlock.indentblockinmatchoutput.kindwith|Numericpr->prindentusr|Printpr->pr(String.makeindent' ')usr|Extendedpr->prblock(Indentindent)usrelsebeginif!warn_tabs&&String.containsblank'\t'thenbeginwarn_tabs:=false;prerr_endline"Warning: ocp-indent input contains indentation by tabs, \
partial indent will be unreliable."end;matchoutput.kindwith|Numeric_->usr|Printpr->prblankusr|Extendedpr->prblock(Whitespaceblank)usrendletprint_spacingoutputblocktokusr=letline=Region.start_linetok.regioninifIndentBlock.starts_lineblockthenletempty_line=matchtok.tokenwith|EOL->true|_->falseinprint_indent~empty_lineoutputlinetok.betweenblockusrelsepr_whitespaceoutputblocktok.betweenusr(* [block] is the current indentation block
[stream] is the token stream *)letrecproceedoutputstreamblockusr=matchNstream.nextstreamwith|Some({token=EOF},_)|None->usr(* End of file *)|Some(tok,stream)->(* Compute block and indent *)letblock=IndentBlock.updateoutput.configblockstreamtokin(* Update block according to the indent in the file if before the
handled region *)letline=Region.start_linetok.regioninletblock=ifoutput.adaptive&¬(output.in_linesline)thenIndentBlock.reverseblockelseblockinifoutput.debug&&(* tok.token <> EOL && tok.token <> ESCAPED_EOL then *)truethenIndentBlock.dumpblock;(* Do print the current token ... *)usr|>print_spacingoutputblocktok|>pr_stringoutputblocktok.substr(* ... and recurse. *)|>proceedoutputstreamblock