WEB-13777 Add "Colors and fonts" page for JSON

This commit is contained in:
Mikhail Golubev
2014-10-16 14:32:58 +04:00
parent d60458de9b
commit 6be53e35b5
7 changed files with 211 additions and 81 deletions
+2 -2
View File
@@ -14,6 +14,6 @@
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="xml-openapi" />
<orderEntry type="module" module-name="spellchecker" />
<orderEntry type="library" name="Guava" level="project" />
</component>
</module>
</module>
@@ -1,73 +0,0 @@
package com.intellij.json;
import com.intellij.lexer.LayeredLexer;
import com.intellij.lexer.Lexer;
import com.intellij.lexer.StringLiteralLexer;
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import static com.intellij.json.JsonElementTypes.*;
import static com.intellij.psi.StringEscapesTokenTypes.*;
public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
@NotNull
@Override
public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
return new MyHighlighter();
}
private static class MyHighlighter extends SyntaxHighlighterBase {
private static final Map<IElementType, TextAttributesKey> ourAttributes = new HashMap<IElementType, TextAttributesKey>();
static {
fillMap(ourAttributes, DefaultLanguageHighlighterColors.BRACES, L_CURLY, R_CURLY);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.BRACKETS, L_BRACKET, R_BRACKET);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.COMMA, COMMA);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.SEMICOLON, COLON);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.STRING, DOUBLE_QUOTED_STRING);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.STRING, SINGLE_QUOTED_STRING);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.NUMBER, NUMBER);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.KEYWORD, TRUE, FALSE, NULL);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.LINE_COMMENT, LINE_COMMENT);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.BLOCK_COMMENT, BLOCK_COMMENT);
// TODO may be it's worth to add more sensible highlighting for identifiers
fillMap(ourAttributes, HighlighterColors.TEXT, INDENTIFIER);
fillMap(ourAttributes, HighlighterColors.BAD_CHARACTER, TokenType.BAD_CHARACTER);
// StringLexer's tokens
fillMap(ourAttributes, DefaultLanguageHighlighterColors.VALID_STRING_ESCAPE, VALID_STRING_ESCAPE_TOKEN);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE, INVALID_CHARACTER_ESCAPE_TOKEN);
fillMap(ourAttributes, DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE, INVALID_UNICODE_ESCAPE_TOKEN);
}
@NotNull
@Override
public Lexer getHighlightingLexer() {
LayeredLexer layeredLexer = new LayeredLexer(new JsonLexer());
layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', DOUBLE_QUOTED_STRING, false, "/", false, false),
new IElementType[]{DOUBLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', SINGLE_QUOTED_STRING, false, "/", false, false),
new IElementType[]{SINGLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
return layeredLexer;
}
@NotNull
@Override
public TextAttributesKey[] getTokenHighlights(IElementType type) {
return pack(ourAttributes.get(type));
}
}
}
@@ -1,13 +1,13 @@
package com.intellij.json.codeinsight;
import com.intellij.json.JsonBundle;
import com.intellij.json.highlighting.JsonSyntaxHighlighterFactory;
import com.intellij.json.psi.JsonNumberLiteral;
import com.intellij.json.psi.JsonPsiUtil;
import com.intellij.json.psi.JsonStringLiteral;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
@@ -23,7 +23,7 @@ public class JsonLiteralAnnotator implements Annotator {
private static final Pattern VALID_ESCAPE = Pattern.compile("\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})");
private static final Pattern VALID_NUMBER_LITERAL = Pattern.compile("-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?");
private static boolean debug = ApplicationManager.getApplication().isUnitTestMode();
private static final boolean DEBUG = ApplicationManager.getApplication().isUnitTestMode();
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
@@ -31,8 +31,7 @@ public class JsonLiteralAnnotator implements Annotator {
final JsonStringLiteral stringLiteral = (JsonStringLiteral)element;
final int elementOffset = element.getTextOffset();
if (JsonPsiUtil.isPropertyKey(element)) {
holder.createInfoAnnotation(element, debug ? "instance field" : null).setTextAttributes(
DefaultLanguageHighlighterColors.INSTANCE_FIELD);
holder.createInfoAnnotation(element, DEBUG ? "property key" : null).setTextAttributes(JsonSyntaxHighlighterFactory.JSON_PROPERTY_KEY);
}
final String text = element.getText();
final int length = text.length();
@@ -0,0 +1,106 @@
package com.intellij.json.highlighting;
import com.google.common.collect.ImmutableMap;
import com.intellij.application.options.colors.InspectionColorSettingsPage;
import com.intellij.icons.AllIcons;
import com.intellij.json.JsonLanguage;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.openapi.options.colors.AttributesDescriptor;
import com.intellij.openapi.options.colors.ColorDescriptor;
import com.intellij.openapi.options.colors.ColorSettingsPage;
import com.intellij.psi.codeStyle.DisplayPriority;
import com.intellij.psi.codeStyle.DisplayPrioritySortable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Map;
import static com.intellij.json.highlighting.JsonSyntaxHighlighterFactory.*;
/**
* @author Mikhail Golubev
*/
public class JsonColorsPage implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
private static final Map<String, TextAttributesKey> ourAdditionalHighlighting = ImmutableMap.of("propertyKey", JSON_PROPERTY_KEY);
private static final AttributesDescriptor[] ourAttributeDescriptors = new AttributesDescriptor[]{
new AttributesDescriptor("Property key", JSON_PROPERTY_KEY),
new AttributesDescriptor("Braces", JSON_BRACES),
new AttributesDescriptor("Brackets", JSON_BRACKETS),
new AttributesDescriptor("Comma", JSON_COMMA),
new AttributesDescriptor("Colon", JSON_COLON),
new AttributesDescriptor("Number", JSON_NUMBER),
new AttributesDescriptor("String", JSON_STRING),
new AttributesDescriptor("Keyword", JSON_KEYWORD),
new AttributesDescriptor("Line comment", JSON_LINE_COMMENT),
new AttributesDescriptor("Block comment", JSON_BLOCK_COMMENT),
//new AttributesDescriptor("", JSON_IDENTIFIER),
new AttributesDescriptor("Valid escape sequence", JSON_VALID_ESCAPE),
new AttributesDescriptor("Invalid escape sequence", JSON_INVALID_ESCAPE),
};
@Nullable
@Override
public Icon getIcon() {
return AllIcons.FileTypes.Json;
}
@NotNull
@Override
public SyntaxHighlighter getHighlighter() {
return SyntaxHighlighterFactory.getSyntaxHighlighter(JsonLanguage.INSTANCE, null, null);
}
@NotNull
@Override
public String getDemoText() {
return "{\n" +
" // Line comments are not included in standard but nonetheless allowed.\n" +
" /* As well as block comments. */\n" +
" <propertyKey>\"the only keywords are\"</propertyKey>: [true, false, null],\n" +
" <propertyKey>\"strings with\"</propertyKey>: {\n" +
" <propertyKey>\"no excapes\"</propertyKey>: \"pseudopolinomiality\"\n" +
" <propertyKey>\"valid escapes\"</propertyKey>: \"C-style\\r\\n and unicode\\u0021\",\n" +
" <propertyKey>\"illegal escapes\"</propertyKey>: \"\\0377\\x\\\"\n" +
" },\n" +
" <propertyKey>\"some numbers\"</propertyKey>: [\n" +
" 42,\n" +
" -0.0e-0,\n" +
" 6.626e-34\n" +
" ] \n" +
"}";
}
@Nullable
@Override
public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
return ourAdditionalHighlighting;
}
@NotNull
@Override
public AttributesDescriptor[] getAttributeDescriptors() {
return ourAttributeDescriptors;
}
@NotNull
@Override
public ColorDescriptor[] getColorDescriptors() {
return ColorDescriptor.EMPTY_ARRAY;
}
@NotNull
@Override
public String getDisplayName() {
return "JSON";
}
@Override
public DisplayPriority getPriority() {
return DisplayPriority.LANGUAGE_SETTINGS;
}
}
@@ -0,0 +1,97 @@
package com.intellij.json.highlighting;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.JsonLexer;
import com.intellij.lexer.LayeredLexer;
import com.intellij.lexer.Lexer;
import com.intellij.lexer.StringLiteralLexer;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.*;
public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
public static final TextAttributesKey JSON_BRACKETS = TextAttributesKey.createTextAttributesKey("JSON.BRACKETS", BRACKETS);
public static final TextAttributesKey JSON_BRACES = TextAttributesKey.createTextAttributesKey("JSON.BRACES", BRACES);
public static final TextAttributesKey JSON_COMMA = TextAttributesKey.createTextAttributesKey("JSON.BRACES", COMMA);
public static final TextAttributesKey JSON_COLON = TextAttributesKey.createTextAttributesKey("JSON.COLON", SEMICOLON);
public static final TextAttributesKey JSON_NUMBER = TextAttributesKey.createTextAttributesKey("JSON.NUMBER", NUMBER);
public static final TextAttributesKey JSON_STRING = TextAttributesKey.createTextAttributesKey("JSON.STRING", STRING);
public static final TextAttributesKey JSON_KEYWORD = TextAttributesKey.createTextAttributesKey("JSON.KEYWORD", KEYWORD);
public static final TextAttributesKey JSON_LINE_COMMENT = TextAttributesKey.createTextAttributesKey("JSON.LINE_COMMENT", LINE_COMMENT);
public static final TextAttributesKey JSON_BLOCK_COMMENT = TextAttributesKey.createTextAttributesKey("JSON.BLOCK_COMMENT", BLOCK_COMMENT);
// Artificial element type
public static final TextAttributesKey JSON_IDENTIFIER = TextAttributesKey.createTextAttributesKey("JSON.IDENTIFIER", IDENTIFIER);
// Added by annotators
public static final TextAttributesKey JSON_PROPERTY_KEY = TextAttributesKey.createTextAttributesKey("JSON.PROPERTY_KEY", INSTANCE_FIELD);
// String escapes
public static final TextAttributesKey JSON_VALID_ESCAPE =
TextAttributesKey.createTextAttributesKey("JSON.VALID_ESCAPE", VALID_STRING_ESCAPE);
public static final TextAttributesKey JSON_INVALID_ESCAPE =
TextAttributesKey.createTextAttributesKey("JSON.INVALID_ESCAPE", INVALID_STRING_ESCAPE);
@NotNull
@Override
public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
return new MyHighlighter();
}
private static class MyHighlighter extends SyntaxHighlighterBase {
private static final Map<IElementType, TextAttributesKey> ourAttributes = new HashMap<IElementType, TextAttributesKey>();
static {
fillMap(ourAttributes, JSON_BRACES, JsonElementTypes.L_CURLY, JsonElementTypes.R_CURLY);
fillMap(ourAttributes, JSON_BRACKETS, JsonElementTypes.L_BRACKET, JsonElementTypes.R_BRACKET);
fillMap(ourAttributes, JSON_COMMA, JsonElementTypes.COMMA);
fillMap(ourAttributes, JSON_COLON, JsonElementTypes.COLON);
fillMap(ourAttributes, JSON_STRING, JsonElementTypes.DOUBLE_QUOTED_STRING);
fillMap(ourAttributes, JSON_STRING, JsonElementTypes.SINGLE_QUOTED_STRING);
fillMap(ourAttributes, JSON_NUMBER, JsonElementTypes.NUMBER);
fillMap(ourAttributes, JSON_KEYWORD, JsonElementTypes.TRUE, JsonElementTypes.FALSE, JsonElementTypes.NULL);
fillMap(ourAttributes, JSON_LINE_COMMENT, JsonElementTypes.LINE_COMMENT);
fillMap(ourAttributes, JSON_BLOCK_COMMENT, JsonElementTypes.BLOCK_COMMENT);
// TODO may be it's worth to add more sensible highlighting for identifiers
fillMap(ourAttributes, JSON_IDENTIFIER, JsonElementTypes.INDENTIFIER);
fillMap(ourAttributes, HighlighterColors.BAD_CHARACTER, TokenType.BAD_CHARACTER);
fillMap(ourAttributes, JSON_VALID_ESCAPE, StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN);
fillMap(ourAttributes, JSON_INVALID_ESCAPE, StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN);
fillMap(ourAttributes, JSON_INVALID_ESCAPE, StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN);
}
@NotNull
@Override
public Lexer getHighlightingLexer() {
LayeredLexer layeredLexer = new LayeredLexer(new JsonLexer());
layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', JsonElementTypes.DOUBLE_QUOTED_STRING, false, "/", false, false),
new IElementType[]{JsonElementTypes.DOUBLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', JsonElementTypes.SINGLE_QUOTED_STRING, false, "/", false, false),
new IElementType[]{JsonElementTypes.SINGLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
return layeredLexer;
}
@NotNull
@Override
public TextAttributesKey[] getTokenHighlights(IElementType type) {
return pack(ourAttributes.get(type));
}
}
}
@@ -1,3 +1,3 @@
{
<info descr="instance field">"aaa"</info>:123
<info descr="property key">"aaa"</info>:123
}
@@ -17,11 +17,12 @@
<extensions defaultExtensionNs="com.intellij">
<fileTypeFactory implementation="com.intellij.json.JsonFileTypeFactory"/>
<lang.parserDefinition language="JSON" implementationClass="com.intellij.json.JsonParserDefinition"/>
<lang.syntaxHighlighterFactory key="JSON" implementationClass="com.intellij.json.JsonSyntaxHighlighterFactory"/>
<lang.syntaxHighlighterFactory key="JSON" implementationClass="com.intellij.json.highlighting.JsonSyntaxHighlighterFactory"/>
<!-- Code style and formatting -->
<codeStyleSettingsProvider implementation="com.intellij.json.formatter.JsonCodeStyleSettingsProvider"/>
<langCodeStyleSettingsProvider implementation="com.intellij.json.formatter.JsonLanguageCodeStyleSettingsProvider"/>
<colorSettingsPage implementation="com.intellij.json.highlighting.JsonColorsPage"/>
<lang.formatter language="JSON" implementationClass="com.intellij.json.formatter.JsonFormattingBuilderModel"/>
<lang.braceMatcher language="JSON" implementationClass="com.intellij.json.JsonBraceMatcher"/>
<quoteHandler fileType="JSON" className="com.intellij.json.JsonQuoteHandler"/>