anchor.diff:  	 format = unknown}).
   
   
  -%% Start of added by HL
   %% ====================================================================
   %% user-program guided pretty-printing of an abstract syntax tree which
   %% must be a form list.
  
positive.code: maybe_parentheses(D,Prec,Ctxt) ->
      case Ctxt#ctxt.prec of
        P when P > Prec -> lay_parentheses(D,Ctxt);
        _ -> D
      end.
  
  maybe_parentheses_1(D, Node, Ctxt) ->
  
negative.code:     remove_trailing_whitespace(S, [C| Acc]).
  
  
  remove_trailing_whites(Str) ->
      Str1=lists:dropwhile(fun(S)->
                                   lists:member(S, [$\n, $\r, $\t, $\s])
                           end, lists:reverse(Str)),
      lists:reverse(Str1).
      
  get_leading_whites(OriginalToks) ->
      Ts1=lists:takewhile(fun(Ts) ->
                                  all_whites(Ts)
                          end, OriginalToks),
      refac_util:concat_toks(lists:append(Ts1)).
  
  get_trailing_whites(Str) ->   
      lists:reverse(lists:takewhile(fun(S) ->
                                            lists:member(S, [$\n, $\r, $\t, $\s])
                                    end, lists:reverse(Str))).
      
  
  %% =====================================================================
  
  get_start_loc(Node) ->
      {L, _} = get_start_end_loc(Node),
      L.
  
  get_start_end_loc(Node)->
      refac_util:get_start_end_loc(Node).
  
  get_start_line_with_comment(Node) ->
      {{L, _}, _} = get_start_end_loc_with_comment(Node),
      L.
     
  get_end_line_with_comment(Node) ->
      {_, {L, _}} = get_start_end_loc_with_comment(Node),
      L.
  
  get_start_loc_with_comment(Node) ->
      {Start, _}= get_start_end_loc_with_comment(Node),
      Start.
  
  get_end_loc_with_comment(Node) ->
      {_, End}=get_start_end_loc_with_comment(Node),
      End.
  
  get_start_end_loc_with_comment(Node) ->
      {Start, End} = get_start_end_loc(Node),
      PreCs = refac_syntax:get_precomments(Node),
      PostCs = refac_syntax:get_postcomments(Node),
      Start1 = case PreCs of
                   [] ->
                       Start;
                   _ ->
                       refac_syntax:get_pos(hd(PreCs))
               end,
      End1 = case PostCs of
                 [] ->
                     End;
                 _ ->
                     LastC = refac_syntax:comment_text(lists:last(PostCs)),
                     {L, C}=refac_syntax:get_pos(lists:last(PostCs)),
                     {L, C+length(LastC)-1}
             end,
      {Start1, End1}.
  
   
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  repair_new_form_str("", NewFormStr, _TabWidth, _FileFormat) -> NewFormStr;
  repair_new_form_str(OldFormStr, NewFormStr, TabWidth, FileFormat)->
      {ok, OldToks0, _} = refac_scan_with_layout:string(OldFormStr,{1,1}, TabWidth, FileFormat),
      OldToksByLine =group_toks_by_line(OldToks0),
      Str1 = get_leading_whites(OldToksByLine),
      Str2 = get_trailing_whites(OldFormStr),
      NewFormStr1=Str1++remove_trailing_whites(NewFormStr)++Str2,
      {ok, NewToks0, _} = refac_scan_with_layout:string(NewFormStr1, {1,1}, TabWidth, FileFormat),
      NewToksByLine = group_toks_by_line(NewToks0),
      DiffByLine = levenshtein_dist(OldToksByLine, NewToksByLine, TabWidth),
      %% refac_io:format("DiffByLine:\n~p\n", [DiffByLine]),
      repair_form_layout(DiffByLine, TabWidth).
      
  
  repair_form_layout(DiffByLine, TabWidth) ->
      repair_form_layout(DiffByLine, none, TabWidth, []).
  repair_form_layout([], _, _TabWidth, Acc) ->
      refac_util:concat_toks(lists:append(lists:reverse(Acc)));
  repair_form_layout([{'*', LineToks}|Lines], PrevDiff, TabWidth, Acc) ->
      case all_whites(LineToks) of
          true ->
              repair_form_layout(Lines, PrevDiff, TabWidth,[LineToks|Acc]);
          false ->
              repair_form_layout(Lines, '*', TabWidth,[LineToks|Acc])
      end;
  repair_form_layout([{'d', _LineToks}|Lines], _PrevDiff, TabWidth, Acc) ->
      repair_form_layout(Lines, 'd', TabWidth, Acc);
  repair_form_layout([{'i', LineToks}|Lines], _PrevDiff, TabWidth, Acc) ->
      repair_form_layout(Lines, 'i', TabWidth, [LineToks|Acc]);
  repair_form_layout([{'s', OldLineToks, NewLineToks}|Lines], PrevDiff, TabWidth, Acc) ->
      case is_editing_change(OldLineToks, NewLineToks) of
          true ->
              NewLineToks1 = recover_tab_keys(OldLineToks, NewLineToks, TabWidth),
              repair_form_layout(Lines, 's', TabWidth, [NewLineToks1|Acc]);
          false ->
              %% layout change.
              case PrevDiff of 
                  '*' ->
                      repair_form_layout(Lines, '*', TabWidth, [OldLineToks|Acc]);
                  _ -> %% rather conservertive.
                      case all_whites_or_comments(OldLineToks) of 
                          true ->
                              Lines1 = lists:dropwhile(
                                         fun(L) ->
                                                 all_whites_or_comments(element(2,L))
                                         end, Lines),
                              case Lines1 of
                                  [{'s', Toks1, Toks2}|_] ->
                                      case has_layout_change(Toks1, Toks2, TabWidth) of 
                                          true ->
                                              NewLineToks1 = recover_tab_keys(OldLineToks, NewLineToks, TabWidth),
                                              repair_form_layout(Lines, 's', TabWidth, [NewLineToks1|Acc]);
                                          false ->
                                              repair_form_layout(Lines, '*', TabWidth, [OldLineToks|Acc])
                                      end;
                                  _ ->
                                      repair_form_layout(Lines, '*', TabWidth, [OldLineToks|Acc])
                              end;                                
                          false ->
                              NewLineToks1 = recover_tab_keys(OldLineToks, NewLineToks, TabWidth),
                              repair_form_layout(Lines, 's', TabWidth, [NewLineToks1|Acc])
                      end
              end
      end.
  
  is_editing_change(Toks1, Toks2) ->
      remove_loc_and_whites(Toks1) =/=
          remove_loc_and_whites(Toks2).
  
  has_layout_change(Toks1, Toks2, TabWidth) ->
      Toks11 = expand_tab_keys(Toks1, TabWidth),
      Toks21 = expand_tab_keys(Toks2, TabWidth),
      Whites1 = lists:takewhile(fun(T) -> is_whitespace(T) end, Toks11),
      Whites2 = lists:takewhile(fun(T) -> is_whitespace(T) end, Toks21),
      length(Whites1)/=length(Whites2).
                                        
                                      
      
  recover_tab_keys(OldToks, NewToks, TabWidth)->
      TabToks =lists:takewhile(fun(T)-> is_tab_token(T) end, OldToks),
      {WhiteToks, Toks1}=lists:splitwith(fun(T) -> 
                                                 case T of
                                                     {whitespace, _L, ' '} ->
                                                         true;
                                                     _ -> false
                                                 end
                                         end, NewToks),
      recover_tab_keys(TabToks, WhiteToks, TabWidth, [])++Toks1.
  
  recover_tab_keys([], WhiteSpaces, _TabWidth, Acc) ->
      lists:reverse(Acc)++WhiteSpaces;
  recover_tab_keys([T={whitespace, _, '\t'}], WhiteSpaces, TabWidth, Acc) ->
      case length(WhiteSpaces)>=TabWidth of
          true ->
              recover_tab_keys([], lists:nthtail(TabWidth, WhiteSpaces), TabWidth, [T|Acc]);
          false ->
              lists:reverse(Acc)++WhiteSpaces
      end;
  recover_tab_keys([T={whitespace, _, '\t'}|Ts], WhiteSpaces, TabWidth, Acc) ->
      case length(WhiteSpaces)>=TabWidth of
          true ->
              recover_tab_keys(Ts, lists:nthtail(TabWidth, WhiteSpaces), TabWidth, [T|Acc]);
          false ->
             lists:reverse(Acc)++WhiteSpaces
      end.
  
  group_toks_by_line(Toks) ->
      Toks1 =[case T  of 
  		{K, {L,_C}, V} -> {K, L, V};
  		{K, {L,_C}} -> {K, L}
  	    end || T <-Toks],
      group_toks_by_line_1(Toks1,[]).
  
  group_toks_by_line_1([],Acc) -> lists:reverse(Acc);
  group_toks_by_line_1(Toks = [T| _Ts],Acc) ->
      L = element(2,T),
      {Toks1, Toks2} = 
  	lists:partition(fun (T1) ->
  				element(2,T1) == L
  			end,
  			Toks),
      group_toks_by_line_1(Toks2,[Toks1|Acc]).
  
  
                          
  is_tab_token({whitespace, _, '\t'}) ->
      true;
  is_tab_token(_) ->
      false.
  
                                      
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  levenshtein_dist(OldToks, NewToks, TabWidth) ->
      OldLen = length(OldToks),
      NewLen = length(NewToks),
      Is =lists:seq(0, OldLen),
      Js= lists:seq(1, NewLen),
      InitAcc=[{{I,0},I}||I<-Is] ++ [{{0, J}, J}||J<-Js],
      Matrix=levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {1, 1}, InitAcc),
      get_edit_ops(Matrix, OldToks, NewToks, OldLen, NewLen, TabWidth, []). 
      
  
  
  levenshtein_dist(_OldToks, _NewToks, _OldLen, NewLen, _TabWidth, {_I, J}, Acc)
    when J>NewLen ->  Acc;
  levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {I, J}, Acc)
    when I>OldLen ->
      levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {1, J+1}, Acc);
  levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {I, J}, Acc) ->
      case same(lists:nth(I, OldToks), lists:nth(J, NewToks), TabWidth) of
          true ->
              {value, {_, V}}=lists:keysearch({I-1, J-1}, 1, Acc),
              levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {I+1, J}, 
                               [{{I,J},V}|Acc]);
          false ->
              {value, {_, Del}} = lists:keysearch({I-1, J}, 1,Acc),
              {value, {_, Ins}} = lists:keysearch({I, J-1}, 1,Acc),
              {value, {_, Sub}} = lists:keysearch({I-1, J-1},1, Acc),
              Min = lists:min([Del, Ins, Sub]),
              levenshtein_dist(OldToks, NewToks, OldLen, NewLen, TabWidth, {I+1, J}, 
                               [{{I,J},Min+1}|Acc])
      end.
  
  
  get_edit_ops(_Matrix, _OldToks, _NewToks, I, J, _TabWidth, Acc) 
    when I=<0 andalso J=<0 ->
      Acc;
  get_edit_ops(Matrix, OldToks, NewToks, I, J, TabWidth,Acc) ->
      Ith = lists:nth(I, OldToks),
      Jth = lists:nth(J, NewToks),
      case same(Ith, Jth, TabWidth) of
          true ->
              get_edit_ops(Matrix, OldToks, NewToks, I-1, J-1, TabWidth, [{'*', Ith}|Acc]);
          false ->
              {value, {_, Del}} = lists:keysearch({I-1, J}, 1,Matrix),
              {value, {_, Ins}} = lists:keysearch({I, J-1}, 1,Matrix),
              {value, {_, Sub}} = lists:keysearch({I-1, J-1},1, Matrix),
              case lists:min([Del, Ins, Sub]) of
                  Ins ->
                      get_edit_ops(Matrix, OldToks, NewToks, I, J-1, TabWidth, [{'i', Jth}|Acc]);
                  Del ->
                      get_edit_ops(Matrix, OldToks, NewToks, I-1, J, TabWidth, [{'d', Ith}|Acc]);
                  Sub ->
                      get_edit_ops(Matrix, OldToks, NewToks, I-1, J-1, TabWidth, [{'s', Ith, Jth}|Acc])
              end
      end.
  
  
  same(Toks1, Toks2, TabWidth) ->
      case all_whites(Toks1) andalso all_whites(Toks2) of 
  	true ->
  	    true;
  	false ->
  	    same_toks_1(Toks1, Toks2, TabWidth)
      end.
  same_toks_1(Toks1, Toks2, TabWidth) ->
      Toks11=expand_tab_keys(Toks1, TabWidth),
      Toks21=expand_tab_keys(Toks2, TabWidth),
      Toks12=remove_whites_after_first_non_white_token(remove_locs(Toks11)),
      Toks22=remove_whites_after_first_non_white_token(remove_locs(Toks21)),
      Toks12==Toks22.
  
  
  all_whites_or_comments(Toks) ->
       lists:all(fun(T) ->
                         is_whitespace_or_comment(T) 
                 end, Toks).
      
  all_whites(Toks) ->
      lists:all(fun(T) ->
  		      is_whitespace(T) 
  	      end, Toks).
  
  expand_tab_keys(Toks, TabWidth) ->
      lists:append([case T of 
  		      {whitespace, L, '\t'} ->
  			  lists:duplicate(TabWidth, {whitespace, L, ' '});
  		      _ -> [T]
  		  end || T<-Toks]).
  
  
  remove_whites_after_first_non_white_token(Toks) ->
      {Toks1, Toks2}=lists:splitwith(fun(T) ->
  					   is_whitespace_or_comment(T)
  				   end, Toks),
      Toks1++[T||T<-Toks2, not is_whitespace(T)].
  
  remove_loc(T) ->
      case T of
          {K, _L, V} -> {K, 0, V};
          {K, _L} -> {K, 0};
  	 _ -> T
      end.
  
  remove_locs(Toks) when is_list(Toks) ->
      [remove_loc(T)|| T<-Toks];
  remove_locs(Others) ->
      Others.
  
  remove_loc_and_whites(Toks) ->
      [remove_loc(T)||T<-Toks,
           not is_whitespace(T)].
  
  
  remove_locs_whites_and_comments(Toks) ->
      [remove_loc(T)||T<-Toks,
           not is_whitespace_or_comment(T)].
  