From d4af5e35af40a44080a0eab7a3a80336d5196df3 Mon Sep 17 00:00:00 2001 From: Ilia Permiashkin Date: Thu, 24 Jul 2025 15:38:18 +0000 Subject: [PATCH] IJPL-197699 Restrict Hunspell plugin to the Hungarian language Merge-request: IJ-MR-170160 Merged-by: Ilia Permiashkin GitOrigin-RevId: c4b7b82889ec9aa4f2ab0a5a95a2a50922ae8830 --- .../engine/SpellCheckerEngine.java | 4 ++ .../grazie/GrazieSpellCheckerEngine.kt | 4 +- .../hunspell/HunspellDictionaryProvider.kt | 39 ++++++++++++------- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/spellchecker/src/com/intellij/spellchecker/engine/SpellCheckerEngine.java b/spellchecker/src/com/intellij/spellchecker/engine/SpellCheckerEngine.java index 7505dcc28666..cbdecb0d73dc 100644 --- a/spellchecker/src/com/intellij/spellchecker/engine/SpellCheckerEngine.java +++ b/spellchecker/src/com/intellij/spellchecker/engine/SpellCheckerEngine.java @@ -18,9 +18,11 @@ package com.intellij.spellchecker.engine; import com.intellij.spellchecker.dictionary.Dictionary; import com.intellij.spellchecker.dictionary.EditableDictionary; import com.intellij.spellchecker.dictionary.Loader; +import kotlin.text.Regex; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Set; public interface SpellCheckerEngine { void loadDictionary(@NotNull Loader loader); @@ -43,6 +45,8 @@ public interface SpellCheckerEngine { boolean isDictionaryLoad(@NotNull String name); + Set getDictionaryNames(); + void removeDictionary(@NotNull String name); void removeDictionariesRecursively(@NotNull String directory); diff --git a/spellchecker/src/com/intellij/spellchecker/grazie/GrazieSpellCheckerEngine.kt b/spellchecker/src/com/intellij/spellchecker/grazie/GrazieSpellCheckerEngine.kt index 7b3346394cd1..7416eb7924e2 100644 --- a/spellchecker/src/com/intellij/spellchecker/grazie/GrazieSpellCheckerEngine.kt +++ b/spellchecker/src/com/intellij/spellchecker/grazie/GrazieSpellCheckerEngine.kt @@ -144,7 +144,9 @@ class GrazieSpellCheckerEngine( ) } - override fun isDictionaryLoad(name: String) = adapter.containsSource(name) + override fun isDictionaryLoad(name: String): Boolean = adapter.containsSource(name) + + override fun getDictionaryNames(): Set = adapter.names override fun loadDictionary(loader: Loader) { this.loader.loadWordList(loader, adapter::addList) diff --git a/spellchecker/src/com/intellij/spellchecker/hunspell/HunspellDictionaryProvider.kt b/spellchecker/src/com/intellij/spellchecker/hunspell/HunspellDictionaryProvider.kt index 1345afa410b6..9d1d32463862 100644 --- a/spellchecker/src/com/intellij/spellchecker/hunspell/HunspellDictionaryProvider.kt +++ b/spellchecker/src/com/intellij/spellchecker/hunspell/HunspellDictionaryProvider.kt @@ -8,12 +8,11 @@ import com.intellij.spellchecker.dictionary.CustomDictionaryProvider import com.intellij.spellchecker.dictionary.Dictionary import com.intellij.spellchecker.ui.SpellCheckingNotifier import com.intellij.spellchecker.util.SpellCheckerBundle +import java.io.File import java.io.FileNotFoundException import java.text.ParseException internal class HunspellDictionaryProvider : CustomDictionaryProvider { - private val UNSUPPORTED_LANGUAGES = setOf("hu_HU") - private fun isHunspellPluginInstalled(): Boolean { val hunspellId = PluginId.getId("hunspell") val ideaPluginDescriptor = PluginManagerCore.getPlugin(hunspellId) @@ -30,18 +29,12 @@ internal class HunspellDictionaryProvider : CustomDictionaryProvider { ) return null } - val dict = HunspellDictionary(dicPath) - - if (dict.language() in UNSUPPORTED_LANGUAGES) { - if (!isHunspellPluginInstalled()) { - SpellCheckingNotifier.showWarningNotificationBalloon(SpellCheckerBundle.message("dictionary.unsupported.language.title"), - SpellCheckerBundle.message("dictionary.unsupported.language", dicPath)) - } - + if (isHungarian(dicPath)) { + SpellCheckingNotifier.showWarningNotificationBalloon(SpellCheckerBundle.message("dictionary.unsupported.language.title"), + SpellCheckerBundle.message("dictionary.unsupported.language", dicPath)) return null } - - return dict + return HunspellDictionary(dicPath) } catch (_: FileNotFoundException) { SpellCheckingNotifier.showWarningNotificationBalloon(SpellCheckerBundle.message("dictionary.not.found.title"), @@ -56,11 +49,31 @@ internal class HunspellDictionaryProvider : CustomDictionaryProvider { } override fun isApplicable(path: String): Boolean { - return !isHunspellPluginInstalled() && (HunspellDictionary.isHunspell(path) || isIncompleteHunspell(path)) + return (HunspellDictionary.isHunspell(path) || isIncompleteHunspell(path)) + && !(isHunspellPluginInstalled() && isHungarian(path)) } override fun getDictionaryType() = SpellCheckerBundle.message("hunspell.dictionary") + private fun isHungarian(path: String): Boolean { + if (FileUtilRt.getExtension(path) != "dic") return false + val (_, aff) = HunspellDictionary.getHunspellPaths(path) + if (!aff.exists()) return false + + try { + for (line in aff.readLines()) { + val args = line.split("\\s+".toRegex()) + if (args.size == 2 && args[0] == "LANG") { + return args[1] in setOf("hu", "HU", "hu_HU") + } + } + } + catch (_: Exception) { + } + + return false + } + private fun isIncompleteHunspell(path: String): Boolean { if (FileUtilRt.getExtension(path) != "dic") return false val (dic, aff) = HunspellDictionary.getHunspellPaths(path)