[m-rev.] For review: aesthetic improvement to pretty_printer output

Ralph Becket rafe at csse.unimelb.edu.au
Fri May 15 13:51:07 AEST 2009


library/pretty_printer.m:
	Add a new doc constructor, hard_nl, which always causes a newline
	(and indentation) to be printed.

	Change the behaviour of the nl constructor so that a newline is
	only started if it increases the amount of space on the line for
	output.

Index: pretty_printer.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/pretty_printer.m,v
retrieving revision 1.8
diff -u -r1.8 pretty_printer.m
--- pretty_printer.m	13 May 2009 01:44:40 -0000	1.8
+++ pretty_printer.m	15 May 2009 03:37:56 -0000
@@ -60,8 +60,12 @@
             % etc. will lead to strange output.
 
     ;       nl
-            % Output a newline if the enclosing group does not fit on the
-            % current line.
+            % Output a newline, followed by indentation, iff the enclosing
+            % group does not fit on the current line and starting a new line
+            % adds more space.
+
+    ;       hard_nl
+            % Always outputs a newline, followed by indentation.
 
     ;       docs(docs)
             % An embedded sequence of docs.
@@ -113,8 +117,8 @@
 
     % group(Docs)
     %   If Docs can be output on the remainder of the current line
-    %   by ignoring any newlines in Docs, then do so.  Otherwise
-    %   newlines in Docs are printed (followed by any indentation).
+    %   by ignoring any nls in Docs, then do so.  Otherwise
+    %   nls in Docs are printed (followed by any indentation).
     %   The formatting test is applied recursively for any subgroups in Docs.
     %
 :- func group(docs) = doc.
@@ -377,20 +381,24 @@
             !:RemainingWidth = !.RemainingWidth - string.length(String),
             Docs = Docs0
         ;
-            % Output soft newlines if what follows up to the next newline
-            % fits on the rest of the current line.  Don't bother outputting
-            % a newline if we're already at the start of a new line and we
-            % don't have any indentation.
-            %
             Doc = nl,
-            ( if LineWidth = !.RemainingWidth, !.Indents = [] then
-                true
-              else
+            ( if
+                F = ( func(S, W) = string.length(S) + W ),
+                IndentWidth = list.foldl(F, !.Indents, 0),
+                !.RemainingWidth < LineWidth - IndentWidth
+              then
                 format_nl(Stream, LineWidth, !.Indents, !:RemainingWidth,
                     !RemainingLines, !IO)
+              else
+                true
             ),
             Docs = Docs0
         ;
+            Doc = hard_nl,
+            format_nl(Stream, LineWidth, !.Indents, !:RemainingWidth,
+                !RemainingLines, !IO),
+            Docs = Docs0
+        ;
             Doc = docs(Docs1),
             Docs = list.(Docs1 ++ Docs0)
         ;
@@ -433,8 +441,8 @@
             expand_docs(Canonicalize, FMap, Docs0, Docs1, OpenGroups,
                 !Limit, !Pri, CurrentRemainingWidth, RemainingWidthAfterGroup),
             ( if RemainingWidthAfterGroup >= 0 then
-                output_current_group(Stream, OpenGroups,
-                    Docs1, Docs, !RemainingWidth, !IO)
+                output_current_group(Stream, LineWidth, !.Indents, OpenGroups,
+                    Docs1, Docs, !RemainingWidth, !RemainingLines, !IO)
               else
                 Docs = Docs1
             )
@@ -458,41 +466,54 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred output_current_group(Stream::in, int::in, docs::in, docs::out,
-        int::in, int::out, State::di, State::uo)
+:- pred output_current_group(Stream::in, int::in, indents::in, int::in,
+        docs::in, docs::out, int::in, int::out, int::in, int::out,
+        State::di, State::uo)
         is det
         <= stream.writer(Stream, string, State).
 
-output_current_group(_Stream, _OpenGroups, [], [], !RemainingWidth, !IO).
+output_current_group(_Stream, _LineWidth, _Indents, _OpenGroups,
+        [], [], !RemainingWidth, !RemainingLines, !IO).
 
-output_current_group(Stream, OpenGroups, [Doc | Docs0], Docs, !RemainingWidth,
-        !IO) :-
+output_current_group(Stream, LineWidth, Indents, OpenGroups,
+        [Doc | Docs0], Docs, !RemainingWidth, !RemainingLines, !IO) :-
 
     ( if Doc = str(String) then
 
         stream.put(Stream, String, !IO),
         !:RemainingWidth = !.RemainingWidth - string.length(String),
-        output_current_group(Stream, OpenGroups, Docs0, Docs,
-            !RemainingWidth, !IO)
+        output_current_group(Stream, LineWidth, Indents, OpenGroups,
+            Docs0, Docs, !RemainingWidth, !RemainingLines, !IO)
+
+      else if Doc = hard_nl then
+
+        format_nl(Stream, LineWidth, Indents, !:RemainingWidth,
+            !RemainingLines, !IO),
+        ( if !.RemainingLines =< 0 then
+            Docs = Docs0
+          else
+            output_current_group(Stream, LineWidth, Indents, OpenGroups,
+                Docs0, Docs, !RemainingWidth, !RemainingLines, !IO)
+        )
 
       else if Doc = pp_internal(open_group) then
 
-        output_current_group(Stream, OpenGroups + 1, Docs0, Docs,
-            !RemainingWidth, !IO)
+        output_current_group(Stream, LineWidth, Indents, OpenGroups + 1,
+            Docs0, Docs, !RemainingWidth, !RemainingLines, !IO)
 
       else if Doc = pp_internal(close_group) then
 
         ( if OpenGroups = 1 then
             Docs = Docs0
           else
-            output_current_group(Stream, OpenGroups - 1, Docs0, Docs,
-                !RemainingWidth, !IO)
+            output_current_group(Stream, LineWidth, Indents, OpenGroups - 1,
+                Docs0, Docs, !RemainingWidth, !RemainingLines, !IO)
         )
 
       else
 
-        output_current_group(Stream, OpenGroups, Docs0, Docs, !RemainingWidth,
-            !IO)
+        output_current_group(Stream, LineWidth, Indents, OpenGroups,
+            Docs0, Docs, !RemainingWidth, !RemainingLines, !IO)
 
     ).
 
@@ -516,13 +537,14 @@
 :- mode expand_docs(in(include_details_cc), in, in, out, in, in, out,
         in, out, in, out) is cc_multi.
 
-expand_docs(_Canonicalize, _FMap, [], [], _OpenGroups, !Limit, !Pri, !N).
+expand_docs(_Canonicalize, _FMap, [], [], _OpenGroups,
+        !Limit, !Pri, !RemainingWidth).
 
 expand_docs(Canonicalize, FMap, [Doc | Docs0], Docs, OpenGroups,
         !Limit, !Pri, !RemainingWidth) :-
     ( if
         (
-            OpenGroups = 0, Doc = nl
+            OpenGroups =< 0, ( Doc = nl ; Doc = hard_nl )
             % We have found the first nl after the close of the current
             % open group.
         ;
@@ -540,7 +562,7 @@
             expand_docs(Canonicalize, FMap, Docs0, Docs1, OpenGroups,
                 !Limit, !Pri, !RemainingWidth)
         ;
-            Doc = nl,
+            ( Doc = nl ; Doc = hard_nl ),
             ( if OpenGroups =< 0 then
                 Docs = [Doc | Docs0]
               else
@@ -609,6 +631,8 @@
 
 %-----------------------------------------------------------------------------%
 
+    % Output a newline followed by indentation.
+    %
 :- pred format_nl(Stream::in, int::in, indents::in, int::out,
         int::in, int::out, State::di, State::uo)
         is det
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list