Merge branch 'master' into tarilabs-20170831
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
index c9ce291..5de7496 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
@@ -676,11 +676,20 @@
         printJavaComment(n.getComment(), arg);
         if (n.getScope().isPresent()) {
             n.getScope().get().accept(this, arg);
+            if (configuration.isColumnAlignFirstMethodChain()) {
+                if (!(n.getScope().get() instanceof MethodCallExpr) || (!((MethodCallExpr)n.getScope().get()).getScope().isPresent())) {
+                    printer.resetMethodChainPosition(printer.getCursor());
+                } else {
+                    printer.wrapToColumn(printer.peekMethodChainPosition().column);
+                }
+            }
             printer.print(".");
         }
         printTypeArgs(n, arg);
         n.getName().accept(this, arg);
+        printer.pushMethodChainPosition(printer.getCursor());
         printArguments(n.getArguments(), arg);
+        printer.popMethodChainPosition();
     }
 
     @Override
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java
index 9a4f42e..3127076 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java
@@ -30,6 +30,7 @@
     private boolean printComments = true;
     private boolean printJavaDoc = true;
     private boolean columnAlignParameters = false;
+    private boolean columnAlignFirstMethodChain = false;
     private String indent = "    ";
     private String endOfLineCharacter = EOL;
     private Function<PrettyPrinterConfiguration, PrettyPrintVisitor> visitorFactory = PrettyPrintVisitor::new;
@@ -59,6 +60,10 @@
         return columnAlignParameters;
     }
 
+    public boolean isColumnAlignFirstMethodChain() {
+        return columnAlignFirstMethodChain;
+    }
+
     public PrettyPrinterConfiguration setPrintComments(boolean printComments) {
         this.printComments = printComments;
         return this;
@@ -73,6 +78,11 @@
         this.columnAlignParameters = columnAlignParameters;
         return this;
     }
+    
+    public PrettyPrinterConfiguration setColumnAlignFirstMethodChain(boolean columnAlignFirstMethodChain) {
+        this.columnAlignFirstMethodChain = columnAlignFirstMethodChain;
+        return this;
+    }
 
     public Function<PrettyPrinterConfiguration, PrettyPrintVisitor> getVisitorFactory() {
         return visitorFactory;
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java b/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
index 7470e23..bb06adb 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
@@ -22,6 +22,8 @@
 package com.github.javaparser.printer;
 
 import java.text.Normalizer;
+import java.util.Deque;
+import java.util.LinkedList;
 
 import com.github.javaparser.Position;
 
@@ -32,10 +34,12 @@
     private boolean indented = false;
     private final StringBuilder buf = new StringBuilder();
     private Position cursor = new Position(1, 0);
+    private Deque<Position> methodChainPositions = new LinkedList<>();
 
     SourcePrinter(final String indentation, final String endOfLineCharacter) {
         this.indentation = indentation;
         this.endOfLineCharacter = endOfLineCharacter;
+        pushMethodChainPosition(cursor); // initialize a default position for methodChainPositions, it is expected by method #resetMethodChainPosition()
     }
 
     public SourcePrinter indent() {
@@ -95,6 +99,23 @@
         return cursor;
     }
     
+    public void resetMethodChainPosition(Position position) {
+        this.methodChainPositions.pop();
+        this.methodChainPositions.push(position);
+    }
+
+    public void pushMethodChainPosition(Position position) {
+        this.methodChainPositions.push(position);
+    }
+    
+    public Position peekMethodChainPosition() {
+        return this.methodChainPositions.peek();
+    }
+    
+    public Position popMethodChainPosition() {
+        return this.methodChainPositions.pop();
+    }
+    
     /**
      * Performs a new line and indent, then prints enough space characters until aligned to the specified column.
      * @param column the column to align to
diff --git a/javaparser-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java b/javaparser-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
index 5ec23e2..65d2dca 100644
--- a/javaparser-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
+++ b/javaparser-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
@@ -32,6 +32,8 @@
 
 import static org.junit.Assert.assertEquals;
 
+import java.util.stream.IntStream;
+
 public class PrettyPrinterTest {
 
     private String prettyPrintField(String code) {
@@ -97,21 +99,50 @@
     
     @Test
     public void prettyColumnAlignParameters() {
-        String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
-        String expected = "class Example {\n" + 
-                "\n" + 
-                "\tvoid foo(Object arg0, Object arg1) {\n" + 
-                "\t\tmyMethod(1,\n" + 
-                "\t\t         2,\n" + 
-                "\t\t         3,\n" + 
-                "\t\t         5,\n" + 
-                "\t\t         Object.class);\n" + 
-                "\t}\n" + 
-                "}\n" + 
-                "";
         PrettyPrinterConfiguration config = new PrettyPrinterConfiguration();
         config.setIndent("\t");
         config.setColumnAlignParameters(true);
+        
+        final String EOL = config.getEndOfLineCharacter();
+        
+        String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
+        String expected = "class Example {" + EOL + 
+                "" + EOL + 
+                "\tvoid foo(Object arg0, Object arg1) {" + EOL + 
+                "\t\tmyMethod(1," + EOL + 
+                "\t\t         2," + EOL + 
+                "\t\t         3," + EOL + 
+                "\t\t         5," + EOL + 
+                "\t\t         Object.class);" + EOL + 
+                "\t}" + EOL + 
+                "}" + EOL + 
+                "";
+        
+        assertEquals(expected, new PrettyPrinter(config).print(JavaParser.parse(code)));
+    }
+    
+    @Test
+    public void prettyAlignMethodCallChains() {
+        IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println);
+        PrettyPrinterConfiguration config = new PrettyPrinterConfiguration();
+        config.setIndent("\t");
+        config.setColumnAlignFirstMethodChain(true);
+        
+        final String EOL = config.getEndOfLineCharacter();
+        
+        String code = "class Example { void foo() { IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println); } }";
+        String expected = "class Example {" + EOL + 
+                "" + EOL + 
+                "\tvoid foo() {" + EOL + 
+                "\t\tIntStream.range(0, 10)" + EOL + 
+                "\t\t         .filter(x -> x % 2 == 0)" + EOL + 
+                "\t\t         .map(x -> x * IntStream.of(1, 3, 5, 1)" + EOL + 
+                "\t\t                                .sum())" + EOL + 
+                "\t\t         .forEach(System.out::println);" + EOL + 
+                "\t}" + EOL + 
+                "}" + EOL + 
+                "";
+
         assertEquals(expected, new PrettyPrinter(config).print(JavaParser.parse(code)));
     }