diff --git a/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.java b/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.java index d7ec8057be51..b3a3be52ad4d 100644 --- a/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.java +++ b/spellchecker/src/com/intellij/spellchecker/SpellCheckerManager.java @@ -22,6 +22,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFileEvent; +import com.intellij.openapi.vfs.VirtualFileListener; import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiModificationTrackerImpl; import com.intellij.spellchecker.dictionary.EditableDictionary; @@ -31,7 +34,6 @@ import com.intellij.spellchecker.engine.SpellCheckerFactory; import com.intellij.spellchecker.engine.SuggestionProvider; import com.intellij.spellchecker.settings.SpellCheckerSettings; import com.intellij.spellchecker.state.AggregatedDictionaryState; -import com.intellij.spellchecker.util.SPFileUtil; import com.intellij.spellchecker.util.Strings; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -41,6 +43,9 @@ import org.jetbrains.annotations.Nullable; import java.io.InputStream; import java.util.*; +import static com.intellij.openapi.util.io.FileUtil.isAncestor; +import static com.intellij.spellchecker.util.SPFileUtil.processFilesRecursively; + public class SpellCheckerManager { private static final Logger LOG = Logger.getInstance("#com.intellij.spellchecker.SpellCheckerManager"); @@ -61,6 +66,38 @@ public class SpellCheckerManager { this.project = project; this.settings = settings; fullConfigurationReload(); + LocalFileSystem.getInstance().addVirtualFileListener(new VirtualFileListener() { + @Override + public void fileDeleted(@NotNull VirtualFileEvent event) { + final String path = event.getFile().getPath(); + if (spellChecker.isDictionaryLoad(path)) { + spellChecker.removeDictionary(path); + restartInspections(); + } + } + + @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + final String path = event.getFile().getPath(); + boolean customDic = path.endsWith(".dic") && settings.getDictionaryFoldersPaths().stream().anyMatch(i -> isAncestor(i, path, true)); + if (customDic) { + spellChecker.loadDictionary(new FileLoader(path, path)); + restartInspections(); + } + } + + @Override + public void contentsChanged(@NotNull VirtualFileEvent event) { + final String path = event.getFile().getPath(); + if (settings.getDisabledDictionariesPaths().contains(path)) return; + + if (spellChecker.isDictionaryLoad(path)) { + spellChecker.removeDictionary(path); + spellChecker.loadDictionary(new FileLoader(path, path)); + restartInspections(); + } + } + }); } public void fullConfigurationReload() { @@ -91,8 +128,8 @@ public class SpellCheckerManager { if (settings != null && settings.getDictionaryFoldersPaths() != null) { final Set disabledDictionaries = settings.getDisabledDictionariesPaths(); for (String folder : settings.getDictionaryFoldersPaths()) { - SPFileUtil.processFilesRecursively(folder, s -> { - boolean dictionaryShouldBeLoad =!disabledDictionaries.contains(s); + processFilesRecursively(folder, s -> { + boolean dictionaryShouldBeLoad = !disabledDictionaries.contains(s); boolean dictionaryIsLoad = spellChecker.isDictionaryLoad(s); if (dictionaryIsLoad && !dictionaryShouldBeLoad) { spellChecker.removeDictionary(s); @@ -142,7 +179,7 @@ public class SpellCheckerManager { if (settings != null && settings.getDictionaryFoldersPaths() != null) { final Set disabledDictionaries = settings.getDisabledDictionariesPaths(); for (String folder : settings.getDictionaryFoldersPaths()) { - SPFileUtil.processFilesRecursively(folder, s -> { + processFilesRecursively(folder, s -> { if (!disabledDictionaries.contains(s)) { loaders.add(new FileLoader(s, s)); } diff --git a/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.after.php b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.after.php new file mode 100644 index 000000000000..6d1b2f522512 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.after.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.before.php b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.before.php new file mode 100644 index 000000000000..6d1b2f522512 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.before.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.dic b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.dic new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.dic.after b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.dic.after new file mode 100644 index 000000000000..2efe12229cbd --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addAnotherToCustomDic/test.dic.after @@ -0,0 +1 @@ +anotherword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addDictionary/test.after.php b/spellchecker/testData/inspection/dictionary/addDictionary/test.after.php new file mode 100644 index 000000000000..15df5adfcaf3 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addDictionary/test.after.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addDictionary/test.dic.after b/spellchecker/testData/inspection/dictionary/addDictionary/test.dic.after new file mode 100644 index 000000000000..be652306a932 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addDictionary/test.dic.after @@ -0,0 +1 @@ +newword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.after.php b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.after.php new file mode 100644 index 000000000000..0d72007b2b86 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.after.php @@ -0,0 +1,5 @@ +anotherword +"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic new file mode 100644 index 000000000000..7e566d96f3f7 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic @@ -0,0 +1,2 @@ +newword + diff --git a/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic.after b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic.after new file mode 100644 index 000000000000..2efe12229cbd --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addOneMoreDictionary/test.dic.after @@ -0,0 +1 @@ +anotherword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addSeveralWords/test.after.php b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.after.php new file mode 100644 index 000000000000..ad11c1f4b0e0 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.after.php @@ -0,0 +1,6 @@ +firstword +secondword +thirdword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic new file mode 100644 index 000000000000..52f676490506 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic @@ -0,0 +1,2 @@ +newword +anotherword diff --git a/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic.after b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic.after new file mode 100644 index 000000000000..f446df54e8ad --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addSeveralWords/test.dic.after @@ -0,0 +1,5 @@ +newword +anotherword +firstword +secondword +thirdword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addToCustomDic/test.after.php b/spellchecker/testData/inspection/dictionary/addToCustomDic/test.after.php new file mode 100644 index 000000000000..15df5adfcaf3 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addToCustomDic/test.after.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/addToCustomDic/test.dic b/spellchecker/testData/inspection/dictionary/addToCustomDic/test.dic new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/spellchecker/testData/inspection/dictionary/addToCustomDic/test.dic.after b/spellchecker/testData/inspection/dictionary/addToCustomDic/test.dic.after new file mode 100644 index 000000000000..be652306a932 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/addToCustomDic/test.dic.after @@ -0,0 +1 @@ +newword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/modifyDict/test.after.php b/spellchecker/testData/inspection/dictionary/modifyDict/test.after.php new file mode 100644 index 000000000000..b3836d0403de --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/modifyDict/test.after.php @@ -0,0 +1,5 @@ +firstword +secondword +thirdword +fourthword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/modifyDict/test.before.php b/spellchecker/testData/inspection/dictionary/modifyDict/test.before.php new file mode 100644 index 000000000000..5108ed66ef1f --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/modifyDict/test.before.php @@ -0,0 +1,5 @@ +fourthword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/modifyDict/test.dic b/spellchecker/testData/inspection/dictionary/modifyDict/test.dic new file mode 100644 index 000000000000..4d05c374826c --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/modifyDict/test.dic @@ -0,0 +1,3 @@ +firstword +secondword +thirdword diff --git a/spellchecker/testData/inspection/dictionary/modifyDict/test.dic.after b/spellchecker/testData/inspection/dictionary/modifyDict/test.dic.after new file mode 100644 index 000000000000..c674efa4a7cf --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/modifyDict/test.dic.after @@ -0,0 +1,3 @@ +secondword +thirdword +fourthword \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/removeDictionary/test.after.php b/spellchecker/testData/inspection/dictionary/removeDictionary/test.after.php new file mode 100644 index 000000000000..6d1b2f522512 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/removeDictionary/test.after.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/removeDictionary/test.before.php b/spellchecker/testData/inspection/dictionary/removeDictionary/test.before.php new file mode 100644 index 000000000000..15df5adfcaf3 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/removeDictionary/test.before.php @@ -0,0 +1,2 @@ +newword"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/removeFromCustomDic/test.before.php b/spellchecker/testData/inspection/dictionary/removeFromCustomDic/test.before.php new file mode 100644 index 000000000000..15df5adfcaf3 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/removeFromCustomDic/test.before.php @@ -0,0 +1,2 @@ +newword +anotherword +"; \ No newline at end of file diff --git a/spellchecker/testData/inspection/dictionary/removeOneOfDictionaries/test.before.php b/spellchecker/testData/inspection/dictionary/removeOneOfDictionaries/test.before.php new file mode 100644 index 000000000000..0d72007b2b86 --- /dev/null +++ b/spellchecker/testData/inspection/dictionary/removeOneOfDictionaries/test.before.php @@ -0,0 +1,5 @@ + oldPaths; + SpellCheckerSettings settings; + SpellCheckerManager spellCheckerManager; + + + @Override + protected void setUp() throws Exception { + super.setUp(); + settings = SpellCheckerSettings.getInstance(getProject()); + spellCheckerManager = SpellCheckerManager.getInstance(getProject()); + oldPaths = settings.getDictionaryFoldersPaths(); + settings.setDictionaryFoldersPaths(Collections.singletonList(getTestDictDirectory())); + spellCheckerManager.fullConfigurationReload(); + } + + @Override + protected void tearDown() throws Exception { + //noinspection SuperTearDownInFinally + super.tearDown(); + settings.setDictionaryFoldersPaths(oldPaths); + } + + @Override + protected String getBasePath() { + return Paths.get(getSpellcheckerTestDataPath(), "inspection", "dictionary").toString(); + } + + private String getTestDictionary() { + return Paths.get(getTestDictDirectory(), TEST_DIC).toString(); + } + + private String getTestDictDirectory() { + return Paths.get(myFixture.getTestDataPath(), getTestName(true)).toString(); + } + + private VirtualFile getTestDictionaryFile() { + return findFileByIoFile(Paths.get(getTestDictionary()).toFile(), true); + } + + private String loadFromTestDictionary() throws IOException { + final VirtualFile file = findFileByIoFile(new File(getTestDictionary()), true); + if (file == null) return null; + return VfsUtilCore.loadText(file); + } + + private void modifyDictContent(String newContent) throws IOException { + WriteAction.run(() -> VfsUtil.saveText(getTestDictionaryFile(), newContent)); + } + + private void doBeforeCheck() { + doTest(Paths.get(getTestDictDirectory(), "test.before.php").toString()); + } + + private void doAfterCheck() { + doTest(Paths.get(getTestDictDirectory(), "test.after.php").toString()); + } + + private void doTest() throws IOException { + final String oldDictContent = loadFromTestDictionary(); + try { + doBeforeCheck(); + modifyDictContent(VfsUtilCore.loadText(findFileByIoFile(Paths.get(getTestDictDirectory(), TEST_DIC_AFTER).toFile(), true))); + doAfterCheck(); + } + finally { + //back to initial state + modifyDictContent(oldDictContent); + } + } + + private void doNewDictTest() throws IOException { + final VirtualFile file = findFileByIoFile(Paths.get(getTestDictDirectory(), TEST_DIC_AFTER).toFile(), true); + try { + doBeforeCheck(); + WriteAction.run(() -> file.copy(this, file.getParent(), NEW_TEST_DIC)); + doAfterCheck(); + } + finally { + //back to initial state + WriteAction.run(() -> file.getParent().findChild(NEW_TEST_DIC).delete(this)); + } + } + + private void doRemoveDictTest() throws IOException { + try { + doBeforeCheck(); + WriteAction.run(() -> { + getTestDictionaryFile().copy(this, getTestDictionaryFile().getParent(), TEMP_DIC); // to revert it back + getTestDictionaryFile().delete(this); + }); + doAfterCheck(); + } + finally { + //back to initial state + WriteAction.run(() -> findFileByIoFile(Paths.get(getTestDictDirectory(), TEMP_DIC).toFile(), true).rename(this, TEST_DIC)); + } + } + + public void testAddDictionary() throws IOException, InterruptedException { + doNewDictTest(); + } + + public void testAddOneMoreDictionary() throws IOException, InterruptedException { + doNewDictTest(); + } + + public void testRemoveDictionary() throws IOException { + doRemoveDictTest(); + } + + public void testRemoveOneOfDictionaries() throws IOException { + doRemoveDictTest(); + } + + public void testAddToCustomDic() throws IOException { + doTest(); + } + + public void testAddAnotherToCustomDic() throws IOException { + doTest(); + } + + public void testRemoveFromCustomDic() throws IOException { + doTest(); + } + + public void testAddSeveralWords() throws IOException { + doTest(); + } + + public void testModifyDict() throws IOException { + doTest(); + } +} diff --git a/spellchecker/testSrc/com/intellij/spellchecker/inspection/SpellcheckerInspectionTestCase.java b/spellchecker/testSrc/com/intellij/spellchecker/inspection/SpellcheckerInspectionTestCase.java index 87497fb435e2..68e5f16f6275 100644 --- a/spellchecker/testSrc/com/intellij/spellchecker/inspection/SpellcheckerInspectionTestCase.java +++ b/spellchecker/testSrc/com/intellij/spellchecker/inspection/SpellcheckerInspectionTestCase.java @@ -25,7 +25,7 @@ public abstract class SpellcheckerInspectionTestCase extends LightPlatformCodeIn return true; } - public static String getSpellcheckerTestDataPath() { + protected static String getSpellcheckerTestDataPath() { return "/spellchecker/testData/"; }