diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/indent/TokenFormatter.java b/php/php.editor/src/org/netbeans/modules/php/editor/indent/TokenFormatter.java index 476431657557..f834010651c5 100644 --- a/php/php.editor/src/org/netbeans/modules/php/editor/indent/TokenFormatter.java +++ b/php/php.editor/src/org/netbeans/modules/php/editor/indent/TokenFormatter.java @@ -36,6 +36,7 @@ import org.netbeans.modules.csl.spi.GsfUtilities; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.editor.indent.spi.Context; +import org.netbeans.modules.php.editor.CodeUtils; import org.netbeans.modules.php.editor.lexer.LexUtilities; import org.netbeans.modules.php.editor.lexer.PHPTokenId; import org.netbeans.modules.php.editor.parser.PHPParseResult; @@ -455,7 +456,9 @@ public void run() { int extraLines; int column = 0; int indentOfOpenTag = 0; + int methodCallParenBalance = 0; // GH-6714 for nested arguments final Deque lastBracedBlockIndent = new ArrayDeque<>(); + final Deque lastAnchorTokenStack = new ArrayDeque<>(); // GH-6714 for nested arguments FormatToken formatToken; String newText = null; @@ -1455,12 +1458,17 @@ && countOfNewLines(formatTokens.get(index + 1).getOldText()) > 0) { } // NETBEANS-3391 if (isLeftParen(formatTokens.get(index - 1))) { + methodCallParenBalance++; if (hasNewLineWithinParensForward(index, formatTokens, formatToken.getId()) && docOptions.wrapMethodCallArgsAfterLeftParen) { indentLine = true; newLines = 1; } } else { + methodCallParenBalance--; + if (methodCallParenBalance > 0 && !lastAnchorTokenStack.isEmpty()) { + lastAnchor = lastAnchorTokenStack.pop(); + } if (hasNewLineWithinParensBackward(index, formatTokens, formatToken.getId()) && docOptions.wrapMethodCallArgsRightParen) { indentLine = true; @@ -1741,6 +1749,9 @@ && countOfNewLines(formatTokens.get(index + 1).getOldText()) > 0) { lastPHPIndent += indentDelta; break; case ANCHOR: + if (methodCallParenBalance > 0 && lastAnchor != null) { + lastAnchorTokenStack.push(lastAnchor); + } lastAnchor = (FormatToken.AnchorToken) formatToken; lastAnchor.setAnchorColumn(column + 1); break; @@ -2156,6 +2167,9 @@ && isAfterLineComment(formatTokens, index - 2)) { } break; case ANCHOR: + if (methodCallParenBalance > 0 && lastAnchor != null) { + lastAnchorTokenStack.push(lastAnchor); + } lastAnchor = (FormatToken.AnchorToken) formatToken; lastAnchor.setAnchorColumn(column); break; @@ -2221,22 +2235,25 @@ && isAfterLineComment(formatTokens, index - 2)) { } delta = replaceString(doc, changeOffset, index, oldText, newText, delta, templateEdit); + // GH-6714 if text have TABs, get incorrect column + // so, use countOfSpaces() instead of newText.length() if (newText == null) { - String formatTokenOldText = formatToken.getOldText() == null ? "" : formatToken.getOldText(); - int formatTokenOldTextLength = formatTokenOldText.length(); + String formatTokenOldText = formatToken.getOldText() == null ? CodeUtils.EMPTY_STRING : formatToken.getOldText(); + int formatTokenOldTextLength = countOfSpaces(formatTokenOldText, docOptions.tabSize); int lines = countOfNewLines(formatTokenOldText); if (lines > 0) { - int lastNewLine = formatTokenOldText.lastIndexOf('\n'); //NOI18N - column = formatTokenOldText.substring(lastNewLine).length(); + int lastNewLine = formatTokenOldText.lastIndexOf(CodeUtils.NEW_LINE); + String substring = formatTokenOldText.substring(lastNewLine); + column = countOfSpaces(substring, docOptions.tabSize); } else { column += formatTokenOldTextLength; } } else { int lines = countOfNewLines(newText); if (lines > 0) { - column = newText.length() - lines; + column = countOfSpaces(newText, docOptions.tabSize) - lines; } else { - column += newText.length(); + column += countOfSpaces(newText, docOptions.tabSize); } } newText = null; diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php new file mode 100644 index 000000000000..360b2991723b --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) + { + nestedCall( + $this->testMethod($arg1), +$this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), +$this->x, + $this->y, + ); + } +} + +array_merge( + $x, +$y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01a.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01a.formatted new file mode 100644 index 000000000000..0138ecf071ab --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01a.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01b.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01b.formatted new file mode 100644 index 000000000000..0138ecf071ab --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithSpaces_01b.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01a.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01a.formatted new file mode 100644 index 000000000000..f2112b53b431 --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01a.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01b.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01b.formatted new file mode 100644 index 000000000000..f2112b53b431 --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_01.php.testGH6714WithTab_01b.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php new file mode 100644 index 000000000000..06c0ef6ee2a7 --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02a.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02a.formatted new file mode 100644 index 000000000000..0138ecf071ab --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02a.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02b.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02b.formatted new file mode 100644 index 000000000000..0138ecf071ab --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithSpaces_02b.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02a.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02a.formatted new file mode 100644 index 000000000000..f2112b53b431 --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02a.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02b.formatted b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02b.formatted new file mode 100644 index 000000000000..f2112b53b431 --- /dev/null +++ b/php/php.editor/test/unit/data/testfiles/formatting/alignment/gh6714_02.php.testGH6714WithTab_02b.formatted @@ -0,0 +1,84 @@ +x, + $this->y, + ); + } + + public function test2( + $param1, + $param2, + $param3, + ) { + nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + return nestedCall( + $this->testMethod($arg1), + $this->x, + $this->y, + ); + } +} + +array_merge( + $x, + $y, +); + +nestedCall( + something( + $arg1, + $arg2, + C::something( + $x, + $y, + $z, + ) + ), + $y, + $z, +); diff --git a/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/indent/PHPFormatterAlignmentTest.java b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/indent/PHPFormatterAlignmentTest.java index e1355767757f..bc8c50c98553 100644 --- a/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/indent/PHPFormatterAlignmentTest.java +++ b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/indent/PHPFormatterAlignmentTest.java @@ -26,10 +26,16 @@ */ public class PHPFormatterAlignmentTest extends PHPFormatterTestBase { + private static final String TEST_DIRECTORY_PATH = "testfiles/formatting/alignment/"; + public PHPFormatterAlignmentTest(String testName) { super(testName); } + private String getTestFilePath(String fileName) { + return TEST_DIRECTORY_PATH + fileName; + } + public void testAlignmentKeywords01() throws Exception { HashMap options = new HashMap(FmtOptions.getDefaults()); options.put(FmtOptions.PLACE_WHILE_ON_NEW_LINE, true); @@ -213,4 +219,100 @@ public void testIssue244566() throws Exception { reformatFileContents("testfiles/formatting/alignment/issue244566.php", options); } + public void testGH6714WithTab_01a() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, true); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, false); + reformatFileContents(getTestFilePath("gh6714_01.php"), options, false, true); + } + + public void testGH6714WithTab_01b() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, false); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, false); + reformatFileContents(getTestFilePath("gh6714_01.php"), options, false, true); + } + + public void testGH6714WithTab_02a() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, true); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, false); + reformatFileContents(getTestFilePath("gh6714_02.php"), options, false, true); + } + + public void testGH6714WithTab_02b() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, false); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, false); + reformatFileContents(getTestFilePath("gh6714_02.php"), options, false, true); + } + + public void testGH6714WithSpaces_01a() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, true); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, true); + reformatFileContents(getTestFilePath("gh6714_01.php"), options, false, true); + } + + public void testGH6714WithSpaces_01b() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, false); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, true); + reformatFileContents(getTestFilePath("gh6714_01.php"), options, false, true); + } + + public void testGH6714WithSpaces_02a() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, true); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, true); + reformatFileContents(getTestFilePath("gh6714_02.php"), options, false, true); + } + + public void testGH6714WithSpaces_02b() throws Exception { + HashMap options = new HashMap<>(FmtOptions.getDefaults()); + options.put(FmtOptions.ALIGN_MULTILINE_CALL_ARGS, false); + options.put(FmtOptions.WRAP_EXTENDS_IMPLEMENTS_LIST, CodeStyle.WrapStyle.WRAP_ALWAYS); + options.put(FmtOptions.ALIGN_MULTILINE_IMPLEMENTS, true); + options.put(FmtOptions.ALIGN_MULTILINE_METHOD_PARAMS, true); + options.put(FmtOptions.TAB_SIZE, 4); + options.put(FmtOptions.CONTINUATION_INDENT_SIZE, 4); + options.put(FmtOptions.EXPAND_TAB_TO_SPACES, true); + reformatFileContents(getTestFilePath("gh6714_02.php"), options, false, true); + } + }