Source

ocaml-indent / main.ml

Full commit
camlspotter 4aed057 
camlspotter 69ca6e2 
camlspotter 2b713d1 

camlspotter 341a5a9 
camlspotter d6bf8c4 



camlspotter 2db6c9a 




camlspotter 341a5a9 
camlspotter d6bf8c4 

camlspotter 2b713d1 

camlspotter d6bf8c4 
camlspotter 4f0aaaf 

camlspotter fd613df 
camlspotter 2b713d1 
camlspotter 2db6c9a 

camlspotter fd613df 
camlspotter 69ca6e2 

camlspotter d6bf8c4 
camlspotter 69ca6e2 
camlspotter 2b713d1 

camlspotter 69ca6e2 
camlspotter 2b713d1 
camlspotter d6bf8c4 
camlspotter 2db6c9a 


camlspotter 4f0aaaf 

camlspotter 2db6c9a 
camlspotter 4f0aaaf 
camlspotter 2db6c9a 
camlspotter 4f0aaaf 



camlspotter 2db6c9a 
camlspotter 4f0aaaf 





camlspotter d6bf8c4 
camlspotter 4f0aaaf 
camlspotter 2db6c9a 

camlspotter d6bf8c4 

camlspotter 2db6c9a 
camlspotter 2b713d1 


camlspotter fd613df 
camlspotter 52b49b7 
camlspotter d6bf8c4 
camlspotter 2b713d1 
camlspotter d6bf8c4 

camlspotter fd613df 
camlspotter 2db6c9a 
camlspotter 5287834 
camlspotter 2b713d1 
camlspotter d6bf8c4 

camlspotter 69ca6e2 
camlspotter 2b713d1 


camlspotter d6bf8c4 
camlspotter d31e732 
camlspotter d6bf8c4 
camlspotter 2b713d1 

camlspotter 6a6cb74 
camlspotter d6bf8c4 
camlspotter 2db6c9a 
camlspotter 2b713d1 
camlspotter 2db6c9a 


camlspotter d31e732 
camlspotter d6bf8c4 

camlspotter 2b713d1 







camlspotter d6bf8c4 




camlspotter 2b713d1 

camlspotter d6bf8c4 
camlspotter 2b713d1 




camlspotter 2db6c9a 







camlspotter 2b713d1 

camlspotter 2db6c9a 

camlspotter 2b713d1 

camlspotter 2db6c9a 



camlspotter 69ca6e2 
camlspotter 2b713d1 
camlspotter 2db6c9a 

camlspotter 2b713d1 
camlspotter 2db6c9a 
camlspotter 2b713d1 
camlspotter d6bf8c4 
camlspotter 2db6c9a 
camlspotter 2b713d1 
camlspotter 2db6c9a 
camlspotter d6bf8c4 

camlspotter 2db6c9a 

camlspotter 2b713d1 
camlspotter 2db6c9a 

camlspotter 2b713d1 

camlspotter 2db6c9a 
camlspotter 2b713d1 

camlspotter 17697e6 
camlspotter 2b713d1 



camlspotter 2db6c9a 






camlspotter fd613df 
open Pos
open Args
module State = Machine.State
module Stack = Machine.Stack

module Sexp = Sexplib.Sexp (* No open Sexplib, since Parser corrides with Sexplib.Parser *)

(** [l] is in the interested area or not? *)
let check_line l = function
  | None -> `Inside
  | Some (start, end_) ->
      if l < start then `Before
      else if l <= end_ then `Inside
      else `Over

module Printer : sig
  type t = (int * int) option
  val print_debug  : t -> int-> string -> unit
  val print_string : t -> int -> string -> unit
end = struct

  type t = (int * int) option

  let print_debug t lnum s = match check_line lnum t with
    | `Before | `Over -> ()
    | `Inside -> print_string s

  (** Print a string [s] for the line number [lnum].
      If the printing text exceeds the interested region,
      It stops printing.

      Currently it cannot print a string correctly if it has
      different number of lines from the original.
  *)
  let print_string t lnum s =
    let add_line t lnum s = match check_line lnum t with
      | `Before -> ()
      | `Over -> raise Exit
      | `Inside -> print_string s
    in
    let get_line s =
      try
        let pos = String.index s '\n' in
        String.sub s 0 (pos + 1),
        Some (String.sub s (pos + 1) (String.length s - pos - 1))
      with
      | Not_found -> s, None
    in
    let rec iter lnum s =
      let line, rest =  get_line s in
      add_line t lnum line;
      match rest with
      | Some s -> iter (lnum+1) s
      | None -> ()
    in
    try iter lnum s with Exit -> ()

end

open Tokenstr

let indent_file path =
  let print_string = Printer.print_string lines in
  let print_debug = Printer.print_debug lines in

  let str = if path = "" then Tokenstr.of_channel stdin else Tokenstr.of_path path in

  let flush_remaining_space info =
    print_string (Region.lnum (fst info.space)) (snd info.space)
  in

  let rec loop last_orig_region state str = match Tokenstr.destr str with
    | None -> state

    | Some (({ token = Parser.EOF } as info), _) ->
        flush_remaining_space info;
        state

    | Some (({ token = t;
               region = orig_region;
               space = (_space_between_region, space_between);
               substr } as info), str) ->

        match check_line (Region.lnum orig_region) lines with
        | `Over ->
            (* The token is outside of our interest.
               Print the remaining things and go out *)
            flush_remaining_space info;
            state
        | (`Before | `Inside as line_status) ->
            (*
              Format.eprintf "<%s %d>@."
            *)

            let last_line = Region.lnum last_orig_region in
            let current_line = Region.lnum orig_region in
            let at_new_line = last_line <>  current_line in (* Is this token at a new line? *)

            (* update the original indent if [at_new_line] *)
            let state =
              if at_new_line then { state with State.orig_indent = Region.columns orig_region }
              else state
            in

            (* Where the cursor move *)
            let _cursor_info = match cursor with
              | None -> None
              | Some lines_cols ->
                  match
                    Region.contain_lines_cols last_orig_region lines_cols,
                    Region.contain_lines_cols orig_region lines_cols
                  with
                  | (`In | `Right), _ -> None                   (* far past *)
                  | `Left, `Right     -> None                   (* far future *)
                  | `Left, `Left      -> Some `In_space_between (* cursor in the space_between *)
                  | `Left, `In        -> Some `In_the_token     (* cursor on the token *)
                  | _                 -> assert false           (* It must be more tolerant, but for now... *)
            in

            let fix_indent = match line_status with
              | `Inside -> true
              | `Before -> false
              | `Over -> assert false
            in

            let pre, post = Machine.update_state state ~at_new_line ~fix_indent str orig_region t in

            (* printing *)

            if not at_new_line then print_string current_line space_between
            else begin
              (* the line 1 has no previous new line char *)
              let spaces = try String.sub space_between 0 (String.rindex space_between '\n' + 1) with _ -> "" in
              let indent_string = String.make (State.indent pre) ' ' in

              (* CR jfuruse: can be a bug. something from space_between_region *)
              print_string last_line spaces;

              if debug then begin
                print_string current_line indent_string;
                if pre == post then
                  print_debug current_line
                    (Printf.sprintf "-- %s\n" (Sexp.to_string_mach (Stack.sexp_of_t pre.State.bases)))
                else
                  print_debug current_line
                    (Printf.sprintf "-- %s // %s\n"
                      (Sexp.to_string_mach (Stack.sexp_of_t pre.State.bases))
                      (Sexp.to_string_mach (Stack.sexp_of_t post.State.bases)))
              end;

              print_string current_line indent_string;
            end;

            print_string current_line substr;

            (* Now move to the next token *)
            (* CR jfuruse: last_token thing seems strange. The state machine should be able to
               access previous tokens freely. (But with risk of memory leak) *)
            let last_token = match t with Parser.COMMENT _ -> state.State.last_token | _ ->  Some t in
            let post = 
              { post with 
                State.last_token = last_token; 
                last_indent = if at_new_line then State.indent pre else post.State.last_indent }
            in

            loop orig_region post str
  in
  let final_state = loop Region.zero State.init str in
  if showstate then State.print final_state;
  Tokenstr.close str

let _ = List.iter indent_file paths