Hey Laurent, Making this more comprehensible is part of my plan for documenting how to create dispatch. You don't really need to understand the whole XP paper to know enough to understand how pretty print works. Let me lay out a quick overview here:
High-level concepts Top-level concept: the pretty printer tries to keep things together on a line unless they don't fit, in which case it splits the lines in appropriate places and indents successive lines to the right place. 2nd top-level concept: pretty printing is a mechanism, not a fixed function. The actual printing is controlled by dispatch functions that in turn call functions in the underlying mechanism. There are four examples you can look at to see how this works in Clojure: two functions in clojure/contrib/pprint/dispatch.clj that implement the standard "simple" dispatch and the specialized "code" dispatch. The other two are in clojure/contrib/pprint/examples and format clojure structure as pretty printed json or xml. There are two ways to define the dispatch function (which is basically always a multimethod because you do different things for different types): writing it out as a function or specifying a format for cl- format using the formatter-out function. I'll assume the first method here, since it will be more familiar. Logical blocks The "things" that the pretty printer thinks about are "logical blocks." These usually correspond to things like lists, vectors, maps and such. Logical blocks are nested (just like lists, vectors,...). Logical blocks are created by the macro pprint-logical-block. This macro wraps its body in a logical block and allows you to specify prefix and suffix (e.g., "(" and ")"). Control variables There are two key variables that control where the pretty printer decides to break lines, *print-right-margin* and *print-miser-width*. The first is the most significant and tells pprint where you want it to try get the line to break. *print-miser-width* is a width back to the left from the right margin where you want pprint to be really aggressive about breaking lines (this is useful for heavily nested structures). For example, "let" may not break between the let and the binding vector, but if the let construct is to the right of the miser width boundary (i.e. very indented), it might put a newline there. This makes it more likely that we'll be able to fit even more deeply nested structures inside the right margin. Note that the pretty printer doesn't completely guarantee that it will be able to print a structure within the right margin, but it does a pretty good job in practice. Newlines The are 4 kinds of newlines that the dispatch function can specify: linear, fill, miser, and mandatory. These are created by the pprint- newline function which takes a keyword argument specifying the type. Simplifying a little, we can consider each type: Linear: If a logical block doesn't fit on a single line, *all* the linear newlines in it are emitted as real newlines, otherwise none of them are. (For example, simple-dispatch specifies a linear newline between each element of a list. So either the list is printed on a single line, or every element is printed on its own line). Fill: If a logical block doesn't fit on a single line, only those fill newlines that are necessary to make the parts fit are emitted and the rest are ignored. (For example, when formatting XML attributes, we fit as many as possible on a single line before inserting a newline.) Miser: If you see a miser newline when you are to the right of the miser width boundary, miser newlines are emitted, otherwise they are ignored. Mandatory: A mandatory newline is always emitted. Indenting By default, when a newline is emitted the next line is indented to the column where the first character of the current logical block was emitted (after any prefix). So simple list structures line up right after the opening paren, for instance. You can override this default with pprint-indent which allows you to specify an indent relative to the beginning of the block or the current column position. Write and write-out "write" is a general function which will (in general) allow you to emit an object using the pretty printer. In dispatch functions, we use "write-out" which is a version of write that assumes that *out* has been correctly set up for the pretty printer. You can think of write- out as a recursive call to the pretty printer when you see it or use it in dispatch functions. I think that should give you enough to get started with. Check out the dispatch functions I mentioned above to see all of this in action. And let me know if I clarify any more stuff. Tom --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---