From 1c7fd314d182bafd7254ca8d025a4d83a72a2d6a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 26 Dec 2017 21:13:56 +0100 Subject: [PATCH] FPPP: Add heuristic for multi-line lists --- CHANGELOG.md | 11 ++-- lib/PhpParser/PrettyPrinterAbstract.php | 57 +++++++++++++++++-- .../formatPreservation/listInsertion.test | 36 +++++++++++- test/code/formatPreservation/listRemoval.test | 5 +- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd91a0e99..4d764017c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ Version 4.0.0-dev ----------------- -Nothing yet. +### Added + +* In formatting-preserving pretty printer: + * Improved formatting of elements inserted into multi-line arrays. Version 4.0.0-alpha3 (2017-12-26) --------------------------------- @@ -9,9 +12,9 @@ Version 4.0.0-alpha3 (2017-12-26) ### Fixed * In the formatting-preserving pretty printer: - * Fixed comment indentation. - * Fixed handling of inline HTML in the fallback case. - * Fixed insertion into list nodes that require creation of a code block. + * Fixed comment indentation. + * Fixed handling of inline HTML in the fallback case. + * Fixed insertion into list nodes that require creation of a code block. ### Added diff --git a/lib/PhpParser/PrettyPrinterAbstract.php b/lib/PhpParser/PrettyPrinterAbstract.php index f07a7cb808..c95cfdaa1c 100644 --- a/lib/PhpParser/PrettyPrinterAbstract.php +++ b/lib/PhpParser/PrettyPrinterAbstract.php @@ -701,7 +701,13 @@ protected function pArray( $beforeFirstKeepOrReplace = true; $delayedAdd = []; - if ($subNodeName === 'stmts' && count($origNodes) === 1 && count($nodes) !== 1) { + $insertNewline = false; + if ($insertStr === "\n") { + $insertStr = ''; + $insertNewline = true; + } + + if ($subNodeName === 'stmts' && \count($origNodes) === 1 && \count($nodes) !== 1) { $startPos = $origNodes[0]->getStartTokenPos(); $endPos = $origNodes[0]->getEndTokenPos(); \assert($startPos >= 0 && $endPos >= 0); @@ -769,7 +775,7 @@ protected function pArray( /** @var Node $delayedAddNode */ foreach ($delayedAdd as $delayedAddNode) { - if ($insertStr === "\n") { + if ($insertNewline) { $delayedAddComments = $delayedAddNode->getComments(); if ($delayedAddComments) { $result .= $this->pComments($delayedAddComments) . $this->nl; @@ -778,8 +784,8 @@ protected function pArray( $this->safeAppend($result, $this->p($delayedAddNode, true)); - if ($insertStr === "\n") { - $result .= $this->nl; + if ($insertNewline) { + $result .= $insertStr . $this->nl; } else { $result .= $insertStr; } @@ -804,6 +810,11 @@ protected function pArray( return null; } + if ($insertStr === ', ' && $this->isMultiline($origNodes)) { + $insertStr = ','; + $insertNewline = true; + } + if ($beforeFirstKeepOrReplace) { // Will be inserted at the next "replace" or "keep" element $delayedAdd[] = $arrItem; @@ -816,12 +827,12 @@ protected function pArray( $origIndentLevel = $this->indentLevel; $this->setIndentLevel($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment); - if ($insertStr === "\n") { + if ($insertNewline) { $comments = $arrItem->getComments(); if ($comments) { $result .= $this->nl . $this->pComments($comments); } - $result .= $this->nl; + $result .= $insertStr . $this->nl; } else { $result .= $insertStr; } @@ -1006,6 +1017,40 @@ protected function pModifiers(int $modifiers) { . ($modifiers & Stmt\Class_::MODIFIER_FINAL ? 'final ' : ''); } + /** + * Determine whether a list of nodes uses multiline formatting. + * + * @param (Node|null)[] $nodes Node list + * + * @return bool Whether multiline formatting is used + */ + protected function isMultiline(array $nodes) : bool { + if (\count($nodes) < 2) { + return false; + } + + $pos = -1; + foreach ($nodes as $node) { + if (null === $node) { + continue; + } + + $endPos = $node->getEndTokenPos() + 1; + if ($pos >= 0) { + $text = $this->origTokens->getTokenCode($pos, $endPos, 0); + if (false === strpos($text, "\n")) { + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + return false; + } + } + $pos = $endPos; + } + + return true; + } + /** * Lazily initializes label char map. * diff --git a/test/code/formatPreservation/listInsertion.test b/test/code/formatPreservation/listInsertion.test index 7d1fd8c158..75fdaa6722 100644 --- a/test/code/formatPreservation/listInsertion.test +++ b/test/code/formatPreservation/listInsertion.test @@ -276,4 +276,38 @@ function test() { $a; $b; -} \ No newline at end of file +} +----- +expr->expr->items, new Expr\ArrayItem(new Scalar\LNumber(42))); +$stmts[0]->expr->expr->items[] = new Expr\ArrayItem(new Scalar\LNumber(24)); +----- +expr->expr->items[3] = new Expr\ArrayItem(new Scalar\LNumber(24)); +----- +params); $stmts[0]->params[] = new Node\Param(new Expr\Variable('x')); $stmts[0]->params[] = new Node\Param(new Expr\Variable('y')); -/* TODO The insertion here should try to to honor the style */ -----