mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 05:51:25 +07:00
PY-80844 Add a new intention for converting between f-strings and t-strings
GitOrigin-RevId: be3ab4d72de05a92c986af31ac8e40309d9754b1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b8c67616f1
commit
f41aae4760
@@ -1,4 +1,4 @@
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="intellij.python.psi"/>
|
||||
</dependencies>
|
||||
@@ -387,6 +387,12 @@
|
||||
<categoryKey>INTN.category.python</categoryKey>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>com.jetbrains.python.codeInsight.intentions.PyFStringToTStringIntention</className>
|
||||
<bundleName>messages.PyPsiBundle</bundleName>
|
||||
<categoryKey>INTN.category.python</categoryKey>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>com.jetbrains.python.codeInsight.intentions.PyConvertLambdaToFunctionIntention</className>
|
||||
<bundleName>messages.PyPsiBundle</bundleName>
|
||||
@@ -603,4 +609,4 @@
|
||||
<pythonHelpersLocator implementation="com.jetbrains.python.PythonHelpersLocatorDefault" />
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
t"""<span">{content}</span>"""
|
||||
@@ -0,0 +1 @@
|
||||
f"""<span">{content}</span>"""
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<span>
|
||||
Converts between f-strings and t-strings (<a href="https://peps.python.org/pep-0750/">PEP-750</a>).
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
||||
@@ -342,6 +342,11 @@ INTN.convert.absolute.to.relative=Convert absolute import to relative
|
||||
#PyInvertIfConditionIntention
|
||||
INTN.invert.if.condition=Invert 'if' condition
|
||||
|
||||
# PyFStringToTStringIntention
|
||||
INTN.NAME.convert.between.f.string.t.string=Convert between f-string and t-string
|
||||
INTN.convert.f.string.to.t.string=Convert f-string to t-string
|
||||
INTN.convert.t.string.to.f.string=Convert t-string to f-string
|
||||
|
||||
### Quick-fixes ###
|
||||
QFIX.add.qualifier=Add qualifier
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.codeInsight.intentions
|
||||
|
||||
import com.intellij.modcommand.ActionContext
|
||||
import com.intellij.modcommand.ModPsiUpdater
|
||||
import com.intellij.modcommand.Presentation
|
||||
import com.intellij.modcommand.PsiUpdateModCommandAction
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
import com.jetbrains.python.psi.PyDocStringOwner
|
||||
import com.jetbrains.python.psi.PyFormattedStringElement
|
||||
import com.jetbrains.python.psi.PyStringLiteralExpression
|
||||
import com.jetbrains.python.psi.PyUtil
|
||||
|
||||
/**
|
||||
* Intention to convert between f-strings and t-strings (PEP-750)
|
||||
*/
|
||||
class PyFStringToTStringIntention : PsiUpdateModCommandAction<PyFormattedStringElement>(PyFormattedStringElement::class.java) {
|
||||
override fun getPresentation(context: ActionContext, stringElement: PyFormattedStringElement): Presentation? {
|
||||
val stringLiteral = stringElement.getParent() as? PyStringLiteralExpression ?: return null
|
||||
val docStringOwner = stringLiteral.parentOfType<PyDocStringOwner>()
|
||||
if (docStringOwner != null && docStringOwner.getDocStringExpression() === stringLiteral) return null
|
||||
|
||||
if (stringElement.isFormatted) {
|
||||
return Presentation.of(PyPsiBundle.message("INTN.convert.f.string.to.t.string"))
|
||||
}
|
||||
else if (stringElement.isTemplate) {
|
||||
return Presentation.of(PyPsiBundle.message("INTN.convert.t.string.to.f.string"))
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String = PyPsiBundle.message("INTN.NAME.convert.between.f.string.t.string")
|
||||
|
||||
override fun invoke(context: ActionContext, stringElement: PyFormattedStringElement, updater: ModPsiUpdater) {
|
||||
val prefixOffset = stringElement.textOffset
|
||||
val oldPrefix = stringElement.prefix
|
||||
val newPrefix = when {
|
||||
oldPrefix.contains("f") || oldPrefix.contains("F") -> oldPrefix.replace("f", "t").replace("F", "T")
|
||||
oldPrefix.contains("t") || oldPrefix.contains("T") -> oldPrefix.replace("t", "f").replace("T", "F")
|
||||
else -> return
|
||||
}
|
||||
PyUtil.updateDocumentUnblockedAndCommitted(stringElement) { document: Document ->
|
||||
document.replaceString(prefixOffset, prefixOffset + oldPrefix.length, newPrefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class MyClass:
|
||||
f"""This <caret>is a docstring with an f-prefix.
|
||||
It should not be convertible to a t-string because it's a docstring.
|
||||
"""
|
||||
@@ -0,0 +1 @@
|
||||
s = t"This is a f-string with an {f"emb<caret>edded {value} f-string"}"
|
||||
@@ -0,0 +1 @@
|
||||
s = t"This is a f-string with an {t"emb<caret>edded {value} f-string"}"
|
||||
@@ -0,0 +1,4 @@
|
||||
s = f"""<caret>
|
||||
This is a multiline string with {variable1}
|
||||
and another {variable2} on a different line.
|
||||
"""
|
||||
@@ -0,0 +1,4 @@
|
||||
s = t"""<caret>
|
||||
This is a multiline string with {variable1}
|
||||
and another {variable2} on a different line.
|
||||
"""
|
||||
@@ -0,0 +1 @@
|
||||
s = rf"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = rt"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = "<caret>This is a regular string without any prefix"
|
||||
@@ -0,0 +1 @@
|
||||
s = f"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = t"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = t"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = f"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = F"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1 @@
|
||||
s = T"Hel<caret>lo, {name}!"
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.intentions;
|
||||
|
||||
import com.jetbrains.python.PyPsiBundle;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
|
||||
/**
|
||||
* Tests for PyFStringToTStringIntention
|
||||
*/
|
||||
public class PyFStringToTStringIntentionTest extends PyIntentionTestCase {
|
||||
public void testSimpleFString() {
|
||||
doFStringToTStringTest();
|
||||
}
|
||||
|
||||
public void testMultilineFString() {
|
||||
doFStringToTStringTest();
|
||||
}
|
||||
|
||||
public void testFStringInsideTString() {
|
||||
doFStringToTStringTest();
|
||||
}
|
||||
|
||||
public void testSimpleTString() {
|
||||
doTStringToFStringTest();
|
||||
}
|
||||
|
||||
public void testRegularString() {
|
||||
doNegativeTest();
|
||||
}
|
||||
|
||||
public void testDocString() {
|
||||
doNegativeTest();
|
||||
}
|
||||
|
||||
public void testRawFString() {
|
||||
doFStringToTStringTest();
|
||||
}
|
||||
|
||||
public void testUppercaseFStringPrefix() {
|
||||
doFStringToTStringTest();
|
||||
}
|
||||
|
||||
private void doFStringToTStringTest() {
|
||||
doTest(PyPsiBundle.message("INTN.convert.f.string.to.t.string"), LanguageLevel.getLatest());
|
||||
}
|
||||
|
||||
private void doTStringToFStringTest() {
|
||||
doTest(PyPsiBundle.message("INTN.convert.t.string.to.f.string"), LanguageLevel.getLatest());
|
||||
}
|
||||
|
||||
private void doNegativeTest() {
|
||||
runWithLanguageLevel(LanguageLevel.getLatest(), () -> doNegativeTest(PyPsiBundle.message("INTN.convert.f.string.to.t.string")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user