diff --git a/changelog.xml b/changelog.xml index d15076a..5eec44e 100644 --- a/changelog.xml +++ b/changelog.xml @@ -16,6 +16,9 @@ Add support for strikethrough as in [GitHub Flavored Markdown](https://github.github.com/gfm/#strikethrough-extension-) + + Always check selected text when running [`_ltex.checkDocument`](https://valentjn.github.io/ltex/ltex-ls/server-usage.html#_ltexcheckdocument-server), even non-comment parts of programs + diff --git a/src/main/kotlin/org/bsplines/ltexls/server/DocumentChecker.kt b/src/main/kotlin/org/bsplines/ltexls/server/DocumentChecker.kt index 31b26c0..732cc68 100644 --- a/src/main/kotlin/org/bsplines/ltexls/server/DocumentChecker.kt +++ b/src/main/kotlin/org/bsplines/ltexls/server/DocumentChecker.kt @@ -14,6 +14,8 @@ import org.bsplines.ltexls.parsing.AnnotatedTextFragment import org.bsplines.ltexls.parsing.CodeAnnotatedTextBuilder import org.bsplines.ltexls.parsing.CodeFragment import org.bsplines.ltexls.parsing.CodeFragmentizer +import org.bsplines.ltexls.parsing.plaintext.PlaintextAnnotatedTextBuilder +import org.bsplines.ltexls.parsing.program.ProgramCommentRegexs import org.bsplines.ltexls.settings.HiddenFalsePositive import org.bsplines.ltexls.settings.Settings import org.bsplines.ltexls.settings.SettingsManager @@ -39,7 +41,7 @@ class DocumentChecker( private fun fragmentizeDocument( document: LtexTextDocumentItem, - range: Range?, + range: Range? = null, ): List { val codeFragmentizer: CodeFragmentizer = CodeFragmentizer.create(document.languageId) var code: String = document.text @@ -57,12 +59,19 @@ class DocumentChecker( private fun buildAnnotatedTextFragments( codeFragments: List, document: LtexTextDocumentItem, + hasRange: Boolean = false, ): List { val annotatedTextFragments = ArrayList() for (codeFragment: CodeFragment in codeFragments) { - val builder: CodeAnnotatedTextBuilder = - CodeAnnotatedTextBuilder.create(codeFragment.codeLanguageId) + val builder: CodeAnnotatedTextBuilder = if ( + hasRange && ProgramCommentRegexs.isSupportedCodeLanguageId(codeFragment.codeLanguageId) + ) { + PlaintextAnnotatedTextBuilder(codeFragment.codeLanguageId) + } else { + CodeAnnotatedTextBuilder.create(codeFragment.codeLanguageId) + } + builder.setSettings(codeFragment.settings) builder.addCode(codeFragment.code) val curAnnotatedText: AnnotatedText = builder.build() @@ -74,12 +83,12 @@ class DocumentChecker( private fun checkAnnotatedTextFragments( annotatedTextFragments: List, - rangeOffset: Int, + rangeStartPos: Int? = null, ): List { val matches = ArrayList() for (annotatedTextFragment: AnnotatedTextFragment in annotatedTextFragments) { - matches.addAll(checkAnnotatedTextFragment(annotatedTextFragment, rangeOffset)) + matches.addAll(checkAnnotatedTextFragment(annotatedTextFragment, rangeStartPos)) } return matches @@ -88,7 +97,7 @@ class DocumentChecker( @Suppress("TooGenericExceptionCaught") private fun checkAnnotatedTextFragment( annotatedTextFragment: AnnotatedTextFragment, - rangeOffset: Int, + rangeStartPos: Int? = null, ): List { val codeFragment: CodeFragment = annotatedTextFragment.codeFragment var settings: Settings = codeFragment.settings @@ -115,8 +124,7 @@ class DocumentChecker( val codeLanguageId: String = codeFragment.codeLanguageId - if (!settings.enabled.contains(codeLanguageId) - && (codeLanguageId != "nop") && (codeLanguageId != "plaintext")) { + if (shouldSkipCheck(codeLanguageId, settings, rangeStartPos)) { Logging.logger.fine(I18n.format("skippingTextCheckAsLtexHasBeenDisabled", codeLanguageId)) return emptyList() } else if (settings.dictionary.contains("BsPlInEs")) { @@ -157,8 +165,10 @@ class DocumentChecker( for (match: LanguageToolRuleMatch in matches) { result.add( match.copy( - fromPos = match.fromPos + annotatedTextFragment.codeFragment.fromPos + rangeOffset, - toPos = match.toPos + annotatedTextFragment.codeFragment.fromPos + rangeOffset, + fromPos = + match.fromPos + annotatedTextFragment.codeFragment.fromPos + (rangeStartPos ?: 0), + toPos = + match.toPos + annotatedTextFragment.codeFragment.fromPos + (rangeStartPos ?: 0), ), ) } @@ -259,14 +269,14 @@ class DocumentChecker( ): Pair, List> { this.lastCheckedDocument = document val originalSettings: Settings = this.settingsManager.settings - val rangeOffset: Int = (if (range == null) 0 else document.convertPosition(range.start)) + val rangeStartPos: Int? = if (range != null) document.convertPosition(range.start) else null try { val codeFragments: List = fragmentizeDocument(document, range) val annotatedTextFragments: List = - buildAnnotatedTextFragments(codeFragments, document) + buildAnnotatedTextFragments(codeFragments, document, (range != null)) val matches: List = - checkAnnotatedTextFragments(annotatedTextFragments, rangeOffset) + checkAnnotatedTextFragments(annotatedTextFragments, rangeStartPos) return Pair(matches, annotatedTextFragments) } finally { this.settingsManager.settings = originalSettings @@ -275,5 +285,18 @@ class DocumentChecker( companion object { private const val MAX_LOG_TEXT_LENGTH = 100 + + private fun shouldSkipCheck( + codeLanguageId: String, + settings: Settings, + rangeStartPos: Int?, + ): Boolean { + return ( + (rangeStartPos == null) + && !settings.enabled.contains(codeLanguageId) + && (codeLanguageId != "nop") + && (codeLanguageId != "plaintext") + ) + } } } diff --git a/src/test/kotlin/org/bsplines/ltexls/server/DocumentCheckerTest.kt b/src/test/kotlin/org/bsplines/ltexls/server/DocumentCheckerTest.kt index a9392fa..b3ba47c 100644 --- a/src/test/kotlin/org/bsplines/ltexls/server/DocumentCheckerTest.kt +++ b/src/test/kotlin/org/bsplines/ltexls/server/DocumentCheckerTest.kt @@ -144,20 +144,40 @@ class DocumentCheckerTest { @Test fun testRange() { - val document: LtexTextDocumentItem = createDocument( + var document: LtexTextDocumentItem = createDocument( "markdown", "# Test\n\nThis is an **test.**\n\nThis is an **test.**\n", ) val settingsManager = SettingsManager(Settings(_logLevel = Level.FINEST)) val documentChecker = DocumentChecker(settingsManager) - val checkingResult: Pair, List> = + var checkingResult: Pair, List> = documentChecker.check(document, Range(Position(4, 0), Position(4, 20))) - val matches: List = checkingResult.first + var matches: List = checkingResult.first assertEquals(1, matches.size) assertEquals("EN_A_VS_AN", matches[0].ruleId) assertEquals("This is an test.", matches[0].sentence?.trim()) assertEquals(38, matches[0].fromPos) assertEquals(40, matches[0].toPos) + + document = createDocument( + "cpp", + """ + #include + + int main() { + std::cout << "This is an test." << std::endl; + return 0; + } + + """.trimIndent(), + ) + checkingResult = documentChecker.check(document, Range(Position(3, 16), Position(3, 32))) + matches = checkingResult.first + assertEquals(1, matches.size) + assertEquals("EN_A_VS_AN", matches[0].ruleId) + assertEquals("This is an test.", matches[0].sentence?.trim()) + assertEquals(58, matches[0].fromPos) + assertEquals(60, matches[0].toPos) } @Test