rejuvenation_23.0.0_507c1f00/src/rejuvenation-indentation.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
with Ada.Assertions;       use Ada.Assertions;
with Ada.Strings;          use Ada.Strings;
with Ada.Strings.Fixed;    use Ada.Strings.Fixed;
with Langkit_Support.Text; use Langkit_Support.Text;

package body Rejuvenation.Indentation is

   function Node_On_Separate_Lines (Node : Ada_Node'Class) return Boolean is

      function First_Token_On_Line (Token : Token_Reference) return Boolean;

      function First_Token_On_Line (Token : Token_Reference) return Boolean is

         function Previous_Token_Not_On_Line
           (Token : Token_Reference) return Boolean;

         function Previous_Token_Not_On_Line
           (Token : Token_Reference) return Boolean
         is
         begin
            if Token = No_Token then
               return True;
            elsif Kind (Data (Token)) = Ada_Whitespace then
               declare
                  Token_Text : constant String :=
                    Encode (Text (Token), Node.Unit.Get_Charset);
               begin
                  return
                    Index (Token_Text, (1 => ASCII.LF)) > 0
                    or else Previous_Token_Not_On_Line (Previous (Token));
               end;
            else
               Assert
                 (Check   => Kind (Data (Token)) /= Ada_Comment,
                  Message =>
                    "Comment is terminated by line end. " &
                    "So no token can follow it on the same line");
               return False;
            end if;
         end Previous_Token_Not_On_Line;
      begin
         return Previous_Token_Not_On_Line (Previous (Token));
      end First_Token_On_Line;

      function Last_Token_On_Line (Token : Token_Reference) return Boolean;

      function Last_Token_On_Line (Token : Token_Reference) return Boolean is

         function Next_Token_Not_On_Line
           (Token : Token_Reference) return Boolean;

         function Next_Token_Not_On_Line
           (Token : Token_Reference) return Boolean
         is
         begin
            case Kind (Data (Token)) is
               when Ada_Termination =>
                  return True;
               when Ada_Comment =>
                  return Next_Token_Not_On_Line (Next (Token));
                  --  really checking on new line might not be needed,
                  --  since comment in Ada is always terminated by a new line.
               when Ada_Whitespace =>
                  declare
                     Token_Text : constant String :=
                       Encode (Text (Token), Node.Unit.Get_Charset);
                  begin
                     return
                       Index (Token_Text, (1 => ASCII.LF)) > 0
                       or else Next_Token_Not_On_Line (Next (Token));
                  end;
               when others =>
                  return False;
            end case;
         end Next_Token_Not_On_Line;
      begin
         return Next_Token_Not_On_Line (Next (Token));
      end Last_Token_On_Line;

   begin
      return
        First_Token_On_Line (Node.Token_Start)
        and then Last_Token_On_Line (Node.Token_End);
   end Node_On_Separate_Lines;

   function Indentation_Of_Node (Node : Ada_Node'Class) return Integer is
      function Indentatation_Of_Token
        (Token : Token_Reference; Nr : Integer) return Integer;
      function Indentatation_Of_Token
        (Token : Token_Reference; Nr : Integer) return Integer
      is
      begin
         if Token = No_Token then
            return Nr;
         elsif Kind (Data (Token)) = Ada_Whitespace then
            declare
               Token_Text : constant String :=
                 Encode (Text (Token), Node.Unit.Get_Charset);
               Pos : constant Natural :=
                 Index (Token_Text, (1 => ASCII.LF), Going => Backward);
            begin
               if Pos = 0 then
                  return
                    Indentatation_Of_Token
                      (Previous (Token), Nr + Token_Text'Length);
               else
                  return Nr + Token_Text'Last - Pos;
               end if;
            end;
         else
            return No_Indentation;
         end if;
      end Indentatation_Of_Token;

   begin
      return Indentatation_Of_Token (Previous (Node.Token_Start), 0);
   end Indentation_Of_Node;

end Rejuvenation.Indentation;