package Sequenic.P2 ; import java.util.* ; /** * Simple library for pretty printing text. A PP object represents * essentially a list of strings. The method {@link #render render} can be used * to render this object to a single string formatted in a certain * way. * *

Logically the strings to be pretty printed are grouped * hierarchically into groups that have to be printed side by side, * and groups that have to be printed above the other. * * *

Internally, PP is structured recursively. It has * right and under pointers that again point to PP * objects. The PP at 'right' is to be printed right to the current * PP, and the PP at 'under' is to be printed below the current * PP. There is also a field line which contains a single * string (which should not contain a newline). It represents the * single line of text belonging to the currect PP. * *

The field indent specifies an indentation offset for the PP (and * all PP's below it). * *

In addition to the redering method, this library also provides * some methods for constructing PPs. * *

Example: see source code. * * @author Wishnu Prasetya (wishnu@cs.uu.nl) * */ public class PP { /** * Offset indentation for this PP. */ private int indent = 0 ; /** * A single line of string which is the content of this PP. */ private String line = "" ; /** * The PP to be printed right to this PP. */ private PP right = null ; /** * The PP to be printed below this PP. */ private PP under = null ; /** * Creating an empty PP. */ public PP() { } /** * Accumulate reachable nodes in visited. */ private void reachableNodes(Collection visited) { if (visited.contains(this)) return ; visited.add(this) ; if (right != null) right.reachableNodes(visited) ; if (under != null) under.reachableNodes(visited) ; } private Collection reachableNodes() { Collection U = new LinkedList() ; reachableNodes(U) ; return U ; } /** * Return true if there is some node in pp which is reachable from this PP. */ private boolean canReach(PP pp) { Collection U = reachableNodes() ; Collection V = pp.reachableNodes() ; V.retainAll(U) ; return ! V.isEmpty() ; } private boolean isCyclic(Collection visited) { if (visited.contains(this)) return false ; visited.add(this) ; if (right != null && right.isCyclic(visited)) return true ; if (under != null && under.isCyclic(visited)) return true ; visited.remove(this); return false ; } private boolean isCyclic() { return isCyclic(new LinkedList()) ; } /** * Class invariant, requiring this PP to be non-cyclic. */ public boolean classinv(){ return ! isCyclic() ; } private String renderWorker(String output, int horOffset, boolean aside) { if (indent<0) indent = 0 ; // ignore negative indentation if (line != null) { if (aside) output = output + space(indent) + line ; else output = output + space(horOffset + indent) + line ; } if (right != null) output = right.renderWorker(output, horOffset + indent + line.length(), true) ; if (under != null) { output = output + "\n" ; output = under.renderWorker(output,horOffset + indent,false) ; } return output ; } /** * To render this PP to a formatted string. The parameter is the * initial indentation. */ public String render(int horOffset) { String output = "" ; return renderWorker(output,horOffset,false) ; } /** * A specification. */ public String render_spec(int horOffset) { assert ! isCyclic() : "PRE" ; return render(horOffset) ; } /** * To make a PP containing a single line of string as its only content. */ static public PP text(String s) { PP pp = new PP() ; pp.line = s ; return pp ; } private static String space(int n) { String s = "" ; for ( ; 0