Skip to content

Commit

Permalink
Improve quote insert handler, fixes #1425 (#1429)
Browse files Browse the repository at this point in the history
  • Loading branch information
PHPirates authored May 19, 2020
1 parent 7eb6dab commit 6b8cdc4
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
16 changes: 14 additions & 2 deletions src/nl/hannahsten/texifyidea/editor/LatexQuoteInsertHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import nl.hannahsten.texifyidea.lang.LatexRegularCommand
import nl.hannahsten.texifyidea.settings.TexifySettings
import nl.hannahsten.texifyidea.util.getOpenAndCloseQuotes
import nl.hannahsten.texifyidea.util.insertUsepackage
import kotlin.math.min

/**
* This class performs smart quote substitution. When this is enabled, it will replace double quotes " and single quotes ' with the appropriate LaTeX symbols.
Expand All @@ -37,7 +38,7 @@ open class LatexQuoteInsertHandler : TypedHandlerDelegate() {
}

// Check if we are not out of the document range
if (offset - 1 < 0 || offset + 1 >= document.textLength) {
if (offset - 1 < 0 || offset - 1 >= document.textLength) {
return super.charTyped(char, project, editor, file)
}

Expand Down Expand Up @@ -68,6 +69,11 @@ open class LatexQuoteInsertHandler : TypedHandlerDelegate() {
// Character before the cursor
val previousChar = document.getText(TextRange.from(offset - 2, 1))

// Don't replace when trying to type an escaped quote \"
if (previousChar == "\\") {
return
}

// Assume that if the previous char is a space, we are not closing anything
if (previousChar == " ") {
isOpeningQuotes = true
Expand All @@ -77,6 +83,12 @@ open class LatexQuoteInsertHandler : TypedHandlerDelegate() {
if (previousChar == "{" || previousChar == "[" || previousChar == "(") {
isOpeningQuotes = true
}

// If we are not closing the command, assume we are opening it (instead of doing nothing)
if (TexifySettings.getInstance().automaticQuoteReplacement == TexifySettings.QuoteReplacement.CSQUOTES
&& document.getText(TextRange.from(min(offset, document.textLength - 1), 1)) != "}") {
isOpeningQuotes = true
}
}

val replacement = if (isOpeningQuotes) openingQuotes else closingQuotes
Expand All @@ -86,7 +98,7 @@ open class LatexQuoteInsertHandler : TypedHandlerDelegate() {
document.insertString(offset - 1, replacement)

// Move the cursor behind the replacement which replaced the typed char
caret.moveToOffset(offset + replacement.length - 1)
caret.moveToOffset(min(offset + replacement.length - 1, document.textLength))

handleCsquotesInsertion(document, file, isOpeningQuotes, caret, char)
}
Expand Down
12 changes: 11 additions & 1 deletion src/nl/hannahsten/texifyidea/util/Packages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ package nl.hannahsten.texifyidea.util

import com.intellij.openapi.progress.Task
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import nl.hannahsten.texifyidea.lang.Package
import nl.hannahsten.texifyidea.psi.LatexCommands
import nl.hannahsten.texifyidea.psi.LatexPsiHelper
import nl.hannahsten.texifyidea.settings.TexifySettings
import nl.hannahsten.texifyidea.util.files.*
import nl.hannahsten.texifyidea.util.files.commandsInFile
import nl.hannahsten.texifyidea.util.files.commandsInFileSet
import nl.hannahsten.texifyidea.util.files.document
import nl.hannahsten.texifyidea.util.files.findRootFile
import nl.hannahsten.texifyidea.util.files.isClassFile
import nl.hannahsten.texifyidea.util.files.isStyleFile

/**
* @author Hannah Schellekens
Expand Down Expand Up @@ -101,8 +107,12 @@ object PackageUtils {

val newNode = LatexPsiHelper(file.project).createFromText(command).firstChild.node

// https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/modifying_psi.html?search=refac#combining-psi-and-document-modifications
// Avoid 'Write access is allowed inside write-action only" exception
runWriteAction {
// Avoid "Attempt to modify PSI for non-committed Document"
PsiDocumentManager.getInstance(file.project).doPostponedOperationsAndUnblockDocument(file.document() ?: return@runWriteAction)
PsiDocumentManager.getInstance(file.project).commitDocument(file.document() ?: return@runWriteAction)
if (anchorAfter != null) {
val anchorBefore = anchorAfter.node.treeNext
if (prependNewLine) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package nl.hannahsten.texifyidea.editor

import com.intellij.testFramework.fixtures.BasePlatformTestCase
import nl.hannahsten.texifyidea.file.LatexFileType
import nl.hannahsten.texifyidea.settings.TexifySettings

class LatexQuoteInsertHandlerTest : BasePlatformTestCase() {

fun testCsquotes() {
myFixture.configureByText(LatexFileType, """Typing <caret> test""")
TexifySettings.getInstance().automaticQuoteReplacement = TexifySettings.QuoteReplacement.CSQUOTES
myFixture.type("\"")
myFixture.checkResult("""\usepackage{csquotes}Typing \enquote{<caret>} test""")
myFixture.type("quote\"")
myFixture.checkResult("""\usepackage{csquotes}Typing \enquote{quote}<caret> test""")
}

fun testCsquotesInWord() {
myFixture.configureByText(LatexFileType, """Typ<caret>ing test""")
TexifySettings.getInstance().automaticQuoteReplacement = TexifySettings.QuoteReplacement.CSQUOTES
myFixture.type("\"")
myFixture.checkResult("""\usepackage{csquotes}Typ\enquote{<caret>}ing test""")
}

fun testCsquotesEndOfLine() {
myFixture.configureByText(LatexFileType, """Typing <caret>""")
TexifySettings.getInstance().automaticQuoteReplacement = TexifySettings.QuoteReplacement.CSQUOTES
myFixture.type("\"")
myFixture.checkResult("""\usepackage{csquotes}Typing \enquote{<caret>}""")
}

fun testEscapedQuotes() {
myFixture.configureByText(LatexFileType, """Typing \<caret>""")
TexifySettings.getInstance().automaticQuoteReplacement = TexifySettings.QuoteReplacement.LIGATURES
myFixture.type("\"")
myFixture.checkResult("""Typing \"""")
}
}

0 comments on commit 6b8cdc4

Please sign in to comment.