[python] PY-36230 fix duplicate "at" in live decorator template

GitOrigin-RevId: f69aae360eac73da13c313d84be8890c3f758cf5
This commit is contained in:
Azim Akhmadjonov
2025-10-22 10:43:29 +00:00
committed by intellij-monorepo-bot
parent abe801075b
commit 460b260c93
3 changed files with 46 additions and 0 deletions
@@ -278,6 +278,7 @@
implementation="com.jetbrains.python.codeInsight.liveTemplates.PythonTemplateContextType$Class"/>
<liveTemplateContext contextId="Python_Top_Level" baseContextId="Python"
implementation="com.jetbrains.python.codeInsight.liveTemplates.PythonTemplateContextType$TopLevel"/>
<liveTemplatePreprocessor implementation="com.jetbrains.python.codeInsight.liveTemplates.PyDecoratorTemplatePreprocessor"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.CollectionElementNameMacro"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.PyClassNameMacro"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.PyFunctionNameMacro"/>
@@ -0,0 +1,31 @@
// 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.codeInsight.liveTemplates
import com.intellij.codeInsight.template.impl.TemplatePreprocessor
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
import com.intellij.util.text.CharArrayUtil
class PyDecoratorTemplatePreprocessor : TemplatePreprocessor {
override fun preprocessTemplate(editor: Editor, file: PsiFile, caretOffset: Int, textToInsert: String, templateText: String) {
if (!templateText.startsWith('@')) {
return
}
val document: Document = editor.getDocument()
if (caretOffset <= 0) {
return
}
val text: CharSequence = document.charsSequence
val checkPos = CharArrayUtil.shiftBackward(text, caretOffset - 1, " \t")
if (checkPos >= 0 && text[checkPos] == '@') {
WriteAction.run<RuntimeException> {
document.deleteString(checkPos, checkPos + 1)
}
}
}
}
@@ -85,6 +85,20 @@ public class PyLiveTemplatesExpandingTest extends PyTestCase {
});
}
// PY-36230
public void testPropertyDecoratorNoDuplicate() {
myFixture.configureByText("a.py", "class MyClass:\n @prop<caret>");
myFixture.type("\t");
myFixture.checkResult("class MyClass:\n @property\n def <caret>(self):\n return ");
}
// PY-36230
public void testPropertyDecoratorNoAtSymbol() {
myFixture.configureByText("a.py", "class MyClass:\n prop<caret>");
myFixture.type("\t");
myFixture.checkResult("class MyClass:\n @property\n def <caret>(self):\n return ");
}
// PY-41231
public void testIterableVariableWithTypeAnnotation() {
doMultiFileTest();