diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index ab2a222e3d9..b4850596d91 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -586,6 +586,7 @@ + + diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringBackspaceHandler.kt b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringBackspaceHandler.kt new file mode 100644 index 00000000000..60bb29c0ca1 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringBackspaceHandler.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.editor + +import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.RangeMarker +import com.intellij.psi.PsiFile +import com.intellij.psi.util.parentOfType +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtStringTemplateExpression + +class KotlinRawStringBackspaceHandler : BackspaceHandlerDelegate() { + private var rangeMarker: RangeMarker? = null + + override fun beforeCharDeleted(c: Char, file: PsiFile, editor: Editor) { + rangeMarker = null + if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE) { + return + } + if (file !is KtFile) { + return + } + val offset = editor.caretModel.offset + val psiElement = file.findElementAt(offset) ?: return + + psiElement.parentOfType(KtStringTemplateExpression::class)?.let { + if (it.text == "\"\"\"\"\"\"") { + if (editor.caretModel.offset == it.textOffset + 3) { + rangeMarker = editor.document.createRangeMarker(it.textRange) + } + } + } + } + + override fun charDeleted(c: Char, file: PsiFile, editor: Editor): Boolean { + rangeMarker?.let { + editor.document.deleteString(it.startOffset, it.endOffset) + rangeMarker = null + return true + } + return false + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringTypedHandler.kt b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringTypedHandler.kt new file mode 100644 index 00000000000..5b0dcebda58 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinRawStringTypedHandler.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.editor + +import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.codeInsight.editorActions.TypedHandlerDelegate +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileTypes.FileType +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtStringTemplateExpression + +class KotlinRawStringTypedHandler : TypedHandlerDelegate() { + override fun beforeCharTyped(c: Char, project: Project, editor: Editor, file: PsiFile, fileType: FileType): Result { + if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE) { + return Result.CONTINUE + } + if (file !is KtFile) { + return Result.CONTINUE + } + if (c != '"') { + return Result.CONTINUE + } + // A quote is typed after 2 other quotes + val offset = editor.caretModel.offset + // Check for caret at end of document + if (offset < editor.document.textLength) { + val psiElement = file.findElementAt(offset) ?: return Result.CONTINUE + if (PsiTreeUtil.getParentOfType(psiElement, KtStringTemplateExpression::class.java) != null) { + return Result.CONTINUE + } + } + + val text = editor.document.text + if (offset >= 2) + if (text[offset - 1] == '"') + if (text[offset - 2] == '"') { + editor.document.insertString(offset, "\"\"\"\"") + editor.caretModel.currentCaret.moveToOffset(offset + 1) + return Result.STOP + } + + return Result.CONTINUE + } +} \ No newline at end of file diff --git a/idea/testData/editor/backspaceHandler/rawStringDelete.kt b/idea/testData/editor/backspaceHandler/rawStringDelete.kt new file mode 100644 index 00000000000..389cf906644 --- /dev/null +++ b/idea/testData/editor/backspaceHandler/rawStringDelete.kt @@ -0,0 +1 @@ +"\"\"\"\"\"\"" \ No newline at end of file diff --git a/idea/testData/editor/backspaceHandler/rawStringDelete.kt.after b/idea/testData/editor/backspaceHandler/rawStringDelete.kt.after new file mode 100644 index 00000000000..81389d50841 --- /dev/null +++ b/idea/testData/editor/backspaceHandler/rawStringDelete.kt.after @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/TypedHandlerTest.kt b/idea/tests/org/jetbrains/kotlin/idea/editor/TypedHandlerTest.kt index d438d11ab14..70d7d4d0025 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/editor/TypedHandlerTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/TypedHandlerTest.kt @@ -74,6 +74,12 @@ class TypedHandlerTest : LightCodeInsightTestCase() { """val x = "$dollar{}]" """ ) + fun testAutoCloseRawString() = doCharTypeTest( + '"', + """val x = """"", + """val x = ""${'"'}"""${'"'}""" + ) + fun testAutoCloseBraceInFunctionDeclaration() = doCharTypeTest( '{', "fun foo() ",