From cabf0773f82a7d2a1321d4d4181439c8ab2e82af Mon Sep 17 00:00:00 2001 From: Den Mukhametianov Date: Thu, 11 Jan 2024 14:49:21 +0100 Subject: [PATCH] [spellchecker] extend DictionaryLevel to DictionaryLayer with corresponding extension point In Rider we want to pass ReSharper settings layers to UI-parts like combobox for choosing default dictionary to save words. GitOrigin-RevId: b6b395d0108f2f1142fc1ab3656d3493c5b9be9c --- .../src/META-INF/SpellCheckerPlugin.xml | 2 + .../intellij/spellchecker/DictionaryLevel.kt | 94 +++++++++++++++++++ .../spellchecker/SpellCheckerManager.kt | 34 ++----- .../inspections/SpellCheckingInspection.java | 2 +- .../spellchecker/quickfixes/SaveTo.java | 34 +++---- .../settings/CustomDictionaryPathListener.kt | 14 --- .../DictionaryLayerChangesSubscriber.kt | 26 +++++ .../settings/SettingsTransferActivity.kt | 7 +- .../settings/SpellCheckerSettings.java | 8 +- .../settings/SpellCheckerSettingsPane.java | 5 +- .../tokenizer/SpellcheckingStrategy.java | 14 +-- .../inspector/AcceptWordAsCorrectTest.java | 23 +++-- 12 files changed, 172 insertions(+), 91 deletions(-) create mode 100644 spellchecker/src/com/intellij/spellchecker/DictionaryLevel.kt delete mode 100644 spellchecker/src/com/intellij/spellchecker/settings/CustomDictionaryPathListener.kt create mode 100644 spellchecker/src/com/intellij/spellchecker/settings/DictionaryLayerChangesSubscriber.kt diff --git a/spellchecker/src/META-INF/SpellCheckerPlugin.xml b/spellchecker/src/META-INF/SpellCheckerPlugin.xml index 4a0ef8b09c0a..d9e1321cbcb0 100644 --- a/spellchecker/src/META-INF/SpellCheckerPlugin.xml +++ b/spellchecker/src/META-INF/SpellCheckerPlugin.xml @@ -8,6 +8,7 @@ + @@ -29,6 +30,7 @@ + diff --git a/spellchecker/src/com/intellij/spellchecker/DictionaryLevel.kt b/spellchecker/src/com/intellij/spellchecker/DictionaryLevel.kt new file mode 100644 index 000000000000..54e7dde9669d --- /dev/null +++ b/spellchecker/src/com/intellij/spellchecker/DictionaryLevel.kt @@ -0,0 +1,94 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.spellchecker + +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.project.Project +import com.intellij.spellchecker.dictionary.EditableDictionary +import com.intellij.spellchecker.dictionary.ProjectDictionary +import com.intellij.spellchecker.settings.DictionaryLayerChangesSubscriber +import com.intellij.spellchecker.settings.DictionaryLayersChangesDispatcher +import com.intellij.spellchecker.state.AppDictionaryState +import com.intellij.spellchecker.state.ProjectDictionaryState +import com.intellij.spellchecker.util.SpellCheckerBundle +import org.jetbrains.annotations.Nls + +abstract class DictionaryLayersProvider { + abstract fun getLayers(project: Project): List + open fun startWatchingChanges(project: Project) { } + + companion object { + val EP_NAME = ExtensionPointName.create("com.intellij.spellchecker.dictionaryLayersProvider") + fun getAllLayers(project: Project): List { + return project.service().getAllLayers() + } + + fun getLayer(project: Project, layerName: String): DictionaryLayer? { + return project.service().getLayer(layerName) + } + } +} + +@Service(Service.Level.PROJECT) +class PerProjectDictionaryLayersHolder(private val project: Project) { + private lateinit var layersMap: Map + private lateinit var layers: List + + init { + project.service() + .register(object : DictionaryLayerChangesSubscriber { + override fun layersChanged() { + rebuild() + } + }) + DictionaryLayersProvider.EP_NAME.extensionList.forEach{ + it.startWatchingChanges(project) + } + rebuild() + } + + fun rebuild() { + layers = DictionaryLayersProvider.EP_NAME.extensionList.flatMap { it.getLayers(project) }.toList() + layersMap = layers.associateBy { it.name } + } + + fun getLayer(layerName: String): DictionaryLayer? { + return layersMap[layerName] + } + + fun getAllLayers(): List { + return layers + } +} + +interface DictionaryLayer { + val dictionary: EditableDictionary + @get:Nls + val name: String +} + +class PlatformSettingsDictionaryLayersProvider : DictionaryLayersProvider() { + override fun getLayers(project: Project): List { + return listOf(ApplicationDictionaryLayer.INSTANCE, ProjectDictionaryLayer(project)) + } +} + +class ProjectDictionaryLayer(val project: Project) : DictionaryLayer { + companion object { + val name = SpellCheckerBundle.message("dictionary.name.project.level") + } + + override val name = Companion.name + override val dictionary: ProjectDictionary = project.service().projectDictionary +} + +class ApplicationDictionaryLayer : DictionaryLayer { + companion object { + val name = SpellCheckerBundle.message("dictionary.name.application.level") + val INSTANCE = ApplicationDictionaryLayer() + } + + override val name = Companion.name + override val dictionary: EditableDictionary = AppDictionaryState.getInstance().dictionary +} \ No newline at end of file diff --git a/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.kt b/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.kt index 883fd4ede6b6..1ac0dc7adfd0 100644 --- a/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.kt +++ b/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.kt @@ -29,7 +29,6 @@ import com.intellij.openapi.vfs.* import com.intellij.project.getProjectStoreDirectory import com.intellij.spellchecker.SpellCheckerManager.Companion.restartInspections import com.intellij.spellchecker.dictionary.* -import com.intellij.spellchecker.dictionary.Dictionary import com.intellij.spellchecker.engine.SpellCheckerEngine import com.intellij.spellchecker.engine.SuggestionProvider import com.intellij.spellchecker.grazie.GrazieSpellCheckerEngine @@ -43,11 +42,8 @@ import com.intellij.util.EventDispatcher import com.intellij.util.application import kotlinx.coroutines.CancellationException import kotlinx.coroutines.runBlocking -import org.jetbrains.annotations.Nls import java.io.File -import java.util.* import java.util.function.Consumer -import java.util.function.Supplier private val LOG = logger() private val BUNDLED_EP_NAME = ExtensionPointName("com.intellij.spellchecker.bundledDictionaryProvider") @@ -238,31 +234,31 @@ class SpellCheckerManager(val project: Project) : Disposable { } fun acceptWordAsCorrect(word: String, project: Project) { - acceptWordAsCorrect(word = word, file = null, project = project, dictionaryLevel = DictionaryLevel.PROJECT) // TODO: or default + acceptWordAsCorrect(word = word, file = null, project = project, dictionaryLayer = ProjectDictionaryLayer(project)) // TODO: or default } - internal fun acceptWordAsCorrect(word: String, file: VirtualFile?, project: Project, dictionaryLevel: DictionaryLevel) { - if (DictionaryLevel.NOT_SPECIFIED == dictionaryLevel) { + internal fun acceptWordAsCorrect(word: String, file: VirtualFile?, project: Project, dictionaryLayer: DictionaryLayer?) { + if (dictionaryLayer == null) { return } val transformed = spellChecker!!.transformation.transform(word) ?: return - val dictionary = if (DictionaryLevel.PROJECT == dictionaryLevel) projectDictionary else appDictionary + val dictionary = dictionaryLayer.dictionary if (file != null) { WriteCommandAction.writeCommandAction(project) .run { UndoManager.getInstance(project).undoableActionPerformed(object : BasicUndoableAction(file) { override fun undo() { - removeWordFromDictionary(dictionary!!, transformed) + removeWordFromDictionary(dictionary, transformed) } override fun redo() { - addWordToDictionary(dictionary!!, transformed) + addWordToDictionary(dictionary, transformed) } }) } } - addWordToDictionary(dictionary = dictionary!!, word = transformed) + addWordToDictionary(dictionary = dictionary, word = transformed) } private fun addWordToDictionary(dictionary: EditableDictionary, word: String) { @@ -338,22 +334,6 @@ class SpellCheckerManager(val project: Project) : Disposable { } } -internal enum class DictionaryLevel(private val nameSupplier: Supplier<@Nls String>) { - APP(SpellCheckerBundle.messagePointer("dictionary.name.application.level")), - PROJECT(SpellCheckerBundle.messagePointer("dictionary.name.project.level")), - NOT_SPECIFIED(SpellCheckerBundle.messagePointer("dictionary.name.not.specified")); - - @Nls - fun getName(): String = nameSupplier.get() - - companion object { - private val DICTIONARY_LEVELS = EnumSet.allOf(DictionaryLevel::class.java).associateBy { it.getName() } - - @JvmStatic - fun getLevelByName(name: String): DictionaryLevel = DICTIONARY_LEVELS.get(name) ?: NOT_SPECIFIED - } -} - private class CustomDictFileListener(private val project: Project, private val manager: SpellCheckerManager) : VirtualFileListener { override fun fileDeleted(event: VirtualFileEvent) { removeCustomDictionaries(event.file.path) diff --git a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java index 6bfb3412b37d..e1ba347ace2f 100644 --- a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java +++ b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java @@ -141,7 +141,7 @@ public final class SpellCheckingInspection extends LocalInspectionTool { private static void addBatchDescriptor(PsiElement element, @NotNull TextRange textRange, @NotNull ProblemsHolder holder) { - SpellCheckerQuickFix[] fixes = SpellcheckingStrategy.getDefaultBatchFixes(); + SpellCheckerQuickFix[] fixes = SpellcheckingStrategy.getDefaultBatchFixes(element); ProblemDescriptor problemDescriptor = createProblemDescriptor(element, textRange, fixes, false); holder.registerProblem(problemDescriptor); } diff --git a/spellchecker/src/com/intellij/spellchecker/quickfixes/SaveTo.java b/spellchecker/src/com/intellij/spellchecker/quickfixes/SaveTo.java index d1fe2028146b..8b8a40e5788f 100644 --- a/spellchecker/src/com/intellij/spellchecker/quickfixes/SaveTo.java +++ b/spellchecker/src/com/intellij/spellchecker/quickfixes/SaveTo.java @@ -11,29 +11,27 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.spellchecker.DictionaryLevel; +import com.intellij.spellchecker.DictionaryLayer; +import com.intellij.spellchecker.DictionaryLayersProvider; import com.intellij.spellchecker.SpellCheckerManager; import com.intellij.spellchecker.util.SpellCheckerBundle; import com.intellij.ui.components.JBList; +import com.intellij.util.containers.ContainerUtil; import icons.SpellcheckerIcons; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Arrays; -import java.util.List; public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { - private static final SaveTo SAVE_TO_APP_FIX = new SaveTo(DictionaryLevel.APP); - private static final SaveTo SAVE_TO_PROJECT_FIX = new SaveTo(DictionaryLevel.PROJECT); private static final String DICTIONARY = " dictionary"; private static final String DOTS = "..."; - private DictionaryLevel myLevel = DictionaryLevel.NOT_SPECIFIED; + @Nullable private DictionaryLayer myLevel = null; private String myWord; - private SaveTo(@NotNull DictionaryLevel level) { + public SaveTo(@NotNull DictionaryLayer level) { myLevel = level; } @@ -41,7 +39,7 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { myWord = word; } - public SaveTo(String word, @NotNull DictionaryLevel level) { + public SaveTo(String word, @NotNull DictionaryLayer level) { myWord = word; myLevel = level; } @@ -53,7 +51,7 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { @Override public @NotNull String getFamilyName() { - final String dictionary = myLevel != DictionaryLevel.NOT_SPECIFIED ? myLevel.getName() + DICTIONARY : DOTS; + final String dictionary = myLevel != null ? myLevel.getName() + DICTIONARY : DOTS; return SpellCheckerBundle.message("save.0.to.1", "", dictionary); } @@ -68,10 +66,10 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { .getDataContextFromFocusAsync() .onSuccess(context -> { final String wordToSave = myWord != null ? myWord : ProblemDescriptorUtil.extractHighlightedText(descriptor, descriptor.getPsiElement()); - final VirtualFile file = descriptor.getPsiElement().getContainingFile().getVirtualFile(); - if (myLevel == DictionaryLevel.NOT_SPECIFIED) { - final List dictionaryList = Arrays.asList(DictionaryLevel.PROJECT.getName(), DictionaryLevel.APP.getName()); - final JBList dictList = new JBList<>(dictionaryList); + if (myLevel == null) { + final JBList dictList = new JBList<>( + ContainerUtil.map(DictionaryLayersProvider.Companion.getAllLayers(project), it -> it.getName()) + ); JBPopupFactory.getInstance() .createListPopupBuilder(dictList) @@ -80,7 +78,7 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { () -> CommandProcessor.getInstance().executeCommand( project, - () -> acceptWord(wordToSave, DictionaryLevel.getLevelByName(dictList.getSelectedValue()), descriptor), + () -> acceptWord(wordToSave, DictionaryLayersProvider.Companion.getLayer(project, dictList.getSelectedValue()), descriptor), getName(), null ) @@ -94,7 +92,7 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { }); } - private static void acceptWord(String word, DictionaryLevel level, ProblemDescriptor descriptor) { + private static void acceptWord(String word, @Nullable DictionaryLayer level, ProblemDescriptor descriptor) { SideEffectGuard.checkSideEffectAllowed(SideEffectGuard.EffectType.SETTINGS); PsiElement psi = descriptor.getPsiElement(); @@ -106,10 +104,6 @@ public final class SaveTo implements SpellCheckerQuickFix, LowPriorityAction { UpdateHighlightersUtil.removeHighlightersWithExactRange(file.getViewProvider().getDocument(), project, range); } - public static SaveTo getSaveToLevelFix(DictionaryLevel level) { - return DictionaryLevel.PROJECT == level ? SAVE_TO_PROJECT_FIX : SAVE_TO_APP_FIX; - } - @Override public Icon getIcon(int flags) { return SpellcheckerIcons.Spellcheck; diff --git a/spellchecker/src/com/intellij/spellchecker/settings/CustomDictionaryPathListener.kt b/spellchecker/src/com/intellij/spellchecker/settings/CustomDictionaryPathListener.kt deleted file mode 100644 index 999ea6e385f2..000000000000 --- a/spellchecker/src/com/intellij/spellchecker/settings/CustomDictionaryPathListener.kt +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.spellchecker.settings - -import com.intellij.util.messages.Topic - -// used in Rider -interface CustomDictionaryPathListener { - fun dictionariesChanged(paths: List) - - companion object { - @Topic.AppLevel - val TOPIC: Topic = Topic(CustomDictionaryPathListener::class.java) - } -} \ No newline at end of file diff --git a/spellchecker/src/com/intellij/spellchecker/settings/DictionaryLayerChangesSubscriber.kt b/spellchecker/src/com/intellij/spellchecker/settings/DictionaryLayerChangesSubscriber.kt new file mode 100644 index 000000000000..3b48a70c4f26 --- /dev/null +++ b/spellchecker/src/com/intellij/spellchecker/settings/DictionaryLayerChangesSubscriber.kt @@ -0,0 +1,26 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.spellchecker.settings + +import com.intellij.openapi.components.Service +import com.intellij.util.application +import com.intellij.util.messages.MessageBusConnection +import com.intellij.util.messages.Topic + +@Service(Service.Level.PROJECT) +class DictionaryLayersChangesDispatcher { + @Topic.ProjectLevel + private val topic = Topic(DictionaryLayerChangesSubscriber::class.java) + + val publisher: DictionaryLayerChangesSubscriber + get() = application.messageBus.syncPublisher(topic) + + fun register(subscriber: DictionaryLayerChangesSubscriber): MessageBusConnection { + val connection = application.messageBus.connect() + connection.subscribe(topic, subscriber) + return connection + } +} + +interface DictionaryLayerChangesSubscriber { + fun layersChanged() +} \ No newline at end of file diff --git a/spellchecker/src/com/intellij/spellchecker/settings/SettingsTransferActivity.kt b/spellchecker/src/com/intellij/spellchecker/settings/SettingsTransferActivity.kt index 485e74da4a69..800c6f5627e4 100644 --- a/spellchecker/src/com/intellij/spellchecker/settings/SettingsTransferActivity.kt +++ b/spellchecker/src/com/intellij/spellchecker/settings/SettingsTransferActivity.kt @@ -3,7 +3,8 @@ package com.intellij.spellchecker.settings import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity -import com.intellij.spellchecker.DictionaryLevel +import com.intellij.spellchecker.ApplicationDictionaryLayer +import com.intellij.spellchecker.ProjectDictionaryLayer import com.intellij.spellchecker.state.ProjectDictionaryState internal class SettingsTransferActivity : ProjectActivity { @@ -12,9 +13,9 @@ internal class SettingsTransferActivity : ProjectActivity { if (settings.isSettingsTransferred) { return } - if (settings.isUseSingleDictionaryToSave && DictionaryLevel.PROJECT.getName() == settings.dictionaryToSave && + if (settings.isUseSingleDictionaryToSave && ProjectDictionaryLayer.name == settings.dictionaryToSave && project.getService(ProjectDictionaryState::class.java).projectDictionary.words.isEmpty()) { - settings.dictionaryToSave = DictionaryLevel.APP.getName() + settings.dictionaryToSave = ApplicationDictionaryLayer.name } settings.isSettingsTransferred = true } diff --git a/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettings.java b/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettings.java index ac7f8dd12b4b..194a52b94fdd 100644 --- a/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettings.java +++ b/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettings.java @@ -1,13 +1,12 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.spellchecker.settings; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.spellchecker.DictionaryLevel; +import com.intellij.spellchecker.ProjectDictionaryLayer; import com.intellij.spellchecker.util.SPFileUtil; import com.intellij.util.PathUtil; import org.jdom.Element; @@ -31,7 +30,7 @@ public final class SpellCheckerSettings implements PersistentStateComponent customDictionariesPaths) { myCustomDictionariesPaths = customDictionariesPaths; - ApplicationManager.getApplication().getMessageBus() - .syncPublisher(CustomDictionaryPathListener.Companion.getTOPIC()) - .dictionariesChanged(customDictionariesPaths); } public Set getRuntimeDisabledDictionariesNames() { diff --git a/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettingsPane.java b/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettingsPane.java index 565881ab14ae..deb1f18acc4e 100644 --- a/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettingsPane.java +++ b/spellchecker/src/com/intellij/spellchecker/settings/SpellCheckerSettingsPane.java @@ -13,7 +13,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.profile.codeInspection.ui.ErrorsConfigurable; -import com.intellij.spellchecker.DictionaryLevel; +import com.intellij.spellchecker.DictionaryLayersProvider; import com.intellij.spellchecker.SpellCheckerManager; import com.intellij.spellchecker.dictionary.CustomDictionaryProvider; import com.intellij.spellchecker.inspections.SpellCheckingInspection; @@ -77,8 +77,7 @@ public final class SpellCheckerSettingsPane implements Disposable { myDictionariesComboBox.setEnabled(myUseSingleDictionary.isSelected()); } }); - myDictionariesComboBox.addItem(DictionaryLevel.APP.getName()); - myDictionariesComboBox.addItem(DictionaryLevel.PROJECT.getName()); + DictionaryLayersProvider.Companion.getAllLayers(project).forEach(it -> myDictionariesComboBox.addItem(it.getName())); linkContainer.setLayout(new BorderLayout()); linkContainer.add(link); diff --git a/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java b/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java index d682a78782ec..279f6c4152d5 100644 --- a/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java +++ b/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java @@ -14,7 +14,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.spellchecker.DictionaryLevel; +import com.intellij.spellchecker.DictionaryLayersProvider; import com.intellij.spellchecker.inspections.PlainTextSplitter; import com.intellij.spellchecker.inspections.SpellCheckingInspection; import com.intellij.spellchecker.quickfixes.ChangeTo; @@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Objects; import java.util.Set; /** @@ -53,9 +54,6 @@ public class SpellcheckingStrategy { public static final Tokenizer TEXT_TOKENIZER = new TokenizerBase<>(PlainTextSplitter.getInstance()); - private static final SpellCheckerQuickFix[] BATCH_FIXES = - new SpellCheckerQuickFix[]{SaveTo.getSaveToLevelFix(DictionaryLevel.APP), SaveTo.getSaveToLevelFix(DictionaryLevel.PROJECT)}; - public Tokenizer getTokenizer(PsiElement element, Set scope) { return getTokenizer(element); } @@ -145,7 +143,7 @@ public class SpellcheckingStrategy { final SpellCheckerSettings settings = SpellCheckerSettings.getInstance(element.getProject()); if (settings.isUseSingleDictionaryToSave()) { - result.add(new SaveTo(typo, DictionaryLevel.getLevelByName(settings.getDictionaryToSave()))); + result.add(new SaveTo(typo, Objects.requireNonNull(DictionaryLayersProvider.Companion.getLayer(element.getProject(), settings.getDictionaryToSave())))); return result.toArray(LocalQuickFix.EMPTY_ARRAY); } @@ -153,8 +151,10 @@ public class SpellcheckingStrategy { return result.toArray(LocalQuickFix.EMPTY_ARRAY); } - public static SpellCheckerQuickFix[] getDefaultBatchFixes() { - return BATCH_FIXES; + public static SpellCheckerQuickFix[] getDefaultBatchFixes(PsiElement element) { + return DictionaryLayersProvider.Companion.getAllLayers(element.getProject()) + .stream().map(it -> new SaveTo(it)) + .toArray(SpellCheckerQuickFix[]::new); } public boolean isMyContext(@NotNull PsiElement element) { diff --git a/spellchecker/testSrc/com/intellij/spellchecker/inspector/AcceptWordAsCorrectTest.java b/spellchecker/testSrc/com/intellij/spellchecker/inspector/AcceptWordAsCorrectTest.java index 6ec083b26254..f22a7ba7dffd 100644 --- a/spellchecker/testSrc/com/intellij/spellchecker/inspector/AcceptWordAsCorrectTest.java +++ b/spellchecker/testSrc/com/intellij/spellchecker/inspector/AcceptWordAsCorrectTest.java @@ -6,8 +6,9 @@ import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.spellchecker.DictionaryLevel; +import com.intellij.spellchecker.ProjectDictionaryLayer; import com.intellij.spellchecker.SpellCheckerManager; import com.intellij.testFramework.fixtures.BasePlatformTestCase; @@ -20,11 +21,12 @@ public class AcceptWordAsCorrectTest extends BasePlatformTestCase { public static final String TEST_TXT = "test.txt"; private void doTest(String word, VirtualFile file) { - final SpellCheckerManager manager = SpellCheckerManager.getInstance(getProject()); + var project = getProject(); + final SpellCheckerManager manager = SpellCheckerManager.getInstance(project); try { assertTrue(manager.hasProblem(word)); - CommandProcessor.getInstance().executeCommand(getProject(), () -> manager - .acceptWordAsCorrect$intellij_spellchecker(word, file, getProject(), DictionaryLevel.PROJECT), getName(), null); + CommandProcessor.getInstance().executeCommand(project, () -> manager + .acceptWordAsCorrect$intellij_spellchecker(word, file, project, new ProjectDictionaryLayer(project)), getName(), null); assertFalse(manager.hasProblem(word)); } finally { @@ -72,20 +74,21 @@ public class AcceptWordAsCorrectTest extends BasePlatformTestCase { public void testUndoRedo() { final VirtualFile file = myFixture.configureByText(TEST_TXT, TYPPO).getVirtualFile(); - final UndoManager instance = UndoManager.getInstance(getProject()); + final Project project = getProject(); + final UndoManager instance = UndoManager.getInstance(project); ((UndoManagerImpl)instance).dropHistoryInTests(); // to make sure it's empty - final SpellCheckerManager manager = SpellCheckerManager.getInstance(getProject()); + final SpellCheckerManager manager = SpellCheckerManager.getInstance(project); assertTrue(manager.hasProblem(TYPPO)); - CommandProcessor.getInstance().executeCommand(getProject(), () -> manager - .acceptWordAsCorrect$intellij_spellchecker(TYPPO, file, getProject(), DictionaryLevel.PROJECT), getName(), null); + CommandProcessor.getInstance().executeCommand(project, () -> manager + .acceptWordAsCorrect$intellij_spellchecker(TYPPO, file, project, new ProjectDictionaryLayer(project)), getName(), null); assertFalse(manager.hasProblem(TYPPO)); - instance.undo(FileEditorManager.getInstance(getProject()).getSelectedEditor(file)); + instance.undo(FileEditorManager.getInstance(project).getSelectedEditor(file)); assertTrue(manager.hasProblem(TYPPO)); - instance.redo(FileEditorManager.getInstance(getProject()).getSelectedEditor(file)); + instance.redo(FileEditorManager.getInstance(project).getSelectedEditor(file)); assertFalse(manager.hasProblem(TYPPO)); } }