1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-07-24 20:59:02 +02:00

[VIM-1425] Fix % command

Command % worked wrong when
- There was '\\' character on the way
- Inside strings
This commit is contained in:
Alex Plate 2019-04-11 16:09:57 +03:00
parent f6e7019b51
commit d0a39ef32f
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F
2 changed files with 81 additions and 8 deletions
src/com/maddyhome/idea/vim/helper
test/org/jetbrains/plugins/ideavim/action/motion/updown

View File

@ -291,13 +291,14 @@ public class SearchHelper {
int res = -1;
final int inCheckPos = dir < 0 && pos > 0 ? pos - 1 : pos;
boolean inString = checkInString(chars, inCheckPos, true);
boolean initialInString = inString;
boolean inChar = checkInString(chars, inCheckPos, false);
boolean initial = true;
int stack = 0;
// Search to start or end of file, as appropriate
while (pos >= 0 && pos < chars.length() && cnt > 0) {
// If we found a match and we're not in a string...
if (chars.charAt(pos) == match && !inString && !inChar) {
if (chars.charAt(pos) == match && initialInString == inString && !inChar) {
// We found our match
if (stack == 0) {
res = pos;
@ -319,10 +320,10 @@ public class SearchHelper {
stack++;
}
// We found the start/end of a string
else if (!inChar && chars.charAt(pos) == '"' && (pos == 0 || chars.charAt(pos - 1) != '\\')) {
else if (!inChar && isQuoteWithoutEscape(chars, pos, '"')) {
inString = !inString;
}
else if (!inString && chars.charAt(pos) == '\'' && (pos == 0 || chars.charAt(pos - 1) != '\\')) {
else if (!inString && isQuoteWithoutEscape(chars, pos, '\'')) {
inChar = !inChar;
}
}
@ -334,6 +335,24 @@ public class SearchHelper {
return res;
}
/**
* Returns true if [quote] is at this [pos] and it's not escaped (like \")
*/
private static boolean isQuoteWithoutEscape(@NotNull CharSequence chars, int pos, char quote) {
if (chars.charAt(pos) != quote) return false;
int backslashCounter = 0;
while (pos-- > 0) {
if (chars.charAt(pos) == '\\') {
backslashCounter++;
}
else {
break;
}
}
return backslashCounter % 2 == 0;
}
private enum Direction {
BACK(-1), FORWARD(1);
@ -517,10 +536,10 @@ public class SearchHelper {
boolean inString = false;
boolean inChar = false;
for (int i = offset; i <= pos; i++) {
if (!inChar && chars.charAt(i) == '"' && (i == 0 || chars.charAt(i - 1) != '\\')) {
if (!inChar && isQuoteWithoutEscape(chars, i, '"')) {
inString = !inString;
}
else if (!inString && chars.charAt(i) == '\'' && (i == 0 || chars.charAt(i - 1) != '\\')) {
else if (!inString && isQuoteWithoutEscape(chars, i, '\'')) {
inChar = !inChar;
}
}
@ -939,11 +958,10 @@ public class SearchHelper {
else if (hex && ((ch >= '0' && ch <= '9') || "abcdefABCDEF".indexOf(ch) >= 0)) {
return true;
}
else if (decimal && (ch >= '0' && ch <= '9')) {
return true;
else {
return decimal && (ch >= '0' && ch <= '9');
}
return false;
}
/**

View File

@ -132,4 +132,59 @@ class MotionPercentOrMatchActionTest : VimTestCase() {
typeText(parseKeys("%"))
myFixture.checkResult("/* foo <caret> */")
}
fun `test motion with quote on the way`() {
doTest(parseKeys("%"), """
for (; c!= cj;c = it.next()) <caret>{
if (dsa) {
if (c == '\\') {
dsadsakkk
}
}
}
""".trimIndent(),
"""
for (; c!= cj;c = it.next()) {
if (dsa) {
if (c == '\\') {
dsadsakkk
}
}
<caret>}
""".trimIndent())
}
fun `test motion outside text`() {
doTest(parseKeys("%"), """
(
""${'"'}
""${'"'} + <caret>title("Display")
""${'"'}
""${'"'}
)
""".trimIndent(),
"""
(
""${'"'}
""${'"'} + title("Display"<caret>)
""${'"'}
""${'"'}
)
""".trimIndent())
}
fun `test motion in text`() {
doTest(parseKeys("%"), """ "I found <caret>it in a (legendary) land" """,
""" "I found it in a (legendary<caret>) land" """)
}
fun `test motion in text with quotes`() {
doTest(parseKeys("%"), """ "I found <caret>it in \"a (legendary) land" """,
""" "I found it in \"a (legendary<caret>) land" """)
}
fun `test motion in text with quotes and double escape`() {
doTest(parseKeys("%"), """ "I found <caret>it in \\\"a (legendary) land" """,
""" "I found it in \\\"a (legendary<caret>) land" """)
}
}