diff --git a/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java b/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java index 6cfeac5af1cb..10c8c9be41cb 100644 --- a/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java +++ b/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java @@ -221,6 +221,7 @@ public class PyStringLiteralLexer extends LexerBase { if (myBuffer.charAt(i) == '\\') { LOG.assertTrue(myState == AFTER_FIRST_QUOTE); i++; + if (myIsRaw) return i; if (i == myBufferEnd) { myState = AFTER_LAST_QUOTE; return i; @@ -282,7 +283,7 @@ public class PyStringLiteralLexer extends LexerBase { final int quote_limit = myIsTriple ? 3 : 1; int qcnt = 0; // count consequent quotes while (i < myBufferEnd) { // scan to next \something - if (myBuffer.charAt(i) == '\\') { + if (myBuffer.charAt(i) == '\\' && !myIsRaw) { return i; } if (myState == BEFORE_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar) { @@ -292,7 +293,7 @@ public class PyStringLiteralLexer extends LexerBase { qcnt = 0; // for last quote detection in the same pass } } - else if (myState == AFTER_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar) { // done? + else if (myState == AFTER_FIRST_QUOTE && myBuffer.charAt(i) == myQuoteChar && (!myIsRaw || myBuffer.charAt(i-1) != '\\')) { // done? qcnt += 1; if (qcnt == quote_limit) { myState = AFTER_LAST_QUOTE; diff --git a/python/testData/selectWord/escapeSequenceRaw/after1.py b/python/testData/selectWord/escapeSequenceRaw/after1.py new file mode 100644 index 000000000000..cc34c2e72f4e --- /dev/null +++ b/python/testData/selectWord/escapeSequenceRaw/after1.py @@ -0,0 +1 @@ +s = r'Hello\nWorld!' \ No newline at end of file diff --git a/python/testData/selectWord/escapeSequenceRaw/before.py b/python/testData/selectWord/escapeSequenceRaw/before.py new file mode 100644 index 000000000000..7de388ad5996 --- /dev/null +++ b/python/testData/selectWord/escapeSequenceRaw/before.py @@ -0,0 +1 @@ +s = r'Hello\nWorld!' \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PySelectWordTest.java b/python/testSrc/com/jetbrains/python/PySelectWordTest.java index 9321d576a925..0d043332488b 100644 --- a/python/testSrc/com/jetbrains/python/PySelectWordTest.java +++ b/python/testSrc/com/jetbrains/python/PySelectWordTest.java @@ -46,6 +46,10 @@ public class PySelectWordTest extends PyTestCase { doTest(); } + public void testEscapeSequenceRaw() { // PY-10322 + doTest(); + } + private void doTest() { CodeInsightTestUtil.doWordSelectionTestOnDirectory(myFixture, "selectWord/" + getTestName(true), "py"); } diff --git a/python/testSrc/com/jetbrains/python/PyStringLiteralLexerTest.java b/python/testSrc/com/jetbrains/python/PyStringLiteralLexerTest.java index 037eef11427e..100f84988709 100644 --- a/python/testSrc/com/jetbrains/python/PyStringLiteralLexerTest.java +++ b/python/testSrc/com/jetbrains/python/PyStringLiteralLexerTest.java @@ -26,4 +26,9 @@ public class PyStringLiteralLexerTest extends PyLexerTestCase { PyLexerTestCase.doLexerTest("u\"\\N{LATIN SMALL LETTER B}\"", new PyStringLiteralLexer(PyTokenTypes.SINGLE_QUOTED_UNICODE), "Py:SINGLE_QUOTED_UNICODE", "VALID_STRING_ESCAPE_TOKEN", "Py:SINGLE_QUOTED_UNICODE"); } + + public void testRawBackslashN() { + PyLexerTestCase.doLexerTest("r'[\\w\\']'", new PyStringLiteralLexer(PyTokenTypes.SINGLE_QUOTED_STRING), true, + "r'[\\w\\']'"); + } } diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyLexerTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyLexerTestCase.java index 4ce5e3516364..aa6fc8af0ab4 100644 --- a/python/testSrc/com/jetbrains/python/fixtures/PyLexerTestCase.java +++ b/python/testSrc/com/jetbrains/python/fixtures/PyLexerTestCase.java @@ -35,6 +35,13 @@ public abstract class PyLexerTestCase extends PlatformLiteFixture { } public static void doLexerTest(String text, Lexer lexer, String... expectedTokens) { + doLexerTest(text, lexer, false, expectedTokens); + } + + public static void doLexerTest(String text, + Lexer lexer, + boolean checkTokenText, + String... expectedTokens) { lexer.start(text); int idx = 0; int tokenPos = 0; @@ -44,13 +51,13 @@ public abstract class PyLexerTestCase extends PlatformLiteFixture { lexer.advance(); while (lexer.getTokenType() != null) { remainingTokens.append(","); - remainingTokens.append(" \"").append(lexer.getTokenType().toString()).append("\""); + remainingTokens.append(" \"").append(checkTokenText ? lexer.getTokenText() : lexer.getTokenType().toString()).append("\""); lexer.advance(); } fail("Too many tokens. Following tokens: " + remainingTokens.toString()); } assertEquals("Token offset mismatch at position " + idx, tokenPos, lexer.getTokenStart()); - String tokenName = lexer.getTokenType().toString(); + String tokenName = checkTokenText ? lexer.getTokenText() : lexer.getTokenType().toString(); assertEquals("Token mismatch at position " + idx, expectedTokens[idx], tokenName); idx++; tokenPos = lexer.getTokenEnd();