PreviousUpNext

15.4.838  src/lib/prettyprint/big/src/prettyprinter.pkg

## prettyprinter.pkg

# Compiled by:
#     src/lib/prettyprint/big/prettyprint.lib


stipulate
    package fil =  file__premicrothread;                                # file__premicrothread  is from   src/lib/std/src/posix/file--premicrothread.pkg
herein

    package   prettyprinter
    : (weak)  Prettyprinter                                             # Prettyprinter         is from   src/lib/prettyprint/big/src/prettyprinter.api
    {
        # I find the original prettyprinter interface ugly and clumsy;
        # this is an attempt to provide something simpler and cleaner.
        #
        # The idea is to do
        #
        #     pp.horizontal_else_vertical_box .{
        #         pp.out "Various\rstuff\rof consequence.\n";
        #     };
        #
        # or
        #
        #     pp.horizontal_else_vertical_box .{
        #         pp.put "Various stuff of consequence.\n";
        #     };
        #
        # instead of
        #
        #     pp::begin_horizontal_else_vertical_box stream;
        #     pp::string        stream "Various";
        #     pp::break         stream { spaces=>1; indent_on_wrap=>4 };
        #     pp::string        stream "stuff";
        #     pp::break         stream { spaces=>1; indent_on_wrap=>4 };
        #     pp::string        stream "of consequence.";
        #     pp::newline       stream;
        #     pp::end_box     stream;
        #
        # approximately.  In particular, I see the former as:
        #  o  Inherently keeping block open/close pairs matched.
        #     (The original code had at least one such bug.)
        #  o  Reducing clutter by making the 'stream' arguments implicit.
        #  o  Reducing clutter by allowing newlines to be included in strings
        #     instead of having to be separate calls.
        # Currently unused, probably needs tuning.
        #
        #    
        # TO DO:                                   XXX BUGGO FIXME
        #    Drop wrap'_box and wrap'_box'
        #    Change horizontal_else_vertical_box and horizontal_else_vertical_box' to align  and align'
        #    Change wrap_box and wrap_box' to wrap   and wrap' 
        #    Maybe change '\r' to '\ ' (or to \{  } so we can specify the
        #       number of blanks in a break naturally)? Or maybe out/put distinction handles this ok?

        package pp = prettyprint;       # prettyprint   is from   src/lib/prettyprint/big/src/prettyprint.pkg

        Prettyprinter
            =
            { stream:      prettyprint::Stream,
              text_stream: Null_Or( fil::Output_Stream ),

              align:   (Void -> Void) -> Void,
              wrap:    (Void -> Void) -> Void,

              align':  Int -> (Void -> Void) -> Void,
              wrap':   Int -> (Void -> Void) -> Void,

              flush:      Void -> Void,
              close:      Void -> Void,

              lit:        String -> Void,
              out:        String -> Void,
              put:        String -> Void
            };  


        fun make_file_prettyprinter  prettyprint_filename
            =
            {   text_stream =  fil::open_for_write  prettyprint_filename; 
                #
                prettyprint_device
                    =
                    {   consumer  =>  (fn string =  fil::write  (text_stream,  string)),
                        linewidth =>  2000,                                                     # Arbitrary large number.
                        flush     =>  .{ fil::flush  text_stream; }
                    };

                stream =   pp::open_stream  prettyprint_device;

                fun align     thunk =   { pp::begin_horizontal_else_vertical_box    stream;    thunk();   pp::end_box stream;   };
                fun wrap      thunk =   { pp::begin_wrap_box    stream;    thunk();   pp::end_box stream;   };

                fun align'    i thunk =   { pp::begin_indented_horizontal_else_vertical_box    stream (pp::BOX_RELATIVE i);   thunk();   pp::end_box stream; };
                fun wrap'     i thunk =   { pp::begin_indented_wrap_box    stream (pp::BOX_RELATIVE i);   thunk();   pp::end_box stream; };

                fun flush ()           =   { pp::flush_stream  stream;    fil::flush         text_stream; };
                fun close ()           =   { pp::close_stream  stream;    fil::close_output  text_stream; };



                ##############################################################################
                #                       lit / out / put
                #
                # The idea with out/put is to replace
                # explicit calls to pp::break and pp::newline
                # with embedded ' '  '\r'  '\n'  chars:
                #
                #   lit:   Entire string output literally with no special character treatments.
                #   out:   '\n'                 treated as pp::newline
                #          '\r'                 treated as pp::break { spaces => 3, indent_on_wrap => 0 }
                #          N blanks             treated as pp::break { spaces => n, indent_on_wrap => 0 }
                #   put:   Same, except indent_on_wrap for blanks is 4.
                # 
                # The expectation is that:
                #   lit:   Will typically be used to format short statements in a line box.
                #   put:   Will typically be used to wrap individual words in a wrap box.
                # In the former case, one usually wants wrapped lines to be aligned,  hence the 'indent_on_wrap => 0'
                # In the latter case, one usually wants wrapped lines to be indented, hence the 'indent_on_wrap => 4'
                # 
                # (I don't expect \r to appear in 'put' strings, in general,
                # but there seems no reason not to support it.)
                ##############################################################################


                fun lit string
                    = 
                    pp::string stream string;

                fun output indent string
                    = 
                    next 0
                    where

                        len =   size string;

                        fun next i
                            =
                            if (i < len)
                                #
                                c =  string::get (string, i);

                                case c
                                    '\n' =>  do_newline i;
                                    '\r' =>  do_cr      i;
                                    ' '  =>  do_spaces (i, i+1);
                                     _   =>  do_other  (i, i+1);
                                esac;
                            fi

                        also
                        fun do_newline  i                                               # Treat each \n in 'string' as a call to pp:newline.
                            =
                            {    pp::newline stream;
                                 next (i+1);
                            }

                        also
                        fun do_cr  i                                                    # Treat each \r in 'string' as a call to pp:break { spaces => 3, indent_on_wrap => 0 }.
                            =
                            {    pp::break  stream  { spaces => 1,  indent_on_wrap => 0 };
                                 next (i+1);
                            }

                        also
                        fun do_spaces  (i, j)                                           # Treat a run of 'n' blanks in 'string' as a call to pp:break { spaces => n, indent_on_wrap => 4 }.
                            =
                            {
                                if (j >= len)

                                    pp::break  stream  { spaces => j-i,  indent_on_wrap => indent };
                                else
                                    c =  string::get (string, j);

                                    if (c == ' ')
                                        #
                                        do_spaces (i, j+1);                             # Scan to end of string of blanks.
                                    else
                                        pp::break  stream  { spaces => j-i,  indent_on_wrap => 4 };
                                        next j;
                                    fi;
                                fi;
                            }

                        also                                                            # Treat literally a run of non-\n, non-\r, non-blank chars in 'string'.
                        fun do_other (i, j)
                            =
                            if (j >= len)
                                #
                                pp::string stream (string::substring (string, i, j-i));
                            else
                                c =  string::get (string, j);

                                if  (c != ' '
                                and  c != '\r'
                                and  c != '\n'
                                )
                                     do_other (i, j+1);                                 # Scan to end of string of vanilla characters.
                                else
                                     substring =  string::substring (string, i, j-i);
                                     pp::string stream substring;
                                     next j;
                                fi;
                            fi;
                    end;                                                                # fun output

                fun out string =   output 0 string;
                fun put string =   output 4 string;


                { stream,
                  text_stream => THE text_stream,

                  align,
                  wrap,

                  align',
                  wrap',

                  flush,
                  close,

                  lit,
                  out,
                  put
                };  
            };

    }; #  package prettyprinter
end;



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext