ccdc1199f5342018584a3c9d1caf08b36f3821f8
[idea/community.git] / spellchecker / src / com / intellij / spellchecker / tokenizer / SpellcheckingStrategy.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.spellchecker.tokenizer;
17
18 import com.intellij.codeInspection.SuppressionUtil;
19 import com.intellij.openapi.extensions.ExtensionPointName;
20 import com.intellij.openapi.fileTypes.FileType;
21 import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType;
22 import com.intellij.openapi.util.TextRange;
23 import com.intellij.openapi.util.text.StringUtil;
24 import com.intellij.psi.*;
25 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
26 import com.intellij.psi.xml.XmlAttributeValue;
27 import com.intellij.psi.xml.XmlText;
28 import com.intellij.spellchecker.inspections.PlainTextSplitter;
29 import com.intellij.spellchecker.inspections.TextSplitter;
30 import com.intellij.spellchecker.quickfixes.AcceptWordAsCorrect;
31 import com.intellij.spellchecker.quickfixes.ChangeTo;
32 import com.intellij.spellchecker.quickfixes.RenameTo;
33 import com.intellij.spellchecker.quickfixes.SpellCheckerQuickFix;
34 import org.jetbrains.annotations.NotNull;
35
36 public class SpellcheckingStrategy {
37   protected final Tokenizer<PsiComment> myCommentTokenizer = new CommentTokenizer();
38   protected final Tokenizer<XmlAttributeValue> myXmlAttributeTokenizer = new XmlAttributeValueTokenizer();
39   protected final Tokenizer<XmlText> myXmlTextTokenizer = new XmlTextTokenizer();
40
41   public static final ExtensionPointName<SpellcheckingStrategy> EP_NAME = ExtensionPointName.create("com.intellij.spellchecker.support");
42   public static final Tokenizer EMPTY_TOKENIZER = new Tokenizer() {
43     @Override
44     public void tokenize(@NotNull PsiElement element, TokenConsumer consumer) {
45     }
46   };
47
48   public static final Tokenizer<PsiElement> TEXT_TOKENIZER = new TokenizerBase<PsiElement>(PlainTextSplitter.getInstance());
49
50   private static final SpellCheckerQuickFix[] BATCH_FIXES = new SpellCheckerQuickFix[]{new AcceptWordAsCorrect()};
51
52   @NotNull
53   public Tokenizer getTokenizer(PsiElement element) {
54     if (element instanceof PsiLanguageInjectionHost && InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)element)) {
55       return EMPTY_TOKENIZER;
56     }
57     if (element instanceof PsiNameIdentifierOwner) return new PsiIdentifierOwnerTokenizer();
58     if (element instanceof PsiComment) {
59       if (SuppressionUtil.isSuppressionComment(element)) {
60         return EMPTY_TOKENIZER;
61       }
62       return myCommentTokenizer;
63     }
64     if (element instanceof XmlAttributeValue) return myXmlAttributeTokenizer;
65     if (element instanceof XmlText) return myXmlTextTokenizer;
66     if (element instanceof PsiPlainText) {
67       PsiFile file = element.getContainingFile();
68       FileType fileType = file == null ? null : file.getFileType();
69       if (fileType instanceof CustomSyntaxTableFileType) {
70         return new CustomFileTypeTokenizer(((CustomSyntaxTableFileType)fileType).getSyntaxTable());
71       }
72       return TEXT_TOKENIZER;
73     }
74     return EMPTY_TOKENIZER;
75   }
76
77   public SpellCheckerQuickFix[] getRegularFixes(PsiElement element,
78                                                 int offset,
79                                                 @NotNull TextRange textRange,
80                                                 boolean useRename,
81                                                 String wordWithTypo) {
82     return getDefaultRegularFixes(useRename, wordWithTypo);
83   }
84
85   public static SpellCheckerQuickFix[] getDefaultRegularFixes(boolean useRename, String wordWithTypo) {
86     return new SpellCheckerQuickFix[]{
87       useRename ? new RenameTo(wordWithTypo) : new ChangeTo(wordWithTypo),
88       new AcceptWordAsCorrect(wordWithTypo)
89     };
90   }
91
92   public static SpellCheckerQuickFix[] getDefaultBatchFixes() {
93     return BATCH_FIXES;
94   }
95
96   protected static class XmlAttributeValueTokenizer extends Tokenizer<XmlAttributeValue> {
97     public void tokenize(@NotNull final XmlAttributeValue element, final TokenConsumer consumer) {
98       if (element instanceof PsiLanguageInjectionHost && InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)element)) return;
99
100       final String valueTextTrimmed = element.getValue().trim();
101       // do not inspect colors like #00aaFF
102       if (valueTextTrimmed.startsWith("#") && valueTextTrimmed.length() <= 7 && isHexString(valueTextTrimmed.substring(1))) {
103         return;
104       }
105
106       consumer.consumeToken(element, TextSplitter.getInstance());
107     }
108
109     private static boolean isHexString(final String s) {
110       for (int i = 0; i < s.length(); i++) {
111         if (!StringUtil.isHexDigit(s.charAt(i))) {
112           return false;
113         }
114       }
115       return true;
116     }
117   }
118
119   public boolean isMyContext(@NotNull PsiElement element) {
120     return true;
121   }
122 }