diff --git a/src/prettier_ada-document_vector_vectors.ads b/src/prettier_ada-document_vector_vectors.ads new file mode 100644 index 0000000..0f4c7da --- /dev/null +++ b/src/prettier_ada-document_vector_vectors.ads @@ -0,0 +1,13 @@ +-- +-- Copyright (C) 2024, AdaCore +-- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-- + +with Ada.Containers.Vectors; +with Prettier_Ada.Document_Vectors; + +package Prettier_Ada.Document_Vector_Vectors is new + Ada.Containers.Vectors + (Positive, + Prettier_Ada.Document_Vectors.Vector, + Prettier_Ada.Document_Vectors."="); diff --git a/src/prettier_ada-documents-builders.adb b/src/prettier_ada-documents-builders.adb index 40bd6a7..4be701f 100644 --- a/src/prettier_ada-documents-builders.adb +++ b/src/prettier_ada-documents-builders.adb @@ -435,4 +435,158 @@ package body Prettier_Ada.Documents.Builders is procedure Reset_Document_Id renames Prettier_Ada.Documents.Implementation.Reset_Document_Id; + --------------------- + -- Alignment_Table -- + --------------------- + + function Alignment_Table + (Rows : Document_Table; Must_Break : Boolean := True) return Document_Type + is + Elements : Prettier_Ada.Document_Vector_Vectors.Vector; + Separators : Prettier_Ada.Document_Vector_Vectors.Vector; + + procedure Normalize_Table; + -- Splits Rows into Elements and Separators. + -- Separators are placed between elements so this ensures that for each + -- row: + -- Elements (row).Length = Separators (row).Length - 1 + -- + -- Example: + -- + -- Rows: [[E11, S11, E12, S12, E13], [E21, S21, E22, S22, E23]] + -- + -- Results in: + -- + -- Elements: [[E11, E12, E13], [E21, E22, E23]] + -- Separators: [[S11, S12], [S21, S22]] + + --------------------- + -- Normalize_Table -- + --------------------- + + procedure Normalize_Table is + begin + -- Iterate through all rows + + for Row_Index in Rows.First_Index .. Rows.Last_Index loop + declare + use Prettier_Ada.Document_Vector_Vectors; + + use type Ada.Containers.Count_Type; + + Row : constant Constant_Reference_Type := + Rows.Constant_Reference (Row_Index); + -- This is the current row + + -- For each row, we will have a list of elements and a list + -- of separators. + + Row_Elements : Prettier_Ada.Document_Vectors.Vector; + Row_Separators : Prettier_Ada.Document_Vectors.Vector; + + Elements_Aggregate : Prettier_Ada.Document_Vectors.Vector; + -- Elements that follow another element are aggregated + -- together. + + begin + -- Iterate through all columns + + for Column_Index in Row.First_Index .. Row.Last_Index loop + declare + use Prettier_Ada.Document_Vectors; + + Table_Element : + constant Prettier_Ada + .Document_Vectors + .Constant_Reference_Type := + Row.Constant_Reference (Column_Index); + + Is_Separator : constant Boolean := + Table_Element.Bare_Document.Kind in Document_Command + and then Table_Element.Bare_Document.Command.Kind + in Command_Alignment_Table_Separator; + -- A table element can either be an element or a + -- separator. + begin + if Is_Separator then + -- Start by adding Elements_Aggregate to Row_Elements + + if Elements_Aggregate.Is_Empty then + -- No elements before the separator. Simply add an + -- empty string. + + Row_Elements.Append + (Text + (Ada.Strings.Unbounded.Null_Unbounded_String)); + + elsif Elements_Aggregate.Length = 1 then + Row_Elements.Append + (Elements_Aggregate.First_Element); + + else + Row_Elements.Append (Group (Elements_Aggregate)); + end if; + + Elements_Aggregate.Clear; + + -- Then add the separator to Row_Separators + + Row_Separators.Append (Table_Element); + + else + Elements_Aggregate.Append (Table_Element); + end if; + end; + end loop; + + -- If the last element of this row is not a separator, then + -- Elements_Aggregate won't be empty. If so, add it to + -- Row_Elements. + + if not Elements_Aggregate.Is_Empty then + if Elements_Aggregate.Length = 1 then + Row_Elements.Append (Elements_Aggregate.First_Element); + + else + Row_Elements.Append (Group (Elements_Aggregate)); + end if; + end if; + + -- Flush this row's elements and separators + Elements.Append (Row_Elements); + Separators.Append (Row_Separators); + end; + end loop; + end Normalize_Table; + + begin + Normalize_Table; + + return + Wrap_Command + (new Command_Type' + (Kind => Command_Alignment_Table, + Alignment_Table_Elements => Elements, + Alignment_Table_Separators => Separators, + Alignment_Table_Must_Break => Must_Break)); + end Alignment_Table; + + ------------------------------- + -- Alignment_Table_Separator -- + ------------------------------- + + function Alignment_Table_Separator + (Aligner_Text : Ada.Strings.Unbounded.Unbounded_String) + return Document_Type + is + begin + return + Wrap_Command + (new Command_Type' + (Kind => + Command_Alignment_Table_Separator, + Alignment_Table_Separator_Text => + To_Prettier_String (Aligner_Text))); + end Alignment_Table_Separator; + end Prettier_Ada.Documents.Builders; diff --git a/src/prettier_ada-documents-builders.ads b/src/prettier_ada-documents-builders.ads index a9bfe41..5f39827 100644 --- a/src/prettier_ada-documents-builders.ads +++ b/src/prettier_ada-documents-builders.ads @@ -4,6 +4,7 @@ -- with Prettier_Ada.Document_Vectors; +with Prettier_Ada.Document_Vector_Vectors; -- This package provides functions to build a Document_Type. -- The API mimics the original Prettier builders API with the following @@ -17,6 +18,7 @@ with Prettier_Ada.Document_Vectors; package Prettier_Ada.Documents.Builders is subtype Document_Vector is Prettier_Ada.Document_Vectors.Vector; + subtype Document_Table is Prettier_Ada.Document_Vector_Vectors.Vector; No_Document : constant Document_Type; @@ -171,6 +173,16 @@ package Prettier_Ada.Documents.Builders is return Document_Type; -- Join an array of Documents with a Separator + function Alignment_Table + (Rows : Document_Table; Must_Break : Boolean := True) + return Document_Type; + -- Create a new Aligment_Table Document Command + + function Alignment_Table_Separator + (Aligner_Text : Ada.Strings.Unbounded.Unbounded_String) + return Document_Type; + -- Create a new Aligment_Table_Separator Document Command + private No_Document : constant Document_Type := Prettier_Ada.Documents.No_Document; diff --git a/src/prettier_ada-documents-implementation.adb b/src/prettier_ada-documents-implementation.adb index b221310..fb62eed 100644 --- a/src/prettier_ada-documents-implementation.adb +++ b/src/prettier_ada-documents-implementation.adb @@ -30,8 +30,6 @@ package body Prettier_Ada.Documents.Implementation is subtype Optional_Boolean is Optional_Booleans.Generic_Optional_Type; - subtype Document_Vector is Prettier_Ada.Document_Vectors.Vector; - package Document_Hashed_Sets is new Ada.Containers.Hashed_Sets (Element_Type => Document_Type, @@ -90,6 +88,28 @@ package body Prettier_Ada.Documents.Implementation is subtype Symbol_To_Mode_Map is Symbol_To_Mode_Maps.Map; + type Format_State_Record is record + Current_Line_Length : Natural; + Group_Mode_Map : Symbol_To_Mode_Map; + Line_Suffix : Print_Command_Type_Vector; + Print_Commands : Print_Command_Type_Vector; + Printed_Cursor_Count : Natural; + Result : Prettier_String; + Should_Remeasure : Boolean; + Last_Was_Hardline : Boolean; + -- Flag indicating if the last text added to Result was a hardline + end record; + + Default_Format_State : constant Format_State_Record := + (Current_Line_Length => 0, + Group_Mode_Map => Symbol_To_Mode_Maps.Empty_Map, + Line_Suffix => [], + Print_Commands => [], + Printed_Cursor_Count => 0, + Result => Empty_Prettier_String, + Should_Remeasure => False, + Last_Was_Hardline => False); + procedure Append (To : in out Prettier_String; Source : Prettier_String); -- Append Source to the end of To @@ -107,6 +127,12 @@ package body Prettier_Ada.Documents.Implementation is return Boolean; -- TODO: Description + procedure Format + (Format_State : in out Format_State_Record; + Format_Options : Format_Options_Type); + -- Resume the formatting operations on Format_State. + -- Formats according to Format_Options. + function Generate_Indentation (From : Indentation_Queue_Type; Data : Indentation_Data_Type; @@ -237,7 +263,6 @@ package body Prettier_Ada.Documents.Implementation is and not Group_Command.Break then -- TODO: Why should this be "propagated"? - Gnatfmt_Trace.Trace ("BPG"); Group_Command.all.Break := True; end if; end; @@ -294,18 +319,13 @@ package body Prettier_Ada.Documents.Implementation is Current_Has_Line_Suffix : Boolean := Has_Line_Suffix; begin - Gnatfmt_Trace.Trace ("F1"); if Remaining_Width = Integer'Last then - Gnatfmt_Trace.Trace ("F2"); return True; end if; while Remaining_Width >= 0 loop - Gnatfmt_Trace.Trace ("F3"); if Fit_Commands.Is_Empty then - Gnatfmt_Trace.Trace ("F4"); if Rest_Idx < Rest_Commands.First_Index then - Gnatfmt_Trace.Trace ("F5"); return True; end if; @@ -313,7 +333,6 @@ package body Prettier_Ada.Documents.Implementation is Rest_Idx := @ - Natural (1); else - Gnatfmt_Trace.Trace ("F6"); declare Current_Fit_Command : constant Fit_Command_Type := Fit_Commands.Last_Element; @@ -322,24 +341,22 @@ package body Prettier_Ada.Documents.Implementation is Document : Document_Type renames Current_Fit_Command.Document; + use type Ada.Containers.Count_Type; + begin - Gnatfmt_Trace.Trace ("F7"); Fit_Commands.Delete_Last; case Document.Bare_Document.Kind is when Document_Text => - Gnatfmt_Trace.Trace ("F8"); Append (Current_Line, Document.Bare_Document.Text); Remaining_Width := @ - Document.Bare_Document.Text.Display_Width; when Document_List => - Gnatfmt_Trace.Trace ("F9"); for Child_Document of reverse Get_Document_Parts (Document) loop - Gnatfmt_Trace.Trace ("F10"); Fit_Commands.Append (Fit_Command_Type'(Mode, Child_Document)); end loop; @@ -347,17 +364,14 @@ package body Prettier_Ada.Documents.Implementation is when Document_Command => case Document.Bare_Document.Command.Kind is when Command_Fill => - Gnatfmt_Trace.Trace ("F9"); for Child_Document of reverse Get_Document_Parts (Document) loop - Gnatfmt_Trace.Trace ("F10"); Fit_Commands.Append (Fit_Command_Type'(Mode, Child_Document)); end loop; when Command_Indent => - Gnatfmt_Trace.Trace ("F11"); Ada.Assertions.Assert (Document .Bare_Document @@ -373,7 +387,6 @@ package body Prettier_Ada.Documents.Implementation is .Indent_Contents)); when Command_Align => - Gnatfmt_Trace.Trace ("F11"); Ada.Assertions.Assert (Document .Bare_Document @@ -389,7 +402,6 @@ package body Prettier_Ada.Documents.Implementation is .Align_Contents)); when Command_Indent_If_Break => - Gnatfmt_Trace.Trace ("F11"); Ada.Assertions.Assert (Document .Bare_Document @@ -405,7 +417,6 @@ package body Prettier_Ada.Documents.Implementation is .Indent_If_Break_Contents)); when Command_Label => - Gnatfmt_Trace.Trace ("F11"); Ada.Assertions.Assert (Document .Bare_Document @@ -421,21 +432,16 @@ package body Prettier_Ada.Documents.Implementation is .Label_Contents)); when Command_Trim => - Gnatfmt_Trace.Trace ("F12"); Remaining_Width := @ + Trim (Current_Line); when Command_Group => - Gnatfmt_Trace.Trace ("F13"); if Must_Be_Flat and Document.Bare_Document.Command.Break then - Gnatfmt_Trace.Trace ("F14"); return False; end if; declare - use type Ada.Containers.Count_Type; - Group_Mode : constant Mode_Kind := (if Document.Bare_Document.Command.Break then Mode_Break @@ -468,7 +474,6 @@ package body Prettier_Ada.Documents.Implementation is .Group_Contents); begin - Gnatfmt_Trace.Trace ("F15"); Fit_Commands.Append (Fit_Command_Type'(Group_Mode, Contents)); end; @@ -510,7 +515,6 @@ package body Prettier_Ada.Documents.Implementation is .Flat_Contents); begin - Gnatfmt_Trace.Trace ("F16"); if Contents /= No_Document and then (if Contents.Bare_Document.Kind in Document_Text @@ -521,35 +525,28 @@ package body Prettier_Ada.Documents.Implementation is .Text .Is_Empty) then - Gnatfmt_Trace.Trace ("F17"); Fit_Commands.Append (Fit_Command_Type'(Mode, Contents)); end if; end; when Command_Line => - Gnatfmt_Trace.Trace ("F18"); if Mode = Mode_Break or Document.Bare_Document.Command.Hard then - Gnatfmt_Trace.Trace ("F19"); return True; end if; if not Document.Bare_Document.Command.Soft then - Gnatfmt_Trace.Trace ("F20"); Append (Current_Line, (" ", 1)); Remaining_Width := @ - Natural (1); end if; when Command_Line_Suffix => - Gnatfmt_Trace.Trace ("F21"); Current_Has_Line_Suffix := True; when Command_Line_Suffix_Boundary => - Gnatfmt_Trace.Trace ("F22"); if Current_Has_Line_Suffix then - Gnatfmt_Trace.Trace ("F23"); return False; end if; @@ -557,6 +554,159 @@ package body Prettier_Ada.Documents.Implementation is | Command_Cursor => null; + when Command_Alignment_Table => + -- First check if the table has more than 1 row and + -- must break. In such case, no calculations are + -- needed. + + if Document + .Bare_Document + .Command + .Alignment_Table_Elements + .Length > 1 + and then Document + .Bare_Document + .Command + .Alignment_Table_Must_Break + then + return False; + end if; + + declare + Alignment_Table_Elements : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Elements; + Alignment_Table_Separators : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Separators; + + -- The algorithm relies on not only checking the + -- previous elements/separators of the row but + -- also of other rows. The easist way to do this + -- is with indices. Start by finding the longest + -- column and row. + + First_Row_Index : constant Positive := + Alignment_Table_Elements.First_Index; + Last_Row_Index : constant Positive := + Alignment_Table_Elements.Last_Index; + First_Column_Index : constant Positive := + Alignment_Table_Elements + .Constant_Reference (First_Row_Index) + .First_Index; + Last_Column_Index : constant Positive := + [for Row_Elements of Alignment_Table_Elements + => Row_Elements.Last_Index]'Reduce + (Positive'Max, + 1); + + begin + -- Append to Fit_Comands every element/separator + -- in reverse order (starting from the last + -- column of the last row). + + for Column_Index + in reverse First_Column_Index + .. Last_Column_Index + loop + if Alignment_Table_Separators + .Constant_Reference (Last_Row_Index) + .Last_Index + >= Column_Index + then + Fit_Commands.Append + (Fit_Command_Type' + (Mode_Flat, + Alignment_Table_Separators + .Constant_Reference + (Last_Row_Index) + .Constant_Reference + (Column_Index))); + end if; + + if Alignment_Table_Elements + .Constant_Reference (Last_Row_Index) + .Last_Index + >= Column_Index + then + Fit_Commands.Append + (Fit_Command_Type' + (Mode_Flat, + Alignment_Table_Elements + .Constant_Reference + (Last_Row_Index) + .Constant_Reference + (Column_Index))); + end if; + end loop; + + for Row_Index + in reverse First_Row_Index + .. Standard."-" (Last_Row_Index, 1) + loop + -- At a Line between rows + + Fit_Commands.Append + (Fit_Command_Type' + (Mode_Flat, + Prettier_Ada.Documents.Builders.Line)); + + for Column_Index + in reverse First_Column_Index + .. Last_Column_Index + loop + if Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Last_Index + >= Column_Index + then + Fit_Commands.Append + (Fit_Command_Type' + (Mode_Flat, + Alignment_Table_Separators + .Constant_Reference + (Row_Index) + .Constant_Reference + (Column_Index))); + end if; + + if Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Last_Index + >= Column_Index + then + Fit_Commands.Append + (Fit_Command_Type' + (Mode_Flat, + Alignment_Table_Elements + .Constant_Reference + (Row_Index) + .Constant_Reference + (Column_Index))); + end if; + end loop; + end loop; + end; + + when Command_Alignment_Table_Separator => + Append + (Current_Line, + Document + .Bare_Document + .Command + .Alignment_Table_Separator_Text); + Remaining_Width := + @ + - Document + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Display_Width; + end case; end case; end; @@ -574,12 +724,56 @@ package body Prettier_Ada.Documents.Implementation is (Document : Document_Type; Options : Format_Options_Type := Default_Format_Options) return Ada.Strings.Unbounded.Unbounded_String + is + State : Format_State_Record := Default_Format_State; + + begin + -- Adapt State, which at this point is a Default_Format_state, based + -- on Document (to be formatted) and Options. + + State.Current_Line_Length := + Options.Indentation.Offset.Spaces + + Options.Indentation.Offset.Tabs * Options.Indentation.Width; + + State.Result := + (VSS.Strings."&" + (VSS.Strings."*" + (VSS.Strings.Character_Count (Options.Indentation.Offset.Tabs), + VSS.Characters.Latin.Character_Tabulation), + VSS.Strings."*" + (VSS.Strings.Character_Count (Options.Indentation.Offset.Spaces), + VSS.Characters.Latin.Space)), + VSS.Strings.Display_Cell_Count + (Options.Indentation.Offset.Spaces + + Options.Indentation.Offset.Tabs * Options.Indentation.Width)); + + State.Print_Commands := + [Print_Command_Type' + (Root_Indent (Options.Indentation), + Mode_Break, + Document)]; + + Propagate_Breaks (Document); + + Format (State, Options); + + return + VSS.Strings.Conversions.To_Unbounded_UTF_8_String (State.Result.Text); + end Format; + + ------------ + -- Format -- + ------------ + + procedure Format + (Format_State : in out Format_State_Record; + Format_Options : Format_Options_Type) is use type Ada.Containers.Count_Type; use type VSS.Strings.Virtual_String; End_Of_Line : constant Prettier_String := - (case Options.End_Of_Line is + (case Format_Options.End_Of_Line is when LF => (VSS.Strings.Empty_Virtual_String & VSS.Characters.Latin.Line_Feed, @@ -594,44 +788,11 @@ package body Prettier_Ada.Documents.Implementation is & VSS.Characters.Latin.Line_Feed, 0)); - Group_Mode_Map : Symbol_To_Mode_Map; - - Pos : Natural := - Options.Indentation.Offset.Spaces - + Options.Indentation.Offset.Tabs * Options.Indentation.Width; - - Should_Remeasure : Boolean := False; - - Line_Suffix : Print_Command_Type_Vector := []; - - Print_Commands : Print_Command_Type_Vector := - [Print_Command_Type' - (Root_Indent (Options.Indentation), - Mode_Break, - Document)]; - - Printed_Cursor_Count : Natural := 0; - - Result : Prettier_String := - (VSS.Strings."&" - (VSS.Strings."*" - (VSS.Strings.Character_Count (Options.Indentation.Offset.Tabs), - VSS.Characters.Latin.Character_Tabulation), - VSS.Strings."*" - (VSS.Strings.Character_Count (Options.Indentation.Offset.Spaces), - VSS.Characters.Latin.Space)), - VSS.Strings.Display_Cell_Count - (Options.Indentation.Offset.Spaces - + Options.Indentation.Offset.Tabs * Options.Indentation.Width)); - begin - - Propagate_Breaks (Document); - - while Print_Commands.Length > 0 loop + while Format_State.Print_Commands.Length > 0 loop declare Print_Command : constant Print_Command_Type := - Print_Commands.Last_Element; + Format_State.Print_Commands.Last_Element; Indentation : Indentation_Queue_Type renames Print_Command.Indentation; Mode : Mode_Kind renames Print_Command.Mode; @@ -652,6 +813,29 @@ package body Prettier_Ada.Documents.Implementation is procedure Process_Document_Text; -- TODO: Description + procedure Process_Document_Command_Alignment_Table; + -- Processes Print_Command as an Alignment_Table. + -- An Alignment_Table can be processed in two modes: + -- - Break + -- - Flat + -- + -- To process an Alignment Table in Break mode, each column is + -- handled sequentially. For each column, the required alignment + -- is calculated and applied. Once a column is processed, its + -- separators are appended. This process is repeated for each + -- column until the entire table is processed. + -- + -- To process an Alignment_Table in Flat mode, each row is handled + -- sequentually as list. + + procedure Process_Document_Command_Alignment_Table_Separator; + -- Processes Print_Command as an Alignment_Table_Separator + -- command. An Alignment_Table_Separator command is only processed + -- this way if it's not a child document of an Alignment_Table or + -- if the Alignment_Table was handled in Flat mode. In this case, + -- the separators' text is simply appended to + -- Format_State.Result. + ------------------------------------ -- Process_Document_Command_Group -- ------------------------------------ @@ -676,32 +860,25 @@ package body Prettier_Ada.Documents.Implementation is .Bare_Document .Command .Group_Contents); - Remainder : constant Integer := - Options.Width - Pos; - Has_Line_Suffix : constant Boolean := - Line_Suffix.Length > 0; + Remaining_Line_Length : constant Integer := + Format_Options.Width - Format_State.Current_Line_Length; + Has_Line_Suffix : constant Boolean := + Format_State.Line_Suffix.Length > 0; begin - Gnatfmt_Trace.Trace ("72"); - Should_Remeasure := False; + Format_State.Should_Remeasure := False; if not Document.Bare_Document.Command.Break and then Fits (Next, - Print_Commands, - Remainder, + Format_State.Print_Commands, + Remaining_Line_Length, Has_Line_Suffix, - Group_Mode_Map) + Format_State.Group_Mode_Map) then - Gnatfmt_Trace.Trace ("721"); - Gnatfmt_Trace.Trace - ((if Next.Mode = Mode_Flat - then "flat" - else "break")); - Print_Commands.Append (Next); + Format_State.Print_Commands.Append (Next); else - Gnatfmt_Trace.Trace ("722"); if Document .Bare_Document .Command @@ -714,7 +891,6 @@ package body Prettier_Ada.Documents.Implementation is .Bare_Document .List.Length /= 0 then - Gnatfmt_Trace.Trace ("7221"); declare Expanded_States : constant Document_Vector := @@ -734,16 +910,13 @@ package body Prettier_Ada.Documents.Implementation is .Command .Break then - Gnatfmt_Trace.Trace ("72211"); - Gnatfmt_Trace.Trace ("break"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode_Break, Most_Expanded)); else - Gnatfmt_Trace.Trace ("72212"); for J in Expanded_States.First_Index + Natural (1) .. Expanded_States.Last_Index + Natural (1) @@ -751,15 +924,12 @@ package body Prettier_Ada.Documents.Implementation is if J >= Expanded_States.Last_Index + Natural (1) then - Gnatfmt_Trace.Trace ("722121"); - Gnatfmt_Trace.Trace ("break"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode_Break, Most_Expanded)); else - Gnatfmt_Trace.Trace ("722122"); declare State : constant Document_Type := @@ -773,18 +943,12 @@ package body Prettier_Ada.Documents.Implementation is begin if Fits (Print_Command, - Print_Commands, - Remainder, + Format_State.Print_Commands, + Remaining_Line_Length, Has_Line_Suffix, - Group_Mode_Map) + Format_State.Group_Mode_Map) then - Gnatfmt_Trace.Trace ("7221221"); - Gnatfmt_Trace.Trace - ((if Print_Command.Mode - = Mode_Flat - then "flat" - else "break")); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command); exit; end if; @@ -795,9 +959,7 @@ package body Prettier_Ada.Documents.Implementation is end; else - Gnatfmt_Trace.Trace ("7222"); - Gnatfmt_Trace.Trace ("break"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode_Break, @@ -816,28 +978,21 @@ package body Prettier_Ada.Documents.Implementation is procedure Process_Mode_Flat is Print_Command : constant Print_Command_Type := Print_Command_Type' - (Indentation, - (if Document - .Bare_Document - .Command - .Break - then Mode_Break - else Mode_Flat), - Document - .Bare_Document - .Command - .Group_Contents); + (Indentation, + (if Document + .Bare_Document + .Command + .Break + then Mode_Break + else Mode_Flat), + Document + .Bare_Document + .Command + .Group_Contents); begin - Gnatfmt_Trace.Trace ("71"); - if not Should_Remeasure then - Gnatfmt_Trace.Trace ("711"); - Gnatfmt_Trace.Trace - ((if Print_Command.Mode = Mode_Flat - then "flat" - else "break")); - Print_Commands.Append (Print_Command); + if not Format_State.Should_Remeasure then + Format_State.Print_Commands.Append (Print_Command); else - Gnatfmt_Trace.Trace ("712"); Process_Mode_Break; end if; end Process_Mode_Flat; @@ -857,9 +1012,9 @@ package body Prettier_Ada.Documents.Implementation is if Document.Bare_Document.Command.Id /= No_Symbol then - Group_Mode_Map.Include + Format_State.Group_Mode_Map.Include (Document.Bare_Document.Command.Id, - Print_Commands.Last_Element.Mode); + Format_State.Print_Commands.Last_Element.Mode); end if; end Process_Document_Command_Group; @@ -868,7 +1023,8 @@ package body Prettier_Ada.Documents.Implementation is ----------------------------------- procedure Process_Document_Command_Fill is - Remainder : constant Integer := Options.Width - Pos; + Remaining_Line_Length : constant Integer := + Format_Options.Width - Format_State.Current_Line_Length; Parts : constant Document_Vector := Document .Bare_Document @@ -888,16 +1044,21 @@ package body Prettier_Ada.Documents.Implementation is Fits (Content_Flat_Command, [], - Remainder, - Line_Suffix.Length > 0, - Group_Mode_Map, + Remaining_Line_Length, + Format_State.Line_Suffix.Length > 0, + Format_State.Group_Mode_Map, True); begin if Content_Fits then - Print_Commands.Append (Content_Flat_Command); + Format_State + .Print_Commands + .Append (Content_Flat_Command); + else - Print_Commands.Append (Content_Break_Command); + Format_State + .Print_Commands + .Append (Content_Break_Command); end if; end; @@ -919,19 +1080,27 @@ package body Prettier_Ada.Documents.Implementation is Fits (Content_Flat_Command, [], - Remainder, - Line_Suffix.Length > 0, - Group_Mode_Map, + Remaining_Line_Length, + Format_State.Line_Suffix.Length > 0, + Format_State.Group_Mode_Map, True); begin if Content_Fits then - Print_Commands.Append (White_Flat_Command); - Print_Commands.Append (Content_Flat_Command); + Format_State + .Print_Commands + .Append (White_Flat_Command); + Format_State + .Print_Commands + .Append (Content_Flat_Command); else - Print_Commands.Append (White_Break_Command); - Print_Commands.Append (Content_Break_Command); + Format_State + .Print_Commands + .Append (White_Break_Command); + Format_State + .Print_Commands + .Append (Content_Break_Command); end if; end; @@ -958,9 +1127,9 @@ package body Prettier_Ada.Documents.Implementation is Fits (Content_Flat_Command, [], - Remainder, - Line_Suffix.Length > 0, - Group_Mode_Map, + Remaining_Line_Length, + Format_State.Line_Suffix.Length > 0, + Format_State.Group_Mode_Map, True); Remaining_Parts : constant Document_Vector := @@ -988,26 +1157,44 @@ package body Prettier_Ada.Documents.Implementation is Fits (First_And_Second_Content_Flat_Command, [], - Remainder, - Line_Suffix.Length > 0, - Group_Mode_Map, + Remaining_Line_Length, + Format_State.Line_Suffix.Length > 0, + Format_State.Group_Mode_Map, True); begin if First_And_Second_Content_Fits then - Print_Commands.Append (Remaining_Print_Command); - Print_Commands.Append (White_Flat_Command); - Print_Commands.Append (Content_Flat_Command); + Format_State + .Print_Commands + .Append (Remaining_Print_Command); + Format_State + .Print_Commands + .Append (White_Flat_Command); + Format_State + .Print_Commands + .Append (Content_Flat_Command); elsif Content_Fits then - Print_Commands.Append (Remaining_Print_Command); - Print_Commands.Append (White_Break_Command); - Print_Commands.Append (Content_Flat_Command); + Format_State + .Print_Commands + .Append (Remaining_Print_Command); + Format_State + .Print_Commands + .Append (White_Break_Command); + Format_State + .Print_Commands + .Append (Content_Flat_Command); else - Print_Commands.Append (Remaining_Print_Command); - Print_Commands.Append (White_Break_Command); - Print_Commands.Append (Content_Break_Command); + Format_State + .Print_Commands + .Append (Remaining_Print_Command); + Format_State + .Print_Commands + .Append (White_Break_Command); + Format_State + .Print_Commands + .Append (Content_Break_Command); end if; end; end if; @@ -1030,44 +1217,41 @@ package body Prettier_Ada.Documents.Implementation is procedure Process_Mode_Break is begin - Gnatfmt_Trace.Trace ("131"); - if not Line_Suffix.Is_Empty then - Gnatfmt_Trace.Trace ("1311"); - Print_Commands.Append + if not Format_State.Line_Suffix.Is_Empty then + Format_State.Print_Commands.Append (Print_Command_Type'(Indentation, Mode, Document)); - Gnatfmt_Trace.Trace - ("1312 Length" & Line_Suffix.Length'Image); - for Suffix of reverse Line_Suffix loop - Print_Commands.Append (Suffix); + for Suffix of reverse Format_State.Line_Suffix loop + Format_State.Print_Commands.Append (Suffix); end loop; - Line_Suffix.Clear; + Format_State.Line_Suffix.Clear; + Format_State.Last_Was_Hardline := False; else - Gnatfmt_Trace.Trace ("1312"); if Document.Bare_Document.Command.Literal then - Gnatfmt_Trace.Trace ("13121"); if Indentation.Root /= null then - Gnatfmt_Trace.Trace ("131211"); - Append (Result, End_Of_Line); - Append (Result, Indentation.Root.Value); - Pos := + Append (Format_State.Result, End_Of_Line); + Append + (Format_State.Result, Indentation.Root.Value); + Format_State.Current_Line_Length := Natural (Indentation.Root.Value.Display_Width); else - Gnatfmt_Trace.Trace ("131212"); - Append (Result, End_Of_Line); - Pos := - Options.Indentation.Offset.Spaces - + Options.Indentation.Offset.Tabs - * Options.Indentation.Width; + Append (Format_State.Result, End_Of_Line); + Format_State.Current_Line_Length := + Format_Options.Indentation.Offset.Spaces + + Format_Options.Indentation.Offset.Tabs + * Format_Options.Indentation.Width; end if; + Format_State.Last_Was_Hardline := False; else - Gnatfmt_Trace.Trace ("13122"); - Pos := @ - Trim (Result); - Append (Result, End_Of_Line); - Append (Result, Indentation.Value); - Pos := Natural (Indentation.Value.Display_Width); + Format_State.Current_Line_Length := + @ - Trim (Format_State.Result); + Append (Format_State.Result, End_Of_Line); + Append (Format_State.Result, Indentation.Value); + Format_State.Current_Line_Length := + Natural (Indentation.Value.Display_Width); + Format_State.Last_Was_Hardline := True; end if; end if; end Process_Mode_Break; @@ -1078,28 +1262,24 @@ package body Prettier_Ada.Documents.Implementation is procedure Process_Mode_Flat is begin - Gnatfmt_Trace.Trace ("132"); if not Document.Bare_Document.Command.Hard then - Gnatfmt_Trace.Trace ("1321"); if not Document .Bare_Document .Command .Soft then - Gnatfmt_Trace.Trace ("13211"); - Append (Result, (" ", 1)); - Pos := @ + Natural (1); + Append (Format_State.Result, (" ", 1)); + Format_State.Current_Line_Length := @ + Natural (1); end if; + Format_State.Last_Was_Hardline := False; else - Gnatfmt_Trace.Trace ("1322"); - Should_Remeasure := True; + Format_State.Should_Remeasure := True; Process_Mode_Break; end if; end Process_Mode_Flat; begin - Gnatfmt_Trace.Trace ("13"); case Mode is when Mode_Flat => Process_Mode_Flat; @@ -1118,12 +1298,9 @@ package body Prettier_Ada.Documents.Implementation is procedure Process_Document_Text is begin - Gnatfmt_Trace.Trace ("1"); - Append - (Result, Document.Bare_Document.Text); - if Print_Commands.Length > 0 then - Pos := @ + Document.Bare_Document.Text.Display_Width; - end if; + Append (Format_State.Result, Document.Bare_Document.Text); + Format_State.Current_Line_Length := + @ + Document.Bare_Document.Text.Display_Width; end Process_Document_Text; --------------------------- @@ -1135,22 +1312,543 @@ package body Prettier_Ada.Documents.Implementation is Document.Bare_Document.List; begin - Gnatfmt_Trace.Trace ("2"); - Gnatfmt_Trace.Trace ("2 Length" & Documents.Length'Image); for Child_Document of reverse Documents loop Ada.Assertions.Assert (Child_Document /= No_Document); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type'(Indentation, Mode, Child_Document)); end loop; end Process_Document_List; + ---------------------------------------------- + -- Process_Document_Command_Alignment_Table -- + ---------------------------------------------- + + procedure Process_Document_Command_Alignment_Table + is + procedure Process_Mode_Break; + -- Processes the Alignment_Table comamnd in Break mode + + procedure Process_Mode_Flat; + -- Processes the Alignment_Table comamnd in Flat mode + + ------------------------ + -- Process_Mode_Break -- + ------------------------ + + procedure Process_Mode_Break is + use VSS.Strings; + + type Format_State_Array is + array (Positive range <>) of Format_State_Record; + + Alignment_Table_Elements : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Elements; + Alignment_Table_Separators : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Separators; + + States : + Format_State_Array + (Alignment_Table_Elements.First_Index + .. Alignment_Table_Elements.Last_Index) := + [others => Format_State]; + -- The state for each row + + First_Row_Index : constant Positive := + Alignment_Table_Elements.First_Index; + Last_Row_Index : constant Positive := + Alignment_Table_Elements.Last_Index; + First_Column_Index : constant Positive := 1; + Last_Column_Index : constant Positive := + [for Row_Elements of Alignment_Table_Elements + => Row_Elements.Last_Index]'Reduce (Positive'Max, 1); + + Max_Line_Length : Natural := 0; + + begin + Prettier_Ada_Trace.Trace + ("On Process_Document_Command_Alignment_Table." + & "Process_Mode_Break"); + + for State of States loop + State.Result := Empty_Prettier_String; + end loop; + + if Format_State.Last_Was_Hardline then + -- If the last document appended to Format_State.Result + -- was a hardline, then we need to move any indentation + -- from Format_State.Result into + -- States (First_Row_Index).Result. Otherwise, if the + -- first document of the first row is a line break, + -- previously added identation is not removed, resulting + -- in trailing whitespaces in the final + -- Format_State.Result. + + Trim (Format_State.Result, Right); + States (First_Row_Index) + .Result + .Text + .Append (Indentation.Value.Text); + end if; + + Prettier_Ada_Trace.Trace + ("On Column_Index " & First_Column_Index'Image); + + for Row_Index in First_Row_Index .. Last_Row_Index loop + Prettier_Ada_Trace.Trace + ("On Row_Index " & Row_Index'Image); + declare + Separator_Display_Width : + constant Display_Cell_Count := + (if not Alignment_Table_Separators + .Reference (Row_Index) + .Is_Empty + then + Alignment_Table_Separators + .Reference (Row_Index) + .Reference (First_Column_Index) + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Display_Width + else 0); + Next_Options : + constant Format_Options_Type := + Format_Options_Type' + (Width => + (if Natural (Separator_Display_Width) + > Format_Options.Width + then 0 + else + Format_Options.Width + - Natural (Separator_Display_Width)), + Indentation => Format_Options.Indentation, + End_Of_Line => Format_Options.End_Of_Line); + -- The formatting options for each element need + -- to have an offset on the maximum width to account + -- the separator's width. + + begin + States (Row_Index).Should_Remeasure := False; + States (Row_Index).Print_Commands := + [Print_Command_Type' + (Indentation, + Mode_Break, + Alignment_Table_Elements + .Reference (Row_Index) + .Reference (First_Column_Index))]; + + Format (States (Row_Index), Next_Options); + + Prettier_Ada_Trace.Trace + ("States.State.Current_Line_Length" + & States (Row_Index).Current_Line_Length'Image); + + -- Compute the Max_Line_Length seen so far. If there's + -- not separators on this row, then this row line + -- length should not affect the alignment of others. + + if not Alignment_Table_Separators (Row_Index).Is_Empty + then + Max_Line_Length := + Natural'Max + (@, States (Row_Index).Current_Line_Length); + end if; + end; + end loop; + + Prettier_Ada_Trace.Trace + ("Max_Line_Length" & Max_Line_Length'Image); + + for Column_Index + in Standard."+" (First_Column_Index, 1) + .. Last_Column_Index + loop + Prettier_Ada_Trace.Trace + ("On Column_Index " & Column_Index'Image); + + -- Add padding to the buffers + + Prettier_Ada_Trace.Trace + ("Adding padding to the buffers"); + + for Row_Index in First_Row_Index .. Last_Row_Index loop + Prettier_Ada_Trace.Trace + ("On Row_Index " & Row_Index'Image); + + if Column_Index + <= Alignment_Table_Elements + .Element (Row_Index) + .Last_Index + then + declare + Padding : constant Character_Count := + Character_Count + (Max_Line_Length + - States (Row_Index).Current_Line_Length); + + begin + Prettier_Ada_Trace.Trace + ("Padding " & Padding'Image); + + if Padding /= 0 then + States (Row_Index) + .Result + .Text + .Append (Padding * ' '); + States (Row_Index).Current_Line_Length := + Max_Line_Length; + end if; + end; + end if; + + end loop; + + Prettier_Ada_Trace.Trace + ("Adding separators to the buffers"); + + -- Add separators to the buffers + + for Row_Index in First_Row_Index .. Last_Row_Index loop + Prettier_Ada_Trace.Trace + ("On Row_Index " & Row_Index'Image); + + if Standard."-" (Column_Index, 1) + <= Alignment_Table_Separators + .Element (Row_Index) + .Last_Index + then + declare + Separator : constant Document_Type := + Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Constant_Reference + (Standard."-" (Column_Index, 1)); + + Separator_Display_Width : constant Natural := + Natural + (Separator + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Display_Width); + + Row_Line_Length_After_Separator : + constant Natural := + Max_Line_Length + Separator_Display_Width; + + begin + Prettier_Ada_Trace.Trace + ("Row_Line_Length_After_Separator " + & Row_Line_Length_After_Separator'Image); + + States (Row_Index) + .Result + .Text + .Append + (Separator + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Text); + States (Row_Index).Current_Line_Length := + Row_Line_Length_After_Separator; + end; + end if; + end loop; + + -- Format current element and add it to the buffers + + Prettier_Ada_Trace.Trace + ("Format current element and add it to the buffers"); + + Max_Line_Length := 0; + + for Row_Index in First_Row_Index .. Last_Row_Index loop + Prettier_Ada_Trace.Trace + ("On Row_Index " & Row_Index'Image); + + if Column_Index + <= Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Last_Index + then + declare + Separator_Display_Width : + constant Display_Cell_Count := + (if Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Last_Index + >= Column_Index + then + Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Constant_Reference (Column_Index) + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Display_Width + else 0); + Next_Options : + constant Format_Options_Type := + Format_Options_Type' + (Width => + (if Natural (Separator_Display_Width) + > Format_Options.Width + then + 0 + else + Format_Options.Width + - Natural + (Separator_Display_Width)), + Indentation => + Format_Options.Indentation, + End_Of_Line => + Format_Options.End_Of_Line); + + begin + States (Row_Index).Should_Remeasure := False; + States (Row_Index).Print_Commands := + [Print_Command_Type' + (Indentation, + Mode_Break, + Alignment_Table_Elements + .Reference (Row_Index) + .Reference (Column_Index))]; + + Format (States (Row_Index), Next_Options); + + Prettier_Ada_Trace.Trace + ("States.State.Current_Line_Length" + & States (Row_Index) + .Current_Line_Length'Image); + + if not (Alignment_Table_Separators (Row_Index) + .Last_Index + < Column_Index) + then + Max_Line_Length := + Natural'Max + (@, + States (Row_Index).Current_Line_Length); + end if; + end; + end if; + end loop; + end loop; + + -- Finally, concatenate all buffers and add them to Result + + Format_State.Result + .Text + .Append (States (First_Row_Index).Result.Text); + for Row_Index + in Standard."+" (First_Row_Index, 1) .. Last_Row_Index + loop + Format_State.Result.Text.Append (End_Of_Line.Text); + Format_State.Result.Text.Append (Indentation.Value.Text); + Format_State.Result.Text.Append + (States (Row_Index).Result.Text); + end loop; + + -- Also update the Format_State.Current_Line_Length based on + -- the last table row. + + Format_State.Current_Line_Length := + States (Last_Row_Index).Current_Line_Length; + + end Process_Mode_Break; + + ----------------------- + -- Process_Mode_Flat -- + ----------------------- + + procedure Process_Mode_Flat is + Remaining_Line_Length : constant Integer := + Format_Options.Width - Format_State.Current_Line_Length; + Has_Line_Suffix : constant Boolean := + Format_State.Line_Suffix.Length > 0; + + begin + Prettier_Ada_Trace.Trace + ("On Process_Document_Command_Alignment_Table." + & "Process_Mode_Flat"); + + Prettier_Ada_Trace.Trace ("Checking if table fits"); + Prettier_Ada_Trace.Trace + ("Remaining_Line_Length: " & Remaining_Line_Length'Image); + + if not Fits + (Print_Command, + [], + Remaining_Line_Length, + Has_Line_Suffix, + Format_State.Group_Mode_Map) + then + Prettier_Ada_Trace.Trace ("Table does not fit"); + Process_Mode_Break; + + return; + end if; + + Prettier_Ada_Trace.Trace ("Table fits"); + + declare + Alignment_Table_Elements : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Elements; + Alignment_Table_Separators : Document_Table + renames Document + .Bare_Document + .Command + .Alignment_Table_Separators; + + First_Row_Index : constant Positive := + Alignment_Table_Elements.First_Index; + Last_Row_Index : constant Positive := + Alignment_Table_Elements.Last_Index; + First_Column_Index : constant Positive := 1; + Last_Column_Index : constant Positive := + [for Row_Elements of Alignment_Table_Elements + => Row_Elements.Last_Index]'Reduce (Positive'Max, 1); + + begin + -- Add the last row + + for Column_Index + in reverse First_Column_Index .. Last_Column_Index + loop + if Alignment_Table_Separators + .Constant_Reference (Last_Row_Index) + .Last_Index + >= Column_Index + then + Format_State.Print_Commands.Append + (Print_Command_Type' + (Indentation, + Mode_Flat, + Alignment_Table_Separators + .Constant_Reference (Last_Row_Index) + .Constant_Reference (Column_Index))); + end if; + + if Alignment_Table_Elements + .Constant_Reference (Last_Row_Index) + .Last_Index + >= Column_Index + then + Format_State.Print_Commands.Append + (Print_Command_Type' + (Indentation, + Mode_Flat, + Alignment_Table_Elements + .Constant_Reference (Last_Row_Index) + .Constant_Reference (Column_Index))); + end if; + end loop; + + -- Add the remaining rows (in reverse order) with a Line + -- in between. + + for Row_Index + in reverse First_Row_Index + .. Standard."-" (Last_Row_Index, 1) + loop + Format_State.Print_Commands.Append + (Print_Command_Type' + (Indentation, + Mode_Flat, + Prettier_Ada + .Documents + .Builders + .Line)); + + for Column_Index + in reverse First_Column_Index .. Last_Column_Index + loop + if Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Last_Index + >= Column_Index + then + Format_State.Print_Commands.Append + (Print_Command_Type' + (Indentation, + Mode_Flat, + Alignment_Table_Separators + .Constant_Reference (Row_Index) + .Constant_Reference (Column_Index))); + end if; + + if Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Last_Index + >= Column_Index + then + Format_State.Print_Commands.Append + (Print_Command_Type' + (Indentation, + Mode_Flat, + Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Constant_Reference (Column_Index))); + end if; + end loop; + end loop; + end; + end Process_Mode_Flat; + + begin + Prettier_Ada_Trace.Trace + ("On Process_Document_Command_Alignment_Table"); + + if Document.Bare_Document.Command.Alignment_Table_Must_Break + or Mode in Mode_Break + then + Prettier_Ada_Trace.Trace ("Table must break"); + Process_Mode_Break; + + else + Process_Mode_Flat; + end if; + end Process_Document_Command_Alignment_Table; + + -------------------------------------------------- + -- Process_Document_Command_Alignment_Separator -- + -------------------------------------------------- + + procedure Process_Document_Command_Alignment_Table_Separator + is + begin + Append + (Format_State.Result, + Document + .Bare_Document + .Command + .Alignment_Table_Separator_Text); + Format_State.Current_Line_Length := + @ + + Document + .Bare_Document + .Command + .Alignment_Table_Separator_Text + .Display_Width; + end Process_Document_Command_Alignment_Table_Separator; + begin - -- Ada.Text_IO.New_Line; - Print_Commands.Delete_Last; + Format_State.Print_Commands.Delete_Last; case Document.Bare_Document.Kind is when Document_Text => Process_Document_Text; + Format_State.Last_Was_Hardline := False; when Document_List => Process_Document_List; @@ -1158,8 +1856,7 @@ package body Prettier_Ada.Documents.Implementation is when Document_Command => case Document.Bare_Document.Command.Kind is when Command_Cursor => - Gnatfmt_Trace.Trace ("3"); - if Printed_Cursor_Count >= 2 then + if Format_State.Printed_Cursor_Count >= 2 then -- TODO: Replace this by a GNATfmt defined -- exception raise Program_Error; @@ -1167,49 +1864,45 @@ package body Prettier_Ada.Documents.Implementation is -- TODO: How to add this command to Result? -- Should Result be instead a Document_Type_Vector -- with only Document_Text and Command_Cursor? - Printed_Cursor_Count := @ + Natural (1); + Format_State.Printed_Cursor_Count := @ + Natural (1); when Command_Indent => - Gnatfmt_Trace.Trace ("4"); Ada.Assertions.Assert (Document.Bare_Document.Command.Indent_Contents /= No_Document); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Make_Indentation - (Indentation, Options.Indentation), + (Indentation, Format_Options.Indentation), Mode, Document.Bare_Document.Command.Indent_Contents)); when Command_Align => - Gnatfmt_Trace.Trace ("5"); Ada.Assertions.Assert (Document.Bare_Document.Command.Align_Contents /= No_Document); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Make_Align (Indentation, Document.Bare_Document.Command.Align_Data, - Options, - Pos), + Format_Options, + Format_State.Current_Line_Length), Mode, Document.Bare_Document.Command.Align_Contents)); when Command_Trim => - Gnatfmt_Trace.Trace ("6"); - Pos := @ - Trim (Result); + Format_State.Current_Line_Length := + @ - Trim (Format_State.Result); + Format_State.Last_Was_Hardline := False; when Command_Group => - Gnatfmt_Trace.Trace ("7"); Process_Document_Command_Group; when Command_Fill => - Gnatfmt_Trace.Trace ("8"); Process_Document_Command_Fill; when Command_If_Break => - Gnatfmt_Trace.Trace ("9"); declare Group_Mode : constant Mode_Kind := (if Document @@ -1218,13 +1911,13 @@ package body Prettier_Ada.Documents.Implementation is .If_Break_Group_Id /= No_Symbol then - (if Group_Mode_Map.Contains + (if Format_State.Group_Mode_Map.Contains (Document .Bare_Document .Command .If_Break_Group_Id) then - Group_Mode_Map.Element + Format_State.Group_Mode_Map.Element (Document .Bare_Document .Command @@ -1245,7 +1938,6 @@ package body Prettier_Ada.Documents.Implementation is .Break_Contents; begin - Gnatfmt_Trace.Trace ("91"); if Break_Contents /= No_Document and then not (Break_Contents.Bare_Document.Kind @@ -1256,8 +1948,7 @@ package body Prettier_Ada.Documents.Implementation is .Text .Is_Empty) then - Gnatfmt_Trace.Trace ("911"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, @@ -1274,7 +1965,6 @@ package body Prettier_Ada.Documents.Implementation is .Flat_Contents; begin - Gnatfmt_Trace.Trace ("92"); if Flat_Contents /= No_Document and then not (Flat_Contents.Bare_Document.Kind @@ -1286,8 +1976,7 @@ package body Prettier_Ada.Documents.Implementation is .Is_Empty) then - Gnatfmt_Trace.Trace ("921"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, @@ -1301,7 +1990,6 @@ package body Prettier_Ada.Documents.Implementation is end; when Command_Indent_If_Break => - Gnatfmt_Trace.Trace ("10"); declare Group_Mode : constant Mode_Kind := (if Document @@ -1309,13 +1997,13 @@ package body Prettier_Ada.Documents.Implementation is .Command .Indent_If_Break_Group_Id /= No_Symbol - and then Group_Mode_Map.Contains + and then Format_State.Group_Mode_Map.Contains (Document .Bare_Document .Command .Indent_If_Break_Group_Id) then - Group_Mode_Map.Element + Format_State.Group_Mode_Map.Element (Document .Bare_Document .Command @@ -1344,9 +2032,7 @@ package body Prettier_Ada.Documents.Implementation is .Indent_If_Break_Contents)); begin - Gnatfmt_Trace.Trace ("101"); - Gnatfmt_Trace.Trace ("1011"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, @@ -1369,9 +2055,7 @@ package body Prettier_Ada.Documents.Implementation is .Indent_If_Break_Contents); begin - Gnatfmt_Trace.Trace ("102"); - Gnatfmt_Trace.Trace ("1021"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, @@ -1384,8 +2068,7 @@ package body Prettier_Ada.Documents.Implementation is end; when Command_Line_Suffix => - Gnatfmt_Trace.Trace ("11"); - Line_Suffix.Append + Format_State.Line_Suffix.Append (Print_Command_Type' (Indentation, Mode, @@ -1395,10 +2078,8 @@ package body Prettier_Ada.Documents.Implementation is .Line_Suffix_Contents)); when Command_Line_Suffix_Boundary => - Gnatfmt_Trace.Trace ("12"); - if not Line_Suffix.Is_Empty then - Gnatfmt_Trace.Trace ("121"); - Print_Commands.Append + if not Format_State.Line_Suffix.Is_Empty then + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, @@ -1412,36 +2093,40 @@ package body Prettier_Ada.Documents.Implementation is Process_Document_Command_Line; when Command_Label => - Gnatfmt_Trace.Trace ("14"); - Print_Commands.Append + Format_State.Print_Commands.Append (Print_Command_Type' (Indentation, Mode, Document.Bare_Document.Command.Label_Contents)); when Command_Break_Parent => - Gnatfmt_Trace.Trace ("15"); null; + + when Command_Alignment_Table => + Process_Document_Command_Alignment_Table; + + when Command_Alignment_Table_Separator => + Process_Document_Command_Alignment_Table_Separator; end case; end case; - if Print_Commands.Length = 0 and Line_Suffix.Length > 0 then - for Suffix of reverse Line_Suffix loop - Print_Commands.Append (Suffix); + if Format_State.Print_Commands.Length = 0 + and Format_State.Line_Suffix.Length > 0 + then + for Suffix of reverse Format_State.Line_Suffix loop + Format_State.Print_Commands.Append (Suffix); end loop; - Line_Suffix.Clear; + Format_State.Line_Suffix.Clear; end if; end; end loop; Prettier_Ada.Documents.Builders.Reset_Document_Id; - return VSS.Strings.Conversions.To_Unbounded_UTF_8_String (Result.Text); - exception when others => Prettier_Ada.Documents.Builders.Reset_Document_Id; - return Ada.Strings.Unbounded.Null_Unbounded_String; + raise; end Format; ---------- @@ -1760,8 +2445,6 @@ package body Prettier_Ada.Documents.Implementation is is begin - Gnatfmt_Trace.Trace ("PonEnter"); - Gnatfmt_Trace.Trace (Already_Visited.Length'Image); if Document = No_Document then return Optional_Boolean'(Is_Set => False); end if; @@ -1770,19 +2453,15 @@ package body Prettier_Ada.Documents.Implementation is when Document_Command => case Document.Bare_Document.Command.Kind is when Command_Break_Parent => - Gnatfmt_Trace.Trace ("PonEnter2"); Break_Parent_Group (Group_Stack); when Command_Group => - Gnatfmt_Trace.Trace ("PonEnter3"); Group_Stack.Append (Document); if Already_Visited.Contains (Document) then - Gnatfmt_Trace.Trace ("PonEnter4"); return Optional_Boolean' (Is_Set => True, Value => False); end if; - Gnatfmt_Trace.Trace ("PInsert"); Already_Visited.Insert (Document); when others => @@ -1805,7 +2484,6 @@ package body Prettier_Ada.Documents.Implementation is return Optional_Boolean is begin - Gnatfmt_Trace.Trace ("PonExit"); if Document = No_Document then return Optional_Boolean'(Is_Set => False); end if; @@ -1813,7 +2491,6 @@ package body Prettier_Ada.Documents.Implementation is case Document.Bare_Document.Kind is when Document_Command => if Document.Bare_Document.Command.Kind in Command_Group then - Gnatfmt_Trace.Trace ("PonExit1"); declare Group : constant Document_Type := Group_Stack.Last_Element; @@ -1821,7 +2498,6 @@ package body Prettier_Ada.Documents.Implementation is begin Group_Stack.Delete_Last; if Group.Bare_Document.Command.Break then - Gnatfmt_Trace.Trace ("PonExit2"); Break_Parent_Group (Group_Stack); end if; end; @@ -1984,7 +2660,6 @@ package body Prettier_Ada.Documents.Implementation is begin while Doc_Stack.Length > 0 loop - Gnatfmt_Trace.Trace ("TLen" & Doc_Stack.Length'Image); declare Doc : constant Document_Type := Doc_Stack.Last_Element; @@ -1992,7 +2667,6 @@ package body Prettier_Ada.Documents.Implementation is Doc_Stack.Delete_Last; if Doc = Traverse_Doc_On_Exit_Stack_Marker then - Gnatfmt_Trace.Trace ("T1"); declare Doc : constant Document_Type := Doc_Stack.Last_Element; Ignore : constant Optional_Boolean := On_Exit (Doc); @@ -2005,7 +2679,6 @@ package body Prettier_Ada.Documents.Implementation is end if; if On_Exit /= null then - Gnatfmt_Trace.Trace ("T2"); Doc_Stack.Append (Doc); Doc_Stack.Append (Traverse_Doc_On_Exit_Stack_Marker); end if; @@ -2019,7 +2692,6 @@ package body Prettier_Ada.Documents.Implementation is if On_Enter_Result.Is_Set and then not On_Enter_Result.Value then - Gnatfmt_Trace.Trace ("T4"); goto Continue; end if; end; @@ -2027,11 +2699,9 @@ package body Prettier_Ada.Documents.Implementation is case Doc.Bare_Document.Kind is when Document_Text => - Gnatfmt_Trace.Trace ("T10"); null; when Document_List => - Gnatfmt_Trace.Trace ("T5"); declare Documents : constant Document_Vector := Doc.Bare_Document.List; @@ -2046,7 +2716,6 @@ package body Prettier_Ada.Documents.Implementation is when Document_Command => case Doc.Bare_Document.Command.Kind is when Command_Align => - Gnatfmt_Trace.Trace ("T9"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Align_Contents /= No_Document); @@ -2054,7 +2723,6 @@ package body Prettier_Ada.Documents.Implementation is (Doc.Bare_Document.Command.Align_Contents); when Command_Indent => - Gnatfmt_Trace.Trace ("T9"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Indent_Contents /= No_Document); @@ -2062,7 +2730,6 @@ package body Prettier_Ada.Documents.Implementation is (Doc.Bare_Document.Command.Indent_Contents); when Command_Indent_If_Break => - Gnatfmt_Trace.Trace ("T9"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Indent_If_Break_Contents /= No_Document); @@ -2073,7 +2740,6 @@ package body Prettier_Ada.Documents.Implementation is .Indent_If_Break_Contents); when Command_Label => - Gnatfmt_Trace.Trace ("T9"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Label_Contents /= No_Document); @@ -2081,7 +2747,6 @@ package body Prettier_Ada.Documents.Implementation is (Doc.Bare_Document.Command.Label_Contents); when Command_Line_Suffix => - Gnatfmt_Trace.Trace ("T9"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Line_Suffix_Contents /= No_Document); @@ -2089,7 +2754,6 @@ package body Prettier_Ada.Documents.Implementation is (Doc.Bare_Document.Command.Line_Suffix_Contents); when Command_Fill => - Gnatfmt_Trace.Trace ("T5"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Parts.Bare_Document /= null @@ -2114,7 +2778,6 @@ package body Prettier_Ada.Documents.Implementation is end; when Command_Group => - Gnatfmt_Trace.Trace ("T8"); if Should_Traverse_Conditional_Groups and Doc .Bare_Document @@ -2122,7 +2785,6 @@ package body Prettier_Ada.Documents.Implementation is .Expanded_States /= No_Document then - Gnatfmt_Trace.Trace ("T11"); Ada.Assertions.Assert (Doc .Bare_Document @@ -2142,14 +2804,12 @@ package body Prettier_Ada.Documents.Implementation is begin for State of reverse Expanded_States loop - Gnatfmt_Trace.Trace ("T13"); Ada.Assertions.Assert (State /= No_Document); Doc_Stack.Append (State); end loop; end; else - Gnatfmt_Trace.Trace ("T14"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Group_Contents /= No_Document); @@ -2158,7 +2818,6 @@ package body Prettier_Ada.Documents.Implementation is end if; when Command_If_Break => - Gnatfmt_Trace.Trace ("T7"); Ada.Assertions.Assert (Doc.Bare_Document.Command.Flat_Contents /= No_Document); @@ -2175,9 +2834,77 @@ package body Prettier_Ada.Documents.Implementation is | Command_Line | Command_Line_Suffix_Boundary | Command_Trim => - Gnatfmt_Trace.Trace ("T10"); null; + when Command_Alignment_Table => + for Row_Index + in Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .First_Index + .. Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .Last_Index + loop + declare + First_Column_Index : constant Positive := + Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Last_Index; + Last_Column_Index : constant Positive := + Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .Constant_Reference (Row_Index) + .Last_Index; + + begin + Doc_Stack.Append + (Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .Constant_Reference + (Row_Index) + .Constant_Reference + (Last_Column_Index)); + + for Column_Index + in reverse First_Column_Index + .. Standard."-" + (Last_Column_Index, 1) + loop + Doc_Stack.Append + (Doc + .Bare_Document + .Command + .Alignment_Table_Separators + .Constant_Reference + (Row_Index) + .Constant_Reference + (Column_Index)); + Doc_Stack.Append + (Doc + .Bare_Document + .Command + .Alignment_Table_Elements + .Constant_Reference + (Row_Index) + .Constant_Reference + (Column_Index)); + end loop; + end; + end loop; + + when Command_Alignment_Table_Separator => + null; end case; end case; diff --git a/src/prettier_ada-documents-implementation.ads b/src/prettier_ada-documents-implementation.ads index a2a6549..bc4e257 100644 --- a/src/prettier_ada-documents-implementation.ads +++ b/src/prettier_ada-documents-implementation.ads @@ -7,6 +7,7 @@ with Ada.Containers; with Ada.Strings.Unbounded; with Prettier_Ada.Document_Vectors; +with Prettier_Ada.Document_Vector_Vectors; with VSS.Strings; @@ -69,6 +70,10 @@ private package Prettier_Ada.Documents.Implementation is (Text : Ada.Strings.Unbounded.Unbounded_String) return Prettier_String; -- Converts an Unbounded_String into a Prettier_String + subtype Document_Vector is Prettier_Ada.Document_Vectors.Vector; + + subtype Document_Table is Prettier_Ada.Document_Vector_Vectors.Vector; + type Command_Kind is (Command_Align, Command_Break_Parent, @@ -82,7 +87,9 @@ private package Prettier_Ada.Documents.Implementation is Command_Line, Command_Line_Suffix, Command_Line_Suffix_Boundary, - Command_Trim); + Command_Trim, + Command_Alignment_Table, + Command_Alignment_Table_Separator); type Command_Type (Kind : Command_Kind) is record case Kind is @@ -135,6 +142,14 @@ private package Prettier_Ada.Documents.Implementation is when Command_Trim => null; + + when Command_Alignment_Table => + Alignment_Table_Elements : Document_Table; + Alignment_Table_Separators : Document_Table; + Alignment_Table_Must_Break : Boolean; + + when Command_Alignment_Table_Separator => + Alignment_Table_Separator_Text : Prettier_String; end case; end record; diff --git a/src/prettier_ada-documents-json.adb b/src/prettier_ada-documents-json.adb index 7be5edb..a65c978 100644 --- a/src/prettier_ada-documents-json.adb +++ b/src/prettier_ada-documents-json.adb @@ -3,6 +3,7 @@ -- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -- +with Ada.Assertions; with Ada.Containers; with Ada.Containers.Hashed_Maps; @@ -14,9 +15,32 @@ with GNATCOLL.JSON; with Prettier_Ada.Documents.Implementation; use Prettier_Ada.Documents.Implementation; with Prettier_Ada.Document_Vectors; +with Prettier_Ada.Document_Vector_Vectors; package body Prettier_Ada.Documents.Json is subtype Document_Vector is Prettier_Ada.Document_Vectors.Vector; + subtype Document_Table is Prettier_Ada.Document_Vector_Vectors.Vector; + + function Assert_Equal (Actual, Expected : Command_Kind) return Boolean; + -- Returns True is Actual = Expected, else raises an Assertion_Error. + + ------------------- + -- Assert_Equal -- + ------------------- + + function Assert_Equal (Actual, Expected : Command_Kind) return Boolean + is + begin + Ada.Assertions.Assert + (Actual = Expected, + "Unexpected Command_Type. Actual: """ + & Actual'Image + & """. Expected: """ + & Expected'Image + & """."); + + return True; + end Assert_Equal; function Wrap_Command (Command : Command_Access; Id : Natural) return Document_Type @@ -44,6 +68,9 @@ package body Prettier_Ada.Documents.Json is function From_Document_List (List : Document_Vector) return JSON_Value; -- Serialize a document list + function From_Document_Table (Table : Document_Table) return JSON_Value; + -- Serialize a document table + function From_Command (Command : Command_Type) return JSON_Value; -- Serialize a command @@ -92,6 +119,20 @@ package body Prettier_Ada.Documents.Json is return Create (Elements); end From_Document_List; + ------------------------- + -- From_Document_Table -- + ------------------------- + + function From_Document_Table (Table : Document_Table) return JSON_Value + is + Elements : JSON_Array; + begin + for Row of Table loop + Append (Elements, From_Document_List (Row)); + end loop; + return Create (Elements); + end From_Document_Table; + ------------------ -- From_Command -- ------------------ @@ -215,6 +256,24 @@ package body Prettier_Ada.Documents.Json is when Command_Trim => Result.Set_Field ("command", "trim"); + + when Command_Alignment_Table => + Result.Set_Field ("kind", "alignmentTable"); + Result.Set_Field + ("elements", + From_Document_Table (Command.Alignment_Table_Elements)); + Result.Set_Field + ("separators", + From_Document_Table (Command.Alignment_Table_Separators)); + Result.Set_Field + ("mustBreak", Command.Alignment_Table_Must_Break); + + when Command_Alignment_Table_Separator => + Result.Set_Field ("kind", "alignmentTableSeparator"); + Result.Set_Field + ("text", + VSS.Strings.Conversions.To_UTF_8_String + (Command.Alignment_Table_Separator_Text.Text)); end case; return Result; @@ -368,6 +427,22 @@ package body Prettier_Ada.Documents.Json is -- TODO: Add description -- TODO: Add Pre and Post contracts + function To_Command_Alignment_Table + (Json : GNATCOLL.JSON.JSON_Value) + return Command_Type + with Post => Assert_Equal + (To_Command_Alignment_Table'Result.Kind, + Command_Alignment_Table); + -- Decodes Json as a Alignment_Table command + + function To_Command_Alignment_Table_Separator + (Json : GNATCOLL.JSON.JSON_Value) + return Command_Type + with Post => Assert_Equal + (To_Command_Alignment_Table_Separator'Result.Kind, + Command_Alignment_Table_Separator); + -- Decodes Json as a Alignment_Table_Separator command + ---------------------- -- To_Document_Text -- ---------------------- @@ -494,6 +569,18 @@ package body Prettier_Ada.Documents.Json is return Wrap_Command (new Command_Type'(To_Command_Trim (Json)), Id); + elsif Command_Text = "alignmentTable" then + return + Wrap_Command + (new Command_Type'(To_Command_Alignment_Table (Json)), Id); + + elsif Command_Text = "alignmentTableSeparator" then + return + Wrap_Command + (new Command_Type' + (To_Command_Alignment_Table_Separator (Json)), + Id); + else -- TODO: Raise a better exception raise Program_Error; @@ -779,6 +866,87 @@ package body Prettier_Ada.Documents.Json is return (Kind => Command_Trim); end To_Command_Trim; + -------------------------------- + -- To_Command_Alignment_Table -- + -------------------------------- + + function To_Command_Alignment_Table + (Json : GNATCOLL.JSON.JSON_Value) + return Command_Type + is + function To_Document_Table + (Json_Table : GNATCOLL.JSON.JSON_Value) + return Document_Table; + -- TODO: Add description + -- TODO: Add Pre and Post contracts + + ----------------------- + -- To_Document_Table -- + ----------------------- + + function To_Document_Table + (Json_Table : GNATCOLL.JSON.JSON_Value) + return Document_Table + is + Table : Document_Table; + + Rows : constant JSON_Array := Get (Json_Table); + Total_Rows : constant Natural := GNATCOLL.JSON.Length (Rows); + + begin + for Row_Index in 1 .. Total_Rows loop + declare + Current_Row : constant JSON_Array := + Get (Get (Rows, Row_Index)); + Total_Columns : constant Natural := + GNATCOLL.JSON.Length (Current_Row); + + Row : Document_Vector; + + begin + for Column_Index in 1 .. Total_Columns loop + Row.Append + (To_Document_Type (Get (Current_Row, Column_Index))); + end loop; + + Table.Append (Row); + end; + end loop; + + return Table; + end To_Document_Table; + + begin + return + Command_Type' + (Kind => Command_Alignment_Table, + Alignment_Table_Elements => + To_Document_Table (Get (Json, "elements")), + Alignment_Table_Separators => + To_Document_Table (Get (Json, "separators")), + Alignment_Table_Must_Break => Get (Json, "mustBreak")); + end To_Command_Alignment_Table; + + -------------------------------- + -- To_Command_Alignment_Table -- + -------------------------------- + + function To_Command_Alignment_Table_Separator + (Json : GNATCOLL.JSON.JSON_Value) + return Command_Type + is + Text : constant VSS.Strings.Virtual_String := + VSS.Strings.Conversions.To_Virtual_String + (UTF8_String'(Get (Json, "text"))); + Display_Width : constant VSS.Strings.Display_Cell_Count := + VSS.Strings.Utilities.Display_Width (Text); + begin + return + Command_Type' + (Kind => Command_Alignment_Table_Separator, + Alignment_Table_Separator_Text => (Text, Display_Width)); + end To_Command_Alignment_Table_Separator; + begin case Kind (Json) is when JSON_Boolean_Type diff --git a/src/prettier_ada.ads b/src/prettier_ada.ads index 8144662..5a87b2e 100644 --- a/src/prettier_ada.ads +++ b/src/prettier_ada.ads @@ -1,5 +1,5 @@ -- --- Copyright (C) 2023, AdaCore +-- Copyright (C) 2023-2024, AdaCore -- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -- @@ -9,7 +9,7 @@ with GNATCOLL.Traces; package Prettier_Ada is - Gnatfmt_Trace : GNATCOLL.Traces.Trace_Handle := + Prettier_Ada_Trace : GNATCOLL.Traces.Trace_Handle := GNATCOLL.Traces.Create ("PRETTIER_ADA", GNATCOLL.Traces.Off); Version : constant String := "debug"; diff --git a/testsuite/test_programs/src/builders_tester.adb b/testsuite/test_programs/src/builders_tester.adb index 610c469..4b925f6 100644 --- a/testsuite/test_programs/src/builders_tester.adb +++ b/testsuite/test_programs/src/builders_tester.adb @@ -22,6 +22,13 @@ procedure Builders_Tester is procedure Test_Align; -- Builds a Document_Type using the Align builder + procedure Test_Alignment_Table; + -- Builds multiple Document_Type objects using the Alignment_Table builder + + procedure Test_Alignment_Table_Separator; + -- Builds multiple Document_Type objects using the + -- Alignment_Table_Separator builder + procedure Test_Break_Parent; -- Builds a Document_Type using the Break_Parent builder @@ -134,6 +141,136 @@ procedure Builders_Tester is New_Line; end Test_Align; + -------------------------- + -- Test_Alignment_Table -- + -------------------------- + + procedure Test_Alignment_Table + is + function "+" (Source : String) return Document_Type + is (Alignment_Table_Separator (To_Unbounded_String (Source))); + -- Converts Source into a Table_Separator command + + function Build_Table return Document_Type; + -- Creates a compex testing table + + ------------------ + -- Build_Table -- + ------------------ + + function Build_Table return Document_Type + is + Group_1 : constant Symbol_Type := New_Symbol; + Group_2 : constant Symbol_Type := New_Symbol; + Group_3 : constant Symbol_Type := New_Symbol; + Group_4 : constant Symbol_Type := New_Symbol; + + Table : constant Document_Type := + Alignment_Table + ([[Hard_Line_Without_Break_Parent, + -- This line break tests that trailing spaces before a table + -- are removed + "A ", + +":", + Group (Indent (List ([Line, "B "])), Group_1), + +":=", + If_Break + (Indent (Indent (Group ([Line, "C", ";"]))), + Indent (Group ([Line, "C", ";"])), + (Group_Id => Group_1))], + ["AA ", + +":", + Group (Indent (List ([Line, "BB "])), Group_2), + +":=", + If_Break + (Indent (Indent (Group ([Line, "CC", ";"]))), + Indent (Group ([Line, "CC", ";"])), + (Group_Id => Group_2))], + ["AAA ", + +":", + Group (Indent (List ([Line, "BBBBBBBBB;"])), Group_3)], + -- BBBBBBBBB tests that it does not affect other separators + ["AAAA ", + +":", + Group (Indent (List ([Line, "BBBB "])), Group_4), + +":=", + If_Break + (Indent (Indent (Group ([Line, "CCCC", ";"]))), + Indent (Group ([Line, "CCCC", ";"])), + (Group_Id => Group_4))]]); + + Table_Wrapper : constant Document_Type := + Group + (["record", + Indent + (List + ([Hard_Line_Without_Break_Parent, + Table])), + Hard_Line_Without_Break_Parent, + "end record"]); + + begin + return Table_Wrapper; + end Build_Table; + + Alignment_Table_1 : constant Document_Type := Build_Table; + Alignment_Table_2 : constant Document_Type := Build_Table; + + begin + Put_Line ("=== Alignment_Table ==="); + + -- Test table alignment without line breaks + + Put_Line ("> Alignment_Table_1 Document JSON:"); + Put_Line (Serialize (Alignment_Table_1)); + Put_Line ("> Alignment_Table_1 Document Formatted:"); + Put_Line (Format (Alignment_Table_1)); + + -- Test table alignment with all line breaks + + Put_Line ("> Alignment_Table_2 Document JSON:"); + Put_Line (Serialize (Alignment_Table_2)); + Put_Line ("> Alignment_Table_2 Document Formatted:"); + Put_Line + (Format + (Alignment_Table_2, + (Width => 1, + Indentation => + (Kind => Spaces, + Width => 2, + Offset => (Spaces => 0, Tabs => 0)), + End_Of_Line => LF))); + New_Line; + end Test_Alignment_Table; + + ------------------------------------ + -- Test_Alignment_Table_Separator -- + ------------------------------------ + + procedure Test_Alignment_Table_Separator + is + Document : constant Document_Type := + List + (["A", + " ", + Alignment_Table_Separator (To_Unbounded_String (":")), + " ", + "B", + " ", + Alignment_Table_Separator (To_Unbounded_String (":=")), + " ", + "C", + ";"]); + + begin + Put_Line ("=== Alignment_Table_Separator ==="); + Put_Line ("> Alignment_Table_Separator Document JSON:"); + Put_Line (Serialize (Document)); + Put_Line ("> Alignment_Table_Separator Document Formatted:"); + Put_Line (Format (Document)); + New_Line; + end Test_Alignment_Table_Separator; + ------------------------ -- Test_Break_Parent -- ------------------------ @@ -594,6 +731,8 @@ begin -- Run all the test procedures Test_Align; + Test_Alignment_Table; + Test_Alignment_Table_Separator; Test_Break_Parent; Test_Cursor; Test_Fill; diff --git a/testsuite/tests/builders/test.out b/testsuite/tests/builders/test.out index 344113a..9c5e0c7 100644 --- a/testsuite/tests/builders/test.out +++ b/testsuite/tests/builders/test.out @@ -202,6 +202,1388 @@ begin AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(BBBBBBBBBBBBBBBBBBBB, CCCCCCCCCCCCCCCCCCCC) +=== Alignment_Table === +> Alignment_Table_1 Document JSON: +{ + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 83, + "kind": "list", + "list": [ + { + "id": 77, + "kind": "text", + "text": "record" + }, + { + "command": { + "command": "indent", + "indentContents": { + "id": 79, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 78, + "kind": "command" + }, + { + "command": { + "elements": [ + [ + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 74, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 0, + "kind": "command" + }, + { + "id": 1, + "kind": "text", + "text": "A " + } + ] + }, + "id": 0 + }, + "id": 75, + "kind": "command" + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 5, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 3, + "kind": "command" + }, + { + "id": 4, + "kind": "text", + "text": "B " + } + ] + } + }, + "id": 6, + "kind": "command" + }, + "id": 1 + }, + "id": 7, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 12, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 9, + "kind": "command" + }, + { + "id": 10, + "kind": "text", + "text": "C" + }, + { + "id": 11, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 13, + "kind": "command" + } + }, + "id": 14, + "kind": "command" + } + }, + "id": 15, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 19, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 16, + "kind": "command" + }, + { + "id": 17, + "kind": "text", + "text": "C" + }, + { + "id": 18, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 20, + "kind": "command" + } + }, + "id": 21, + "kind": "command" + }, + "ifBreakGroupId": 1 + }, + "id": 22, + "kind": "command" + } + ], + [ + { + "id": 23, + "kind": "text", + "text": "AA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 27, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 25, + "kind": "command" + }, + { + "id": 26, + "kind": "text", + "text": "BB " + } + ] + } + }, + "id": 28, + "kind": "command" + }, + "id": 2 + }, + "id": 29, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 34, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 31, + "kind": "command" + }, + { + "id": 32, + "kind": "text", + "text": "CC" + }, + { + "id": 33, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 35, + "kind": "command" + } + }, + "id": 36, + "kind": "command" + } + }, + "id": 37, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 41, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 38, + "kind": "command" + }, + { + "id": 39, + "kind": "text", + "text": "CC" + }, + { + "id": 40, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 42, + "kind": "command" + } + }, + "id": 43, + "kind": "command" + }, + "ifBreakGroupId": 2 + }, + "id": 44, + "kind": "command" + } + ], + [ + { + "id": 45, + "kind": "text", + "text": "AAA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 49, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 47, + "kind": "command" + }, + { + "id": 48, + "kind": "text", + "text": "BBBBBBBBB;" + } + ] + } + }, + "id": 50, + "kind": "command" + }, + "id": 3 + }, + "id": 51, + "kind": "command" + } + ], + [ + { + "id": 52, + "kind": "text", + "text": "AAAA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 56, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 54, + "kind": "command" + }, + { + "id": 55, + "kind": "text", + "text": "BBBB " + } + ] + } + }, + "id": 57, + "kind": "command" + }, + "id": 4 + }, + "id": 58, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 63, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 60, + "kind": "command" + }, + { + "id": 61, + "kind": "text", + "text": "CCCC" + }, + { + "id": 62, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 64, + "kind": "command" + } + }, + "id": 65, + "kind": "command" + } + }, + "id": 66, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 70, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 67, + "kind": "command" + }, + { + "id": 68, + "kind": "text", + "text": "CCCC" + }, + { + "id": 69, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 71, + "kind": "command" + } + }, + "id": 72, + "kind": "command" + }, + "ifBreakGroupId": 4 + }, + "id": 73, + "kind": "command" + } + ] + ], + "kind": "alignmentTable", + "mustBreak": true, + "separators": [ + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 2, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 8, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 24, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 30, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 46, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 53, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 59, + "kind": "command" + } + ] + ] + }, + "id": 76, + "kind": "command" + } + ] + } + }, + "id": 80, + "kind": "command" + }, + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 81, + "kind": "command" + }, + { + "id": 82, + "kind": "text", + "text": "end record" + } + ] + }, + "id": 0 + }, + "id": 84, + "kind": "command" +} +> Alignment_Table_1 Document Formatted: +record + + A : B := C; + AA : BB := CC; + AAA : BBBBBBBBB; + AAAA : BBBB := CCCC; +end record +> Alignment_Table_2 Document JSON: +{ + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 168, + "kind": "list", + "list": [ + { + "id": 162, + "kind": "text", + "text": "record" + }, + { + "command": { + "command": "indent", + "indentContents": { + "id": 164, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 163, + "kind": "command" + }, + { + "command": { + "elements": [ + [ + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 159, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 85, + "kind": "command" + }, + { + "id": 86, + "kind": "text", + "text": "A " + } + ] + }, + "id": 0 + }, + "id": 160, + "kind": "command" + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 90, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 88, + "kind": "command" + }, + { + "id": 89, + "kind": "text", + "text": "B " + } + ] + } + }, + "id": 91, + "kind": "command" + }, + "id": 5 + }, + "id": 92, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 97, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 94, + "kind": "command" + }, + { + "id": 95, + "kind": "text", + "text": "C" + }, + { + "id": 96, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 98, + "kind": "command" + } + }, + "id": 99, + "kind": "command" + } + }, + "id": 100, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 104, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 101, + "kind": "command" + }, + { + "id": 102, + "kind": "text", + "text": "C" + }, + { + "id": 103, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 105, + "kind": "command" + } + }, + "id": 106, + "kind": "command" + }, + "ifBreakGroupId": 5 + }, + "id": 107, + "kind": "command" + } + ], + [ + { + "id": 108, + "kind": "text", + "text": "AA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 112, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 110, + "kind": "command" + }, + { + "id": 111, + "kind": "text", + "text": "BB " + } + ] + } + }, + "id": 113, + "kind": "command" + }, + "id": 6 + }, + "id": 114, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 119, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 116, + "kind": "command" + }, + { + "id": 117, + "kind": "text", + "text": "CC" + }, + { + "id": 118, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 120, + "kind": "command" + } + }, + "id": 121, + "kind": "command" + } + }, + "id": 122, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 126, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 123, + "kind": "command" + }, + { + "id": 124, + "kind": "text", + "text": "CC" + }, + { + "id": 125, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 127, + "kind": "command" + } + }, + "id": 128, + "kind": "command" + }, + "ifBreakGroupId": 6 + }, + "id": 129, + "kind": "command" + } + ], + [ + { + "id": 130, + "kind": "text", + "text": "AAA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 134, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 132, + "kind": "command" + }, + { + "id": 133, + "kind": "text", + "text": "BBBBBBBBB;" + } + ] + } + }, + "id": 135, + "kind": "command" + }, + "id": 7 + }, + "id": 136, + "kind": "command" + } + ], + [ + { + "id": 137, + "kind": "text", + "text": "AAAA " + }, + { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "command": { + "command": "indent", + "indentContents": { + "id": 141, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 139, + "kind": "command" + }, + { + "id": 140, + "kind": "text", + "text": "BBBB " + } + ] + } + }, + "id": 142, + "kind": "command" + }, + "id": 8 + }, + "id": 143, + "kind": "command" + }, + { + "command": { + "breakContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 148, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 145, + "kind": "command" + }, + { + "id": 146, + "kind": "text", + "text": "CCCC" + }, + { + "id": 147, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 149, + "kind": "command" + } + }, + "id": 150, + "kind": "command" + } + }, + "id": 151, + "kind": "command" + }, + "command": "ifBreak", + "flatContents": { + "command": { + "command": "indent", + "indentContents": { + "command": { + "break": false, + "command": "group", + "expandedStates": null, + "groupContents": { + "id": 155, + "kind": "list", + "list": [ + { + "command": { + "command": "line", + "hard": false, + "literal": false, + "soft": false + }, + "id": 152, + "kind": "command" + }, + { + "id": 153, + "kind": "text", + "text": "CCCC" + }, + { + "id": 154, + "kind": "text", + "text": ";" + } + ] + }, + "id": 0 + }, + "id": 156, + "kind": "command" + } + }, + "id": 157, + "kind": "command" + }, + "ifBreakGroupId": 8 + }, + "id": 158, + "kind": "command" + } + ] + ], + "kind": "alignmentTable", + "mustBreak": true, + "separators": [ + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 87, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 93, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 109, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 115, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 131, + "kind": "command" + } + ], + [ + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 138, + "kind": "command" + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 144, + "kind": "command" + } + ] + ] + }, + "id": 161, + "kind": "command" + } + ] + } + }, + "id": 165, + "kind": "command" + }, + { + "command": { + "command": "line", + "hard": true, + "literal": false, + "soft": false + }, + "id": 166, + "kind": "command" + }, + { + "id": 167, + "kind": "text", + "text": "end record" + } + ] + }, + "id": 0 + }, + "id": 169, + "kind": "command" +} +> Alignment_Table_2 Document Formatted: +record + + A : + B := + C; + AA : + BB := + CC; + AAA : + BBBBBBBBB; + AAAA : + BBBB := + CCCC; +end record + +=== Alignment_Table_Separator === +> Alignment_Table_Separator Document JSON: +{ + "id": 10, + "kind": "list", + "list": [ + { + "id": 0, + "kind": "text", + "text": "A" + }, + { + "id": 1, + "kind": "text", + "text": " " + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":" + }, + "id": 2, + "kind": "command" + }, + { + "id": 3, + "kind": "text", + "text": " " + }, + { + "id": 4, + "kind": "text", + "text": "B" + }, + { + "id": 5, + "kind": "text", + "text": " " + }, + { + "command": { + "kind": "alignmentTableSeparator", + "text": ":=" + }, + "id": 6, + "kind": "command" + }, + { + "id": 7, + "kind": "text", + "text": " " + }, + { + "id": 8, + "kind": "text", + "text": "C" + }, + { + "id": 9, + "kind": "text", + "text": ";" + } + ] +} +> Alignment_Table_Separator Document Formatted: +A : B := C; + === Break_Parent === > Break_Parent Document JSON: { @@ -270,7 +1652,7 @@ B { "command": { "command": "cursor", - "placeHolder": 1 + "placeHolder": 9 }, "id": 1, "kind": "command" @@ -512,7 +1894,7 @@ C } ] }, - "id": 2 + "id": 10 }, "id": 13, "kind": "command" @@ -624,7 +2006,7 @@ C } ] }, - "id": 3 + "id": 11 }, "id": 27, "kind": "command" @@ -715,7 +2097,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "kind": "text", "text": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" }, - "id": 4 + "id": 12 }, "id": 10, "kind": "command"