mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-31442 Support splitting of simple f-strings on enter
This commit is contained in:
@@ -99,11 +99,12 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
final Document doc = editor.getDocument();
|
||||
PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
|
||||
final PsiElement element = file.findElementAt(offset);
|
||||
final PsiElement prevElement = offset > 0 ? file.findElementAt(offset - 1) : null;
|
||||
CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
|
||||
if (codeInsightSettings.JAVADOC_STUB_ON_ENTER) {
|
||||
PsiElement comment = element;
|
||||
if (comment == null && offset != 0) {
|
||||
comment = file.findElementAt(offset - 1);
|
||||
comment = prevElement;
|
||||
}
|
||||
int expectedStringStart = editor.getCaretModel().getOffset() - 3; // """ or '''
|
||||
if (comment != null) {
|
||||
@@ -119,65 +120,60 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
return Result.Continue;
|
||||
}
|
||||
|
||||
final ASTNode node = element.getNode();
|
||||
PsiElement elementParent = element.getParent();
|
||||
if (element.getNode().getElementType() == PyTokenTypes.LPAR) elementParent = elementParent.getParent();
|
||||
if (node.getElementType() == PyTokenTypes.LPAR) elementParent = elementParent.getParent();
|
||||
if (elementParent instanceof PyParenthesizedExpression || elementParent instanceof PyGeneratorExpression) return Result.Continue;
|
||||
|
||||
if (offset > 0 && !(PyTokenTypes.STRING_NODES.contains(element.getNode().getElementType()))) {
|
||||
final PsiElement prevElement = file.findElementAt(offset - 1);
|
||||
if (prevElement == element) return Result.Continue;
|
||||
}
|
||||
|
||||
if (PyTokenTypes.TRIPLE_NODES.contains(element.getNode().getElementType()) ||
|
||||
element.getNode().getElementType() == PyTokenTypes.DOCSTRING) {
|
||||
final PyStringElement stringElement = PsiTreeUtil.getParentOfType(element, PyStringElement.class, false);
|
||||
if (stringElement == null && prevElement == element) {
|
||||
return Result.Continue;
|
||||
}
|
||||
|
||||
final PsiElement prevElement = file.findElementAt(offset - 1);
|
||||
PyStringLiteralExpression string = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PyStringLiteralExpression.class, false);
|
||||
|
||||
if (string != null && prevElement != null && PyTokenTypes.STRING_NODES.contains(prevElement.getNode().getElementType())
|
||||
&& string.getTextOffset() < offset && !(element.getNode() instanceof PsiWhiteSpace)) {
|
||||
final String stringText = element.getText();
|
||||
final int prefixLength = PyStringLiteralUtil.getPrefixLength(stringText);
|
||||
if (string.getTextOffset() + prefixLength >= offset) {
|
||||
|
||||
if (stringElement != null && (!stringElement.isFormatted() || node.getElementType() == PyTokenTypes.FSTRING_TEXT)) {
|
||||
if (stringElement.isTripleQuoted() || node.getElementType() == PyTokenTypes.DOCSTRING) {
|
||||
return Result.Continue;
|
||||
}
|
||||
final String pref = element.getText().substring(0, prefixLength);
|
||||
final String quote = element.getText().substring(prefixLength, prefixLength + 1);
|
||||
|
||||
// Don't split in the middle of an escape sequence
|
||||
final boolean nextIsBackslash = "\\".equals(doc.getText(TextRange.from(offset - 1, 1)));
|
||||
final boolean isEscapedQuote = quote.equals(doc.getText(TextRange.from(offset, 1))) && nextIsBackslash;
|
||||
final boolean isEscapedBackslash = "\\".equals(doc.getText(TextRange.from(offset - 2, 1))) && nextIsBackslash;
|
||||
if (nextIsBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;
|
||||
if (prevElement != null && PsiTreeUtil.isAncestor(stringElement, prevElement, false)) {
|
||||
|
||||
if (stringElement.getTextOffset() + stringElement.getPrefixLength() >= offset) {
|
||||
return Result.Continue;
|
||||
}
|
||||
final String pref = stringElement.getPrefix();
|
||||
final String quote = stringElement.getQuote();
|
||||
|
||||
myPostprocessShift = prefixLength + quote.length();
|
||||
// Don't split in the middle of an escape sequence
|
||||
final boolean nextIsBackslash = "\\".equals(doc.getText(TextRange.from(offset - 1, 1)));
|
||||
final boolean isEscapedQuote = quote.equals(doc.getText(TextRange.from(offset, 1))) && nextIsBackslash;
|
||||
final boolean isEscapedBackslash = "\\".equals(doc.getText(TextRange.from(offset - 2, 1))) && nextIsBackslash;
|
||||
if (nextIsBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;
|
||||
|
||||
if (PsiTreeUtil.getParentOfType(string, IMPLICIT_WRAP_CLASSES) != null) {
|
||||
final StringBuilder replacementString = new StringBuilder();
|
||||
replacementString.append(quote).append(pref).append(quote);
|
||||
doc.insertString(offset, replacementString);
|
||||
caretOffset.set(caretOffset.get() + 1);
|
||||
return Result.Continue;
|
||||
}
|
||||
else {
|
||||
final StringBuilder replacementString = new StringBuilder();
|
||||
if (isEscapedQuote) {
|
||||
replacementString.append(quote);
|
||||
myPostprocessShift = pref.length() + quote.length();
|
||||
|
||||
if (PsiTreeUtil.getParentOfType(stringElement, IMPLICIT_WRAP_CLASSES) != null) {
|
||||
final StringBuilder replacementString = new StringBuilder();
|
||||
replacementString.append(quote).append(pref).append(quote);
|
||||
doc.insertString(offset, replacementString);
|
||||
caretOffset.set(caretOffset.get() + 1);
|
||||
return Result.Continue;
|
||||
}
|
||||
replacementString.append(quote).append(" \\").append(pref);
|
||||
if (!isEscapedQuote) {
|
||||
replacementString.append(quote);
|
||||
else {
|
||||
final StringBuilder replacementString = new StringBuilder();
|
||||
if (isEscapedQuote) {
|
||||
replacementString.append(quote);
|
||||
caretOffset.set(caretOffset.get() + 1);
|
||||
}
|
||||
replacementString.append(quote).append(" \\").append(pref);
|
||||
if (!isEscapedQuote) {
|
||||
replacementString.append(quote);
|
||||
}
|
||||
doc.insertString(offset, replacementString);
|
||||
caretOffset.set(caretOffset.get() + 3);
|
||||
return Result.Continue;
|
||||
}
|
||||
doc.insertString(offset, replacementString);
|
||||
caretOffset.set(caretOffset.get() + 3);
|
||||
return Result.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!PyCodeInsightSettings.getInstance().INSERT_BACKSLASH_ON_WRAP) {
|
||||
return Result.Continue;
|
||||
}
|
||||
|
||||
@@ -103,12 +103,23 @@ public class PyEditingTest extends PyTestCase {
|
||||
assertEquals("f'{}'", doTestTyping("f''", 2, '{'));
|
||||
}
|
||||
|
||||
public void testEnterInFStringFragment() {
|
||||
public void testEnterInMultilineFStringFragment() {
|
||||
doTestEnter("f'''{1 +<caret> 2}'''",
|
||||
"f'''{1 +\n" +
|
||||
" 2}'''");
|
||||
}
|
||||
|
||||
public void testEnterInSingleLineFStringFragment() {
|
||||
doTestEnter("f'foo{1 +<caret> 2}bar'",
|
||||
"f'foo{1 +\n" +
|
||||
"2}bar'");
|
||||
}
|
||||
|
||||
public void testEnterInFStringTextPart() {
|
||||
doTestEnter("f'foo<caret>bar'", "f'foo' \\\n" +
|
||||
" f'bar'");
|
||||
}
|
||||
|
||||
public void testOvertypeFromInside() {
|
||||
assertEquals("''", doTestTyping("''", 1, '\''));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user