blob: 660990d53368fe9728a0905b13f97d7bfbb48140 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.spellchecker;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
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.psi.PsiManager;
import com.intellij.psi.impl.PsiModificationTrackerImpl;
import com.intellij.spellchecker.dictionary.EditableDictionary;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.spellchecker.engine.SpellCheckerEngine;
import com.intellij.spellchecker.engine.SpellCheckerFactory;
import com.intellij.spellchecker.engine.SuggestionProvider;
import com.intellij.spellchecker.settings.SpellCheckerSettings;
import com.intellij.spellchecker.state.StateLoader;
import com.intellij.spellchecker.util.SPFileUtil;
import com.intellij.spellchecker.util.Strings;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.util.*;
public class SpellCheckerManager {
private static final Logger LOG = Logger.getInstance("#com.intellij.spellchecker.SpellCheckerManager");
private static final int MAX_SUGGESTIONS_THRESHOLD = 5;
private static final int MAX_METRICS = 1;
private final Project project;
private SpellCheckerEngine spellChecker;
private EditableDictionary userDictionary;
@NotNull
private final SuggestionProvider suggestionProvider = new BaseSuggestionProvider(this);
private final SpellCheckerSettings settings;
public static SpellCheckerManager getInstance(Project project) {
return ServiceManager.getService(project, SpellCheckerManager.class);
}
public SpellCheckerManager(Project project, SpellCheckerSettings settings) {
this.project = project;
this.settings = settings;
fullConfigurationReload();
}
public void fullConfigurationReload() {
spellChecker = SpellCheckerFactory.create(project);
fillEngineDictionary();
}
public void updateBundledDictionaries(final List<String> removedDictionaries) {
for (BundledDictionaryProvider provider : Extensions.getExtensions(BundledDictionaryProvider.EP_NAME)) {
for (String dictionary : provider.getBundledDictionaries()) {
boolean dictionaryShouldBeLoad = settings == null || !settings.getBundledDisabledDictionariesPaths().contains(dictionary);
boolean dictionaryIsLoad = spellChecker.isDictionaryLoad(dictionary);
if (dictionaryIsLoad && !dictionaryShouldBeLoad) {
spellChecker.removeDictionary(dictionary);
}
else if (!dictionaryIsLoad && dictionaryShouldBeLoad) {
final Class<? extends BundledDictionaryProvider> loaderClass = provider.getClass();
final InputStream stream = loaderClass.getResourceAsStream(dictionary);
if (stream != null) {
spellChecker.loadDictionary(new StreamLoader(stream, dictionary));
}
else {
LOG.warn("Couldn't load dictionary '" + dictionary + "' with loader '" + loaderClass + "'");
}
}
}
}
if (settings != null && settings.getDictionaryFoldersPaths() != null) {
final Set<String> disabledDictionaries = settings.getDisabledDictionariesPaths();
for (String folder : settings.getDictionaryFoldersPaths()) {
SPFileUtil.processFilesRecursively(folder, new Consumer<String>() {
@Override
public void consume(final String s) {
boolean dictionaryShouldBeLoad =!disabledDictionaries.contains(s);
boolean dictionaryIsLoad = spellChecker.isDictionaryLoad(s);
if (dictionaryIsLoad && !dictionaryShouldBeLoad) {
spellChecker.removeDictionary(s);
}
else if (!dictionaryIsLoad && dictionaryShouldBeLoad) {
spellChecker.loadDictionary(new FileLoader(s, s));
}
}
});
}
}
if (removedDictionaries != null && !removedDictionaries.isEmpty()) {
for (final String name : removedDictionaries) {
spellChecker.removeDictionary(name);
}
}
restartInspections();
}
public Project getProject() {
return project;
}
public EditableDictionary getUserDictionary() {
return userDictionary;
}
private void fillEngineDictionary() {
spellChecker.reset();
final StateLoader stateLoader = new StateLoader(project);
stateLoader.load(new Consumer<String>() {
@Override
public void consume(String s) {
//do nothing - in this loader we don't worry about word list itself - the whole dictionary will be restored
}
});
final List<Loader> loaders = new ArrayList<Loader>();
// Load bundled dictionaries from corresponding jars
for (BundledDictionaryProvider provider : Extensions.getExtensions(BundledDictionaryProvider.EP_NAME)) {
for (String dictionary : provider.getBundledDictionaries()) {
if (settings == null || !settings.getBundledDisabledDictionariesPaths().contains(dictionary)) {
final Class<? extends BundledDictionaryProvider> loaderClass = provider.getClass();
final InputStream stream = loaderClass.getResourceAsStream(dictionary);
if (stream != null) {
loaders.add(new StreamLoader(stream, dictionary));
}
else {
LOG.warn("Couldn't load dictionary '" + dictionary + "' with loader '" + loaderClass + "'");
}
}
}
}
if (settings != null && settings.getDictionaryFoldersPaths() != null) {
final Set<String> disabledDictionaries = settings.getDisabledDictionariesPaths();
for (String folder : settings.getDictionaryFoldersPaths()) {
SPFileUtil.processFilesRecursively(folder, new Consumer<String>() {
@Override
public void consume(final String s) {
if (!disabledDictionaries.contains(s)) {
loaders.add(new FileLoader(s, s));
}
}
});
}
}
loaders.add(stateLoader);
for (Loader loader : loaders) {
spellChecker.loadDictionary(loader);
}
userDictionary = stateLoader.getDictionary();
}
public boolean hasProblem(@NotNull String word) {
return !spellChecker.isCorrect(word);
}
public void acceptWordAsCorrect(@NotNull String word, Project project) {
final String transformed = spellChecker.getTransformation().transform(word);
if (transformed != null) {
userDictionary.addToDictionary(transformed);
final PsiModificationTrackerImpl modificationTracker =
(PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker();
modificationTracker.incCounter();
}
}
public void updateUserDictionary(@Nullable Collection<String> words) {
userDictionary.replaceAll(words);
restartInspections();
}
@NotNull
public static List<String> getBundledDictionaries() {
final ArrayList<String> dictionaries = new ArrayList<String>();
for (BundledDictionaryProvider provider : Extensions.getExtensions(BundledDictionaryProvider.EP_NAME)) {
ContainerUtil.addAll(dictionaries, provider.getBundledDictionaries());
}
return dictionaries;
}
@NotNull
public static HighlightDisplayLevel getHighlightDisplayLevel() {
return HighlightDisplayLevel.find(SpellCheckerSeveritiesProvider.TYPO);
}
@NotNull
public List<String> getSuggestions(@NotNull String text) {
return suggestionProvider.getSuggestions(text);
}
@NotNull
protected List<String> getRawSuggestions(@NotNull String word) {
if (!spellChecker.isCorrect(word)) {
List<String> suggestions = spellChecker.getSuggestions(word, MAX_SUGGESTIONS_THRESHOLD, MAX_METRICS);
if (!suggestions.isEmpty()) {
boolean capitalized = Strings.isCapitalized(word);
boolean upperCases = Strings.isUpperCase(word);
if (capitalized) {
Strings.capitalize(suggestions);
}
else if (upperCases) {
Strings.upperCase(suggestions);
}
}
return new ArrayList<String>(new LinkedHashSet<String>(suggestions));
}
return Collections.emptyList();
}
public static void restartInspections() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
Project[] projects = ProjectManager.getInstance().getOpenProjects();
for (Project project : projects) {
if (project.isInitialized() && project.isOpen() && !project.isDefault()) {
DaemonCodeAnalyzer.getInstance(project).restart();
}
}
}
});
}
}