Commits

camlspotter  committed 52b49b7

...

  • Participants
  • Parent commits d65994d

Comments (0)

Files changed (1)

+open Sexplib.Conv
+
 let parse_args () = 
   let rev_paths = ref [] in
   Arg.parse [] (fun s -> rev_paths := s :: !rev_paths) "indent paths";
 end
 
 module Region = struct
+  open Position
   type t = Position.t * Position.t
-  let lnum (p,_) = p.Position.pos_lnum
-  let columns (p,_) = Position.columns p
+  let lnum (p,_) = p.pos_lnum
+  let columns (p,_) = columns p
   let zero = (Position.zero, Position.zero)
+  let move_chars diff (p,p') = 
+    { p  with pos_cnum = p .pos_cnum + diff },
+    { p' with pos_cnum = p'.pos_cnum + diff } 
 end
 
+type kind = [ `TOPLET | `LET | `LPAREN | `LBRACE | `STRUCT | `SIG ] with sexp
+
+type stack = (kind * int) list with sexp
+
 type state = {
-  bases : (Parser.token * int) list; (** indentation stack *)
-  last_region : Region.t;                 (** the last token's region *)
+  bases : stack; (** indentation stack *)
+  last_orig_region : Region.t;            (** the last token's region *)
+  orig_indent : int;  
 }
 
-let indent state token region = 
+let get_indent_chars = function
+  | [] -> 0
+  | (_,i)::_ -> i
+
+
+let pop bases t =
+  let open Parser in
+  let pop f = 
+    let rec pop = function
+      | (token, _) :: bs when f token -> bs
+      | (_, _) :: bs -> pop bs
+      | [] -> bases
+    in
+    pop bases
+  in
+  match t with
+  | RPAREN -> pop (function `LPAREN -> true | _ -> false)
+  | RBRACE -> pop (function `LBRACE -> true | _ -> false)
+  | END ->    pop (function `STRUCT | `SIG -> true | _ -> false)
+  | IN ->     pop (function `LET    -> true | _ -> false)
+  | _ -> bases
+
+(* the indent of a line is computed from:
+   - the state of the last line
+   - the first token of the line
+*)
+let indent bases first_token =
+  pop bases first_token
+;;
+
+(* 
+   bases : If [t] is at the head of the line, [bases] must be updated by [indent]
+   region : With indentation fix. It may not the region from the source.
+*)
+
+let token bases t fixed_region current_indent =
   let open Parser in
 
-  let at_line_head = 
-    Region.lnum state.last_region <> Region.lnum region
-  in
+  let _columns = Region.columns fixed_region in
 
-  let columns = Region.columns region in
+  match t with
+  | LPAREN -> (`LPAREN, current_indent + 2) :: bases
+  | LBRACE -> (`LBRACE, current_indent + 2) :: bases
+  | STRUCT -> (`STRUCT, current_indent + 2) :: bases
+  | SIG    -> (`SIG, current_indent + 2) :: bases
+  | LET -> 
+      let rec is_top = function
+        | [] -> true
+        | ((`STRUCT | `SIG), _) :: _ -> true
+        | (`LET, _) :: _ -> false
+        | _ :: bases -> is_top bases
+      in
 
-  let current_ind = 
-    match state.bases with
-    | [] -> 0
-    | (_,ind)::_ -> ind
-  in
-
-(*
-  let indent_fix = 
-    if at_line_head then current_ind
-    else state.indet_fix in
-  in
-*)
-  
-(*
-  let ind = 
-    if at_line_head then 
-      match token with
-      | AMPERAMPER 
-      | AMPERSAND
-      | BARBAR
-      | COLONCOLON
-      | MINUS
-      | MINUSDOT
-      | PLUS
-      | PLUSDOT
-      | STAR -> base_indent 
-
-      | _ -> base_indent (* + if at_base_line then 0 else 2 *)
-    else (-1)
-  in
-*)
-  let bases = 
-    let open Position in
-
-    let pop f = 
-      let rec pop bases = 
-        begin match bases with
-        | (token, _) :: bases when f token -> bases
-        | (_, _) :: bases -> pop bases
-        | [] -> state.bases
-        end
-      in
-      pop state.bases
-    in
-
-    match token with
-    | LPAREN | LBRACE | STRUCT | LET -> 
-        (token, columns + 2) :: state.bases
-    | RPAREN -> pop (function LPAREN -> true | _ -> false)
-    | RBRACE -> pop (function LBRACE -> true | _ -> false)
-    | END -> pop (function STRUCT -> true | _ -> false)
-    | IN -> pop (function LET -> true | _ -> false)
-
-    | _ -> state.bases
-    in
-  let state = { bases = bases; last_region = region } in
-  match bases with
-  | [] -> 0, state
-  | (_,ind)::_ when at_line_head -> ind, state
-  | _ -> -1, state
+      (`LET, current_indent + 2) :: bases
+  | LET ->    (`LET, current_indent + 2) :: bases
+  | _ ->   pop bases t
+;;
 
 module Lexbuf = struct
 
   let substring t offset len = 
     let offset = offset - t.pos in
     if offset < 0 then assert false;
-    Buffer.sub t.buf offset len
+    try
+      Buffer.sub t.buf offset len
+    with
+    | e -> Format.eprintf "Buffer.sub %S %d %d@." (Buffer.contents t.buf) offset len; raise e
 
   let forget_before t pos =
     assert (t.pos <= pos);
         match LexReader.lex reader Lexer.token with
         | EOF -> ()
         | t -> 
-            let region = LexReader.region reader in
+            (* region from the source *)
+            let orig_region = LexReader.region reader in
+
+            (* space between the last token and the current *)
             let space_between = 
-              let last_end = (snd state.last_region).Position.pos_cnum in
+              let last_end = (snd state.last_orig_region).Position.pos_cnum in
               LexReader.substring 
-                reader last_end ((fst region).Position.pos_cnum - last_end)
+                reader last_end ((fst orig_region).Position.pos_cnum - last_end)
             in
+
+            (* token's string *)
             let substr = LexReader.current_substring reader in
-            let ind, state = indent state t region in
+
+            let new_line = Region.lnum state.last_orig_region <>  Region.lnum orig_region in
+
+            (* original indentation *)
+            let orig_indent = if new_line then Region.columns orig_region else state.orig_indent in
+
+            (* the first token of the line may change the indentation of the line *)
+            let tmp_bases = 
+              if Region.lnum state.last_orig_region <>  Region.lnum orig_region then
+                indent state.bases t 
+              else state.bases
+            in
+
+            let indent = get_indent_chars tmp_bases in
+            
+            (* fixed region *)
+            let fixed_region = Region.move_chars (indent - orig_indent) orig_region in
+
+            let bases = token tmp_bases t fixed_region indent in
+            
+            let state = 
+              { bases = bases;
+                last_orig_region = orig_region; (* or just line number ? *)
+                orig_indent = orig_indent }
+            in
+
+            if new_line then begin
+              let space_between = 
+                try 
+                  let pos = String.rindex space_between '\n' in 
+                  String.sub space_between 0 pos
+                with
+                | _ -> "XXX"
+              in
+              Printf.printf "%s\n" space_between;
 (*
-            Format.eprintf "%S %s %a %d@." 
-              substr
-              (Position.to_string start_pos)
-              Sexplib.Sexp.pp_hum (Parser.sexp_of_token t)
-              ind;
+              print_string (String.make indent ' ');
+              Format.printf "(* %a *)@." Sexplib.Sexp.pp_hum (sexp_of_stack tmp_bases); 
 *)
-            if ind < 0 then begin
-              for i = 0 to String.length space_between - 1 do
-                if space_between.[i] = ' ' then space_between.[i] <- '_'
-              done;
-              Printf.printf "%s" space_between;
-              print_string substr;  
+              print_string (String.make indent ' ');
+              Printf.printf "%s" substr;
             end else begin
-              let r = String.rindex space_between '\n' in
-              Printf.printf "%s" (String.sub space_between 0 r);
-              print_string "\n";
-              print_string (String.make ind ' ');
-              print_string substr;
+              print_string space_between;
+              Printf.printf "%s" substr;
             end;
             loop state
       in
-      loop { bases = []; last_region = Region.zero } 
+      loop { bases = []; last_orig_region = Region.zero; orig_indent = 0 } 
 
     with
     | e ->