Repository: hannah-sten/texify-idea
Issue: reference after punctuation

#### Type of JetBrains IDE (IntelliJ, PyCharm, etc.) and version
IntelliJ IDEA 2023.1.3 (Ultimate Edition)
Build #IU-231.9161.38, built on June 20, 2023


#### Operating System 
Windows 11 Pro
22H2


#### TeXiFy IDEA version
0.7.30


#### What I did (steps to reproduce)
Use a reference command (\\cite, \\ref,...) after a punctiuation, e.g. at the beginning of a sentence yields a "Reference without a non-breaking space" warning.
Regardless of whether this is good linguistic style, I think the warning is wrong in these places.


#### Minimal example to reproduce the problem
![grafik](https://github.com/Hannah-Sten/TeXiFy-IDEA/assets/24541714/7a58902d-2dd4-4ff9-908a-6f8e869ee2e3)


#### Expected behavior
No "Reference without a non-breaking space" warning after punctuation.



Changed files:
src/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspection.kt
test/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspectionTest.kt

diff --git a/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspection.kt b/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspection.kt
index 771b112c8..221ba1150 100644
--- a/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspection.kt
+++ b/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspection.kt
@@ -7,6 +7,8 @@ import com.intellij.codeInspection.ProblemHighlightType
 import com.intellij.openapi.project.Project
 import com.intellij.psi.PsiFile
 import com.intellij.psi.PsiWhiteSpace
+import com.intellij.refactoring.suggested.endOffset
+import com.intellij.refactoring.suggested.startOffset
 import nl.hannahsten.texifyidea.inspections.InsightGroup
 import nl.hannahsten.texifyidea.inspections.TexifyInspectionBase
 import nl.hannahsten.texifyidea.lang.LatexPackage
@@ -14,12 +16,14 @@ import nl.hannahsten.texifyidea.lang.commands.LatexGenericRegularCommand.*
 import nl.hannahsten.texifyidea.lang.magic.MagicCommentScope
 import nl.hannahsten.texifyidea.psi.LatexNoMathContent
 import nl.hannahsten.texifyidea.psi.LatexNormalText
-import nl.hannahsten.texifyidea.util.parser.childrenOfType
+import nl.hannahsten.texifyidea.psi.LatexParameterText
 import nl.hannahsten.texifyidea.util.files.commandsInFile
 import nl.hannahsten.texifyidea.util.files.document
 import nl.hannahsten.texifyidea.util.includedPackages
 import nl.hannahsten.texifyidea.util.magic.CommandMagic
 import nl.hannahsten.texifyidea.util.magic.PatternMagic
+import nl.hannahsten.texifyidea.util.parser.childrenOfType
+import nl.hannahsten.texifyidea.util.parser.lastChildOfType
 import nl.hannahsten.texifyidea.util.parser.parentOfType
 import java.util.*
 
@@ -36,7 +40,17 @@ open class LatexNonBreakingSpaceInspection : TexifyInspectionBase() {
          * All commands that should not have a forced breaking space.
          */
         val IGNORED_COMMANDS = setOf(
-            "\\\\citet", "\\\\citet*", "\\\\Citet", "\\\\Citet*", "\\\\cref", "\\\\Cref", "\\\\cpageref", "\\\\autoref", "\\\\citeauthor", "\\\\textcite", "\\\\Textcite"
+            "\\\\citet",
+            "\\\\citet*",
+            "\\\\Citet",
+            "\\\\Citet*",
+            "\\\\cref",
+            "\\\\Cref",
+            "\\\\cpageref",
+            "\\\\autoref",
+            "\\\\citeauthor",
+            "\\\\textcite",
+            "\\\\Textcite"
         )
 
         /**
@@ -74,17 +88,25 @@ open class LatexNonBreakingSpaceInspection : TexifyInspectionBase() {
                 ?: command.parentOfType(LatexNoMathContent::class)?.prevSibling
                 ?: continue
 
-            // When sibling is whitespace, it's obviously bad news.
+            val previousSentence = sibling.prevSibling
+                ?: sibling.parent?.prevSibling
+                ?: sibling.parentOfType(LatexNoMathContent::class)?.prevSibling
+                ?: continue
+
+            // When sibling is whitespace, it's obviously bad news. Must not have a newline
             if (sibling is PsiWhiteSpace) {
-                descriptors.add(
-                    manager.createProblemDescriptor(
-                        sibling,
-                        "Reference without a non-breaking space",
-                        WhitespaceReplacementFix(),
-                        ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
-                        isOntheFly
+                val lastBitOfText = previousSentence.lastChildOfType(LatexNormalText::class) ?: previousSentence.lastChildOfType(LatexParameterText::class) ?: continue
+                if (!PatternMagic.sentenceSeparatorAtLineEnd.matcher(file.text.subSequence(lastBitOfText.startOffset, lastBitOfText.endOffset)).find()) {
+                    descriptors.add(
+                        manager.createProblemDescriptor(
+                            sibling,
+                            "Reference without a non-breaking space",
+                            WhitespaceReplacementFix(),
+                            ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+                            isOntheFly
+                        )
                     )
-                )
+                }
                 continue
             }
         }
diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspectionTest.kt
index e02e5b249..f92a09909 100644
--- a/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspectionTest.kt
+++ b/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/spacing/LatexNonBreakingSpaceInspectionTest.kt
@@ -16,6 +16,82 @@ class LatexNonBreakingSpaceInspectionTest : TexifyInspectionTestBase(LatexNonBre
         myFixture.checkHighlighting()
     }
 
+    fun testWarningNewline() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                Reference<warning descr="Reference without a non-breaking space">
+                </warning>\\ref{fig}
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testNoWarningNewlineSentence() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                Reference.
+                \\ref{fig}
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testNoWarningNewLineSentenceEnd() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                Reference. \\ref{fig}
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testWarningAfterMathContext() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                Reference ${"$"}math$<warning descr="Reference without a non-breaking space"> </warning>\\ref{fig}.
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testNoWarningAfterEnvironment() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                \\begin{center}
+                    Something centered.
+                \\end{center}
+                \\ref{blub} Starts a new sentence.
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testNoWarningAfterComment() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                % Hello World
+                \\ref{blub} This is science.
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
+    fun testWarningAfterTextModifier() {
+        myFixture.configureByText(
+            LatexFileType,
+            """
+                \\textit{Hello}<warning descr="Reference without a non-breaking space"> </warning>\\ref{blub} world.
+            """.trimIndent()
+        )
+        myFixture.checkHighlighting()
+    }
+
     fun testNoWarning() {
         myFixture.configureByText(
             LatexFileType,