mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 15:06:56 +07:00
[spellchecker] allow SpellCheckerStrategy to decide whether psi element fits or doesn't spell checker scope, pass this scope to getTokenizer
Some backend-driven languages in Rider don't have detailed frontend lexer/parser, so the only node visible to spellchecker will be root PsiFile. We pass range-scope information from backend, and then rider's spell checking strategy will handle it itself. GitOrigin-RevId: b97c9eaaed30d6a0e09d69b13cf4cd5ad1b5d364
This commit is contained in:
committed by
intellij-monorepo-bot
parent
86c8fa3545
commit
75284da775
@@ -185,7 +185,7 @@ public abstract class SpellCheckerDictionaryGenerator {
|
||||
addSeenWord(seenNames, word, language);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, null);
|
||||
}
|
||||
|
||||
protected void addSeenWord(HashSet<String> seenNames, String word, Language language) {
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.spellchecker.SpellCheckerManager;
|
||||
import com.intellij.spellchecker.quickfixes.SpellCheckerQuickFix;
|
||||
import com.intellij.spellchecker.tokenizer.*;
|
||||
@@ -23,6 +22,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.codeInspection.options.OptPane.checkbox;
|
||||
@@ -73,6 +73,7 @@ public final class SpellCheckingInspection extends LocalInspectionTool {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
final SpellCheckerManager manager = SpellCheckerManager.getInstance(holder.getProject());
|
||||
var scope = buildAllowedScopes();
|
||||
|
||||
return new PsiElementVisitor() {
|
||||
@Override
|
||||
@@ -84,51 +85,55 @@ public final class SpellCheckingInspection extends LocalInspectionTool {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract parser definition from element
|
||||
final Language language = element.getLanguage();
|
||||
final IElementType elementType = node.getElementType();
|
||||
final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
|
||||
var strategy = getSpellcheckingStrategy(element, language);
|
||||
if(strategy == null)
|
||||
return;
|
||||
|
||||
// Handle selected options
|
||||
if (parserDefinition != null) {
|
||||
if (parserDefinition.getStringLiteralElements().contains(elementType)) {
|
||||
if (!processLiterals) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (parserDefinition.getCommentTokens().contains(elementType)) {
|
||||
if (!processComments) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!processCode) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!strategy.elementFitsScope(element, scope))
|
||||
return;
|
||||
|
||||
PsiFile containingFile = holder.getFile();
|
||||
if (Boolean.TRUE.equals(containingFile.getUserData(InjectedLanguageManager.FRANKENSTEIN_INJECTION))) {
|
||||
return;
|
||||
}
|
||||
|
||||
tokenize(element, language, new MyTokenConsumer(manager, holder, LanguageNamesValidation.INSTANCE.forLanguage(language)));
|
||||
tokenize(element, language, new MyTokenConsumer(manager, holder, LanguageNamesValidation.INSTANCE.forLanguage(language)), scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Set<SpellCheckingScope> buildAllowedScopes() {
|
||||
var result = new HashSet<SpellCheckingScope>();
|
||||
if(processLiterals)
|
||||
result.add(SpellCheckingScope.Literals);
|
||||
if(processComments)
|
||||
result.add(SpellCheckingScope.Comments);
|
||||
if(processCode)
|
||||
result.add(SpellCheckingScope.Code);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits element text in tokens according to spell checker strategy of given language
|
||||
*
|
||||
* @param element Psi element
|
||||
* @param allowedScopes
|
||||
* @param language Usually element.getLanguage()
|
||||
* @param consumer the consumer of tokens
|
||||
*/
|
||||
public static void tokenize(final @NotNull PsiElement element, final @NotNull Language language, TokenConsumer consumer) {
|
||||
public static void tokenize(@NotNull final PsiElement element,
|
||||
@NotNull final Language language,
|
||||
TokenConsumer consumer, Set<SpellCheckingScope> allowedScopes) {
|
||||
SpellcheckingStrategy factoryByLanguage = getSpellcheckingStrategy(element, language);
|
||||
if (factoryByLanguage == null) {
|
||||
return;
|
||||
}
|
||||
Tokenizer tokenizer = factoryByLanguage.getTokenizer(element);
|
||||
tokenize(factoryByLanguage, element, consumer, allowedScopes);
|
||||
}
|
||||
|
||||
private static void tokenize(SpellcheckingStrategy strategy, PsiElement element, TokenConsumer consumer, Set<SpellCheckingScope> allowedScopes) {
|
||||
var tokenizer = strategy.getTokenizer(element, allowedScopes);
|
||||
//noinspection unchecked
|
||||
tokenizer.tokenize(element, consumer);
|
||||
}
|
||||
@@ -239,4 +244,10 @@ public final class SpellCheckingInspection extends LocalInspectionTool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpellCheckingScope {
|
||||
Comments,
|
||||
Literals,
|
||||
Code,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,20 @@ package com.intellij.spellchecker.tokenizer;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.SuppressionUtil;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageParserDefinitions;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
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.inspections.PlainTextSplitter;
|
||||
import com.intellij.spellchecker.inspections.SpellCheckingInspection;
|
||||
import com.intellij.spellchecker.quickfixes.ChangeTo;
|
||||
import com.intellij.spellchecker.quickfixes.RenameTo;
|
||||
import com.intellij.spellchecker.quickfixes.SaveTo;
|
||||
@@ -22,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines spellchecking support for a custom language.
|
||||
@@ -50,6 +56,10 @@ public class SpellcheckingStrategy {
|
||||
private static final SpellCheckerQuickFix[] BATCH_FIXES =
|
||||
new SpellCheckerQuickFix[]{SaveTo.getSaveToLevelFix(DictionaryLevel.APP), SaveTo.getSaveToLevelFix(DictionaryLevel.PROJECT)};
|
||||
|
||||
public Tokenizer getTokenizer(PsiElement element, Set<SpellCheckingInspection.SpellCheckingScope> scope) {
|
||||
return getTokenizer(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link #EMPTY_TOKENIZER} to skip spellchecking, {@link #TEXT_TOKENIZER} for full element text or custom Tokenizer implementation.
|
||||
*/
|
||||
@@ -82,6 +92,30 @@ public class SpellcheckingStrategy {
|
||||
return EMPTY_TOKENIZER;
|
||||
}
|
||||
|
||||
public boolean elementFitsScope(@NotNull PsiElement element, Set<SpellCheckingInspection.SpellCheckingScope> scope) {
|
||||
|
||||
final Language language = element.getLanguage();
|
||||
final IElementType elementType = element.getNode().getElementType();
|
||||
final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
|
||||
|
||||
if (parserDefinition != null) {
|
||||
if (parserDefinition.getStringLiteralElements().contains(elementType)) {
|
||||
if (!scope.contains(SpellCheckingInspection.SpellCheckingScope.Literals)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (parserDefinition.getCommentTokens().contains(elementType)) {
|
||||
if (!scope.contains(SpellCheckingInspection.SpellCheckingScope.Comments)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!scope.contains(SpellCheckingInspection.SpellCheckingScope.Code)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static boolean isInjectedLanguageFragment(@Nullable PsiElement element) {
|
||||
return element instanceof PsiLanguageInjectionHost
|
||||
&& InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)element);
|
||||
|
||||
Reference in New Issue
Block a user