Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2014-09-17 13:50:44 +04:00
229 changed files with 6479 additions and 62 deletions
+2
View File
@@ -122,6 +122,8 @@
<module fileurl="file://$PROJECT_DIR$/jps/plugin-system/jps-plugin-system.iml" filepath="$PROJECT_DIR$/jps/plugin-system/jps-plugin-system.iml" group="jps" />
<module fileurl="file://$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" filepath="$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" group="jps" />
<module fileurl="file://$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" filepath="$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" group="jps" />
<module fileurl="file://$PROJECT_DIR$/json/json.iml" filepath="$PROJECT_DIR$/json/json.iml" group="json" />
<module fileurl="file://$PROJECT_DIR$/json/tests/json-tests.iml" filepath="$PROJECT_DIR$/json/tests/json-tests.iml" group="json" />
<module fileurl="file://$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" filepath="$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" group="java" />
<module fileurl="file://$PROJECT_DIR$/java/jsp-openapi/jsp-openapi.iml" filepath="$PROJECT_DIR$/java/jsp-openapi/jsp-openapi.iml" group="java" />
<module fileurl="file://$PROJECT_DIR$/java/jsp-spi/jsp-spi.iml" filepath="$PROJECT_DIR$/java/jsp-spi/jsp-spi.iml" group="java" />
+2
View File
@@ -105,6 +105,8 @@
<orderEntry type="module" module-name="structuralsearch-java" />
<orderEntry type="module" module-name="structuralsearch-tests" scope="TEST" />
<orderEntry type="module" module-name="structuralsearch-groovy" />
<orderEntry type="module" module-name="json" />
<orderEntry type="module" module-name="json-tests" scope="TEST" />
<orderEntry type="module" module-name="typeMigration" />
</component>
</module>
@@ -326,7 +326,7 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction {
if (parameter == null) {
continue;
}
notNull(project, field, parameter);
notNull(field, parameter);
cleanupElements.add(parameter);
final PsiElement assignmentStatement = AssignFieldFromParameterAction.addFieldAssignmentStatement(project, field, parameter, editor);
if (assignmentStatement != null) {
@@ -338,11 +338,10 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction {
return created;
}
private static void notNull(Project project, PsiField field, PsiParameter parameter) {
final String notNull = NullableNotNullManager.getInstance(field.getProject()).getNotNull(field);
private static void notNull(PsiField field, PsiParameter parameter) {
final PsiAnnotation notNull = NullableNotNullManager.getInstance(field.getProject()).copyNotNullAnnotation(field);
if (notNull != null) {
final PsiAnnotation annotation = JavaPsiFacade.getElementFactory(project).createAnnotationFromText("@" + notNull, field);
parameter.getModifierList().addBefore(annotation, null);
parameter.getModifierList().addBefore(notNull, null);
}
}
@@ -265,9 +265,9 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
PsiParameter parm = factory.createParameter(parmName, field.getType(), aClass);
final NullableNotNullManager nullableManager = NullableNotNullManager.getInstance(field.getProject());
final String notNull = nullableManager.getNotNull(field);
final PsiAnnotation notNull = nullableManager.copyNotNullAnnotation(field);
if (notNull != null) {
parm.getModifierList().addAfter(factory.createAnnotationFromText("@" + notNull, field), null);
parm.getModifierList().addAfter(notNull, null);
}
constructor.getParameterList().add(parm);
@@ -187,14 +187,14 @@ public final class FieldFromParameterUtils {
modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
final PsiAnnotation nullable = manager.getNullableAnnotation(parameter, false);
if (nullable != null && !manager.isContainerAnnotation(nullable)) {
modifierList.addAfter(factory.createAnnotationFromText("@" + nullable.getQualifiedName(), field), null);
final PsiAnnotation nullable = manager.copyNullableAnnotation(parameter);
if (nullable != null) {
modifierList.addAfter(nullable, null);
}
else if (isFinal) {
final PsiAnnotation notNull = manager.getNotNullAnnotation(parameter, false);
if (notNull != null && !manager.isContainerAnnotation(notNull)) {
modifierList.addAfter(factory.createAnnotationFromText("@" + notNull.getQualifiedName(), field), null);
final PsiAnnotation notNull = manager.copyNotNullAnnotation(parameter);
if (notNull != null) {
modifierList.addAfter(notNull, null);
}
}
@@ -518,14 +518,14 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
final PsiModifierList modifierList = methodToAdd.getModifierList();
final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
modifierList.setModifierProperty(PsiModifier.ABSTRACT, false);
final String nullable = manager.getNullable(method);
final PsiAnnotation nullable = manager.copyNullableAnnotation(method);
if (nullable != null) {
modifierList.addAfter(myFactory.createAnnotationFromText("@" + nullable, methodToAdd), null);
modifierList.addAfter(nullable, null);
}
else {
final String notNull = manager.getNotNull(method);
final PsiAnnotation notNull = manager.copyNotNullAnnotation(method);
if (notNull != null) {
modifierList.addAfter(myFactory.createAnnotationFromText("@" + notNull, methodToAdd), null);
modifierList.addAfter(notNull, null);
}
}
@@ -95,13 +95,25 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
public String getDefaultNullable() {
return myDefaultNullable;
}
@Nullable
public String getNullable(@NotNull PsiModifierListOwner owner) {
PsiAnnotation annotation = getNullableAnnotation(owner, false);
return annotation == null ? null : annotation.getQualifiedName();
}
private String checkContainer(PsiAnnotation annotation, boolean acceptContainer) {
if (annotation == null) {
return null;
}
else {
if (!acceptContainer && isContainerAnnotation(annotation)) {
return null;
}
return annotation.getQualifiedName();
}
}
@Nullable
public PsiAnnotation getNullableAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases) {
return findNullabilityAnnotation(owner, checkBases, true);
@@ -127,6 +139,23 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
return findNullabilityAnnotation(owner, checkBases, false);
}
public PsiAnnotation copyNotNullAnnotation(PsiModifierListOwner owner) {
return copyAnnotation(owner, getNotNullAnnotation(owner, false));
}
public PsiAnnotation copyNullableAnnotation(PsiModifierListOwner owner) {
return copyAnnotation(owner, getNullableAnnotation(owner, false));
}
private PsiAnnotation copyAnnotation(PsiModifierListOwner owner,
PsiAnnotation annotation) {
final String notNull = checkContainer(annotation, false);
if (notNull != null) {
return JavaPsiFacade.getElementFactory(owner.getProject()).createAnnotationFromText("@" + notNull, owner);
}
return null;
}
@Nullable
public String getNotNull(@NotNull PsiModifierListOwner owner) {
PsiAnnotation annotation = getNotNullAnnotation(owner, false);
@@ -413,7 +413,7 @@ public class PropertyUtil {
PsiUtil.setModifierProperty(getMethod, PsiModifier.STATIC, true);
}
annotateWithNullableStuff(field, factory, getMethod);
annotateWithNullableStuff(field, getMethod);
PsiCodeBlock body = factory.createCodeBlockFromText("{\nreturn " + name + ";\n}", null);
getMethod.getBody().replace(body);
@@ -466,7 +466,7 @@ public class PropertyUtil {
String parameterName = codeStyleManager.propertyNameToVariableName(propertyName, VariableKind.PARAMETER);
PsiParameter param = factory.createParameter(parameterName, field.getType());
annotateWithNullableStuff(field, factory, param);
annotateWithNullableStuff(field, param);
setMethod.getParameterList().add(param);
PsiUtil.setModifierProperty(setMethod, PsiModifier.PUBLIC, true);
@@ -506,27 +506,26 @@ public class PropertyUtil {
}
private static void annotateWithNullableStuff(final PsiModifierListOwner field,
final PsiElementFactory factory,
final PsiModifierListOwner listOwner)
throws IncorrectOperationException {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(field.getProject());
final String notNull = manager.getNotNull(field);
final PsiAnnotation notNull = manager.copyNotNullAnnotation(field);
if (notNull != null) {
annotate(factory, listOwner, notNull);
annotate(listOwner, notNull);
}
else {
final String nullable = manager.getNullable(field);
final PsiAnnotation nullable = manager.copyNullableAnnotation(field);
if (nullable != null) {
annotate(factory, listOwner, nullable);
annotate(listOwner, nullable);
}
}
}
private static void annotate(final PsiElementFactory factory, final PsiModifierListOwner listOwner, final String annotationQName)
private static void annotate(final PsiModifierListOwner listOwner, final PsiAnnotation annotation)
throws IncorrectOperationException {
final PsiModifierList modifierList = listOwner.getModifierList();
LOG.assertTrue(modifierList != null);
modifierList.addAfter(factory.createAnnotationFromText("@" + annotationQName, listOwner), null);
modifierList.addAfter(annotation, null);
}
public static String suggestPropertyName(@NotNull PsiField field) {
@@ -0,0 +1,74 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.PsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.json.psi.impl.*;
public interface JsonElementTypes {
IElementType ARRAY = new JsonElementType("ARRAY");
IElementType BOOLEAN_LITERAL = new JsonElementType("BOOLEAN_LITERAL");
IElementType LITERAL = new JsonElementType("LITERAL");
IElementType NULL_LITERAL = new JsonElementType("NULL_LITERAL");
IElementType NUMBER_LITERAL = new JsonElementType("NUMBER_LITERAL");
IElementType OBJECT = new JsonElementType("OBJECT");
IElementType PROPERTY = new JsonElementType("PROPERTY");
IElementType REFERENCE_EXPRESSION = new JsonElementType("REFERENCE_EXPRESSION");
IElementType STRING_LITERAL = new JsonElementType("STRING_LITERAL");
IElementType VALUE = new JsonElementType("VALUE");
IElementType BLOCK_COMMENT = new JsonTokenType("BLOCK_COMMENT");
IElementType COLON = new JsonTokenType(":");
IElementType COMMA = new JsonTokenType(",");
IElementType DOUBLE_QUOTED_STRING = new JsonTokenType("DOUBLE_QUOTED_STRING");
IElementType FALSE = new JsonTokenType("false");
IElementType INDENTIFIER = new JsonTokenType("INDENTIFIER");
IElementType LINE_COMMENT = new JsonTokenType("LINE_COMMENT");
IElementType L_BRACKET = new JsonTokenType("[");
IElementType L_CURLY = new JsonTokenType("{");
IElementType NULL = new JsonTokenType("null");
IElementType NUMBER = new JsonTokenType("NUMBER");
IElementType R_BRACKET = new JsonTokenType("]");
IElementType R_CURLY = new JsonTokenType("}");
IElementType SINGLE_QUOTED_STRING = new JsonTokenType("SINGLE_QUOTED_STRING");
IElementType TRUE = new JsonTokenType("true");
class Factory {
public static PsiElement createElement(ASTNode node) {
IElementType type = node.getElementType();
if (type == ARRAY) {
return new JsonArrayImpl(node);
}
else if (type == BOOLEAN_LITERAL) {
return new JsonBooleanLiteralImpl(node);
}
else if (type == LITERAL) {
return new JsonLiteralImpl(node);
}
else if (type == NULL_LITERAL) {
return new JsonNullLiteralImpl(node);
}
else if (type == NUMBER_LITERAL) {
return new JsonNumberLiteralImpl(node);
}
else if (type == OBJECT) {
return new JsonObjectImpl(node);
}
else if (type == PROPERTY) {
return new JsonPropertyImpl(node);
}
else if (type == REFERENCE_EXPRESSION) {
return new JsonReferenceExpressionImpl(node);
}
else if (type == STRING_LITERAL) {
return new JsonStringLiteralImpl(node);
}
else if (type == VALUE) {
return new JsonValueImpl(node);
}
throw new AssertionError("Unknown element type: " + type);
}
}
}
+12
View File
@@ -0,0 +1,12 @@
package com.intellij.json;
import com.intellij.lexer.FlexAdapter;
/**
* @author Mikhail Golubev
*/
public class JsonLexer extends FlexAdapter {
public JsonLexer() {
super(new _JsonLexer());
}
}
+387
View File
@@ -0,0 +1,387 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilder.Marker;
import com.intellij.openapi.diagnostic.Logger;
import static com.intellij.json.JsonElementTypes.*;
import static com.intellij.json.psi.JsonParserUtil.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.lang.ASTNode;
import com.intellij.psi.tree.TokenSet;
import com.intellij.lang.PsiParser;
@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"})
public class JsonParser implements PsiParser {
public static final Logger LOG_ = Logger.getInstance("com.intellij.json.JsonParser");
public ASTNode parse(IElementType root_, PsiBuilder builder_) {
boolean result_;
builder_ = adapt_builder_(root_, builder_, this, EXTENDS_SETS_);
Marker marker_ = enter_section_(builder_, 0, _COLLAPSE_, null);
if (root_ == ARRAY) {
result_ = array(builder_, 0);
}
else if (root_ == BOOLEAN_LITERAL) {
result_ = boolean_literal(builder_, 0);
}
else if (root_ == LITERAL) {
result_ = literal(builder_, 0);
}
else if (root_ == NULL_LITERAL) {
result_ = null_literal(builder_, 0);
}
else if (root_ == NUMBER_LITERAL) {
result_ = number_literal(builder_, 0);
}
else if (root_ == OBJECT) {
result_ = object(builder_, 0);
}
else if (root_ == PROPERTY) {
result_ = property(builder_, 0);
}
else if (root_ == REFERENCE_EXPRESSION) {
result_ = reference_expression(builder_, 0);
}
else if (root_ == STRING_LITERAL) {
result_ = string_literal(builder_, 0);
}
else if (root_ == VALUE) {
result_ = value(builder_, 0);
}
else {
result_ = parse_root_(root_, builder_, 0);
}
exit_section_(builder_, 0, marker_, root_, result_, true, TRUE_CONDITION);
return builder_.getTreeBuilt();
}
protected boolean parse_root_(final IElementType root_, final PsiBuilder builder_, final int level_) {
return json(builder_, level_ + 1);
}
public static final TokenSet[] EXTENDS_SETS_ = new TokenSet[] {
create_token_set_(BOOLEAN_LITERAL, LITERAL, NULL_LITERAL, NUMBER_LITERAL,
STRING_LITERAL),
create_token_set_(ARRAY, BOOLEAN_LITERAL, LITERAL, NULL_LITERAL,
NUMBER_LITERAL, OBJECT, REFERENCE_EXPRESSION, STRING_LITERAL,
VALUE),
};
/* ********************************************************** */
// '[' array_element* ']'
public static boolean array(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "array")) return false;
if (!nextTokenIs(builder_, L_BRACKET)) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
result_ = consumeToken(builder_, L_BRACKET);
pinned_ = result_; // pin = 1
result_ = result_ && report_error_(builder_, array_1(builder_, level_ + 1));
result_ = pinned_ && consumeToken(builder_, R_BRACKET) && result_;
exit_section_(builder_, level_, marker_, ARRAY, result_, pinned_, null);
return result_ || pinned_;
}
// array_element*
private static boolean array_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "array_1")) return false;
int pos_ = current_position_(builder_);
while (true) {
if (!array_element(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "array_1", pos_)) break;
pos_ = current_position_(builder_);
}
return true;
}
/* ********************************************************** */
// value (','|&']')
static boolean array_element(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "array_element")) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
result_ = value(builder_, level_ + 1);
pinned_ = result_; // pin = 1
result_ = result_ && array_element_1(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, null, result_, pinned_, not_bracket_or_next_value_parser_);
return result_ || pinned_;
}
// ','|&']'
private static boolean array_element_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "array_element_1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
if (!result_) result_ = array_element_1_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// &']'
private static boolean array_element_1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "array_element_1_1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _AND_, null);
result_ = consumeToken(builder_, R_BRACKET);
exit_section_(builder_, level_, marker_, null, result_, false, null);
return result_;
}
/* ********************************************************** */
// TRUE | FALSE
public static boolean boolean_literal(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "boolean_literal")) return false;
if (!nextTokenIs(builder_, "<boolean literal>", FALSE, TRUE)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _COLLAPSE_, "<boolean literal>");
result_ = consumeToken(builder_, TRUE);
if (!result_) result_ = consumeToken(builder_, FALSE);
exit_section_(builder_, level_, marker_, BOOLEAN_LITERAL, result_, false, null);
return result_;
}
/* ********************************************************** */
// value
static boolean json(PsiBuilder builder_, int level_) {
return value(builder_, level_ + 1);
}
/* ********************************************************** */
// string_literal | number_literal | boolean_literal | null_literal
public static boolean literal(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "literal")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _COLLAPSE_, "<literal>");
result_ = string_literal(builder_, level_ + 1);
if (!result_) result_ = number_literal(builder_, level_ + 1);
if (!result_) result_ = boolean_literal(builder_, level_ + 1);
if (!result_) result_ = null_literal(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, LITERAL, result_, false, null);
return result_;
}
/* ********************************************************** */
// !('}'|value)
static boolean not_brace_or_next_value(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "not_brace_or_next_value")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NOT_, null);
result_ = !not_brace_or_next_value_0(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, null, result_, false, null);
return result_;
}
// '}'|value
private static boolean not_brace_or_next_value_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "not_brace_or_next_value_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, R_CURLY);
if (!result_) result_ = value(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// !(']'|value)
static boolean not_bracket_or_next_value(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "not_bracket_or_next_value")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NOT_, null);
result_ = !not_bracket_or_next_value_0(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, null, result_, false, null);
return result_;
}
// ']'|value
private static boolean not_bracket_or_next_value_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "not_bracket_or_next_value_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, R_BRACKET);
if (!result_) result_ = value(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// NULL
public static boolean null_literal(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "null_literal")) return false;
if (!nextTokenIs(builder_, NULL)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, NULL);
exit_section_(builder_, marker_, NULL_LITERAL, result_);
return result_;
}
/* ********************************************************** */
// NUMBER
public static boolean number_literal(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "number_literal")) return false;
if (!nextTokenIs(builder_, NUMBER)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, NUMBER);
exit_section_(builder_, marker_, NUMBER_LITERAL, result_);
return result_;
}
/* ********************************************************** */
// '{' object_element* '}'
public static boolean object(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "object")) return false;
if (!nextTokenIs(builder_, L_CURLY)) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
result_ = consumeToken(builder_, L_CURLY);
pinned_ = result_; // pin = 1
result_ = result_ && report_error_(builder_, object_1(builder_, level_ + 1));
result_ = pinned_ && consumeToken(builder_, R_CURLY) && result_;
exit_section_(builder_, level_, marker_, OBJECT, result_, pinned_, null);
return result_ || pinned_;
}
// object_element*
private static boolean object_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "object_1")) return false;
int pos_ = current_position_(builder_);
while (true) {
if (!object_element(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "object_1", pos_)) break;
pos_ = current_position_(builder_);
}
return true;
}
/* ********************************************************** */
// property (','|&'}')
static boolean object_element(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "object_element")) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
result_ = property(builder_, level_ + 1);
pinned_ = result_; // pin = 1
result_ = result_ && object_element_1(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, null, result_, pinned_, not_brace_or_next_value_parser_);
return result_ || pinned_;
}
// ','|&'}'
private static boolean object_element_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "object_element_1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
if (!result_) result_ = object_element_1_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// &'}'
private static boolean object_element_1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "object_element_1_1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _AND_, null);
result_ = consumeToken(builder_, R_CURLY);
exit_section_(builder_, level_, marker_, null, result_, false, null);
return result_;
}
/* ********************************************************** */
// property_name (':' value)
public static boolean property(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "property")) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, "<property>");
result_ = property_name(builder_, level_ + 1);
pinned_ = result_; // pin = 1
result_ = result_ && property_1(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, PROPERTY, result_, pinned_, null);
return result_ || pinned_;
}
// ':' value
private static boolean property_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "property_1")) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
result_ = consumeToken(builder_, COLON);
pinned_ = result_; // pin = 1
result_ = result_ && value(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, null, result_, pinned_, null);
return result_ || pinned_;
}
/* ********************************************************** */
// literal | reference_expression
static boolean property_name(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "property_name")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = literal(builder_, level_ + 1);
if (!result_) result_ = reference_expression(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// INDENTIFIER
public static boolean reference_expression(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "reference_expression")) return false;
if (!nextTokenIs(builder_, INDENTIFIER)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, INDENTIFIER);
exit_section_(builder_, marker_, REFERENCE_EXPRESSION, result_);
return result_;
}
/* ********************************************************** */
// SINGLE_QUOTED_STRING | DOUBLE_QUOTED_STRING
public static boolean string_literal(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "string_literal")) return false;
if (!nextTokenIs(builder_, "<string literal>", DOUBLE_QUOTED_STRING, SINGLE_QUOTED_STRING)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _COLLAPSE_, "<string literal>");
result_ = consumeToken(builder_, SINGLE_QUOTED_STRING);
if (!result_) result_ = consumeToken(builder_, DOUBLE_QUOTED_STRING);
exit_section_(builder_, level_, marker_, STRING_LITERAL, result_, false, null);
return result_;
}
/* ********************************************************** */
// object | array | literal | reference_expression
public static boolean value(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "value")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _COLLAPSE_, "<value>");
result_ = object(builder_, level_ + 1);
if (!result_) result_ = array(builder_, level_ + 1);
if (!result_) result_ = literal(builder_, level_ + 1);
if (!result_) result_ = reference_expression(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, VALUE, result_, false, null);
return result_;
}
final static Parser not_brace_or_next_value_parser_ = new Parser() {
public boolean parse(PsiBuilder builder_, int level_) {
return not_brace_or_next_value(builder_, level_ + 1);
}
};
final static Parser not_bracket_or_next_value_parser_ = new Parser() {
public boolean parse(PsiBuilder builder_, int level_) {
return not_bracket_or_next_value(builder_, level_ + 1);
}
};
}
@@ -0,0 +1,54 @@
package com.intellij.json;
import com.intellij.lexer.*;
import com.intellij.psi.tree.IElementType;
import static com.intellij.json.JsonElementTypes.*;
%%
%{
public _JsonLexer() {
this((java.io.Reader)null);
}
%}
%public
%class _JsonLexer
%implements FlexLexer
%function advance
%type IElementType
%unicode
EOL="\r"|"\n"|"\r\n"
LINE_WS=[\ \t\f]
WHITE_SPACE=({LINE_WS}|{EOL})+
LINE_COMMENT="//".*
BLOCK_COMMENT="/"\*([^*]|\*+[^*/])*(\*+"/")?
DOUBLE_QUOTED_STRING=\"([^\\\"\r\n]|\\[^\r\n])*\"?
SINGLE_QUOTED_STRING='([^\\'\r\n]|\\[^\r\n])*'?
NUMBER=-?[0-9]+(\.[0-9]+([eE][+-]?[0-9]+)?)?
INDENTIFIER=[:jletter:] [:jletterdigit:]*
%%
<YYINITIAL> {
{WHITE_SPACE} { return com.intellij.psi.TokenType.WHITE_SPACE; }
"{" { return L_CURLY; }
"}" { return R_CURLY; }
"[" { return L_BRACKET; }
"]" { return R_BRACKET; }
"," { return COMMA; }
":" { return COLON; }
"true" { return TRUE; }
"false" { return FALSE; }
"null" { return NULL; }
{LINE_COMMENT} { return LINE_COMMENT; }
{BLOCK_COMMENT} { return BLOCK_COMMENT; }
{DOUBLE_QUOTED_STRING} { return DOUBLE_QUOTED_STRING; }
{SINGLE_QUOTED_STRING} { return SINGLE_QUOTED_STRING; }
{NUMBER} { return NUMBER; }
{INDENTIFIER} { return INDENTIFIER; }
[^] { return com.intellij.psi.TokenType.BAD_CHARACTER; }
}
+670
View File
@@ -0,0 +1,670 @@
/* The following code was generated by JFlex 1.4.3 on 9/8/14 10:09 PM */
package com.intellij.json;
import com.intellij.lexer.*;
import com.intellij.psi.tree.IElementType;
import static com.intellij.json.JsonElementTypes.*;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 9/8/14 10:09 PM from the specification file
* <tt>/home/east825/develop/repos/IDEA/community/json/gen/com/intellij/json/_JsonLexer.flex</tt>
*/
public class _JsonLexer implements FlexLexer {
/** initial size of the lookahead buffer */
private static final int ZZ_BUFFERSIZE = 16384;
/** lexical states */
public static final int YYINITIAL = 0;
/**
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
* at the beginning of a line
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = {
0, 0
};
/**
* Translates characters to character classes
*/
private static final String ZZ_CMAP_PACKED =
"\11\17\1\3\1\2\1\0\1\3\1\1\16\17\4\0\1\3\1\0"+
"\1\6\1\0\1\16\2\0\1\10\2\0\1\5\1\15\1\24\1\11"+
"\1\13\1\4\12\12\1\25\6\0\4\16\1\14\25\16\1\22\1\7"+
"\1\23\1\0\1\16\1\0\1\33\3\16\1\31\1\32\5\16\1\34"+
"\1\16\1\36\3\16\1\27\1\35\1\26\1\30\5\16\1\20\1\0"+
"\1\21\1\0\41\17\2\0\4\16\4\0\1\16\2\0\1\17\7\0"+
"\1\16\4\0\1\16\5\0\27\16\1\0\37\16\1\0\u01ca\16\4\0"+
"\14\16\16\0\5\16\7\0\1\16\1\0\1\16\21\0\160\17\5\16"+
"\1\0\2\16\2\0\4\16\10\0\1\16\1\0\3\16\1\0\1\16"+
"\1\0\24\16\1\0\123\16\1\0\213\16\1\0\5\17\2\0\236\16"+
"\11\0\46\16\2\0\1\16\7\0\47\16\7\0\1\16\1\0\55\17"+
"\1\0\1\17\1\0\2\17\1\0\2\17\1\0\1\17\10\0\33\16"+
"\5\0\3\16\15\0\5\17\6\0\1\16\4\0\13\17\5\0\53\16"+
"\37\17\4\0\2\16\1\17\143\16\1\0\1\16\10\17\1\0\6\17"+
"\2\16\2\17\1\0\4\17\2\16\12\17\3\16\2\0\1\16\17\0"+
"\1\17\1\16\1\17\36\16\33\17\2\0\131\16\13\17\1\16\16\0"+
"\12\17\41\16\11\17\2\16\4\0\1\16\5\0\26\16\4\17\1\16"+
"\11\17\1\16\3\17\1\16\5\17\22\0\31\16\3\17\104\0\1\16"+
"\1\0\13\16\67\0\33\17\1\0\4\17\66\16\3\17\1\16\22\17"+
"\1\16\7\17\12\16\2\17\2\0\12\17\1\0\7\16\1\0\7\16"+
"\1\0\3\17\1\0\10\16\2\0\2\16\2\0\26\16\1\0\7\16"+
"\1\0\1\16\3\0\4\16\2\0\1\17\1\16\7\17\2\0\2\17"+
"\2\0\3\17\1\16\10\0\1\17\4\0\2\16\1\0\3\16\2\17"+
"\2\0\12\17\4\16\7\0\1\16\5\0\3\17\1\0\6\16\4\0"+
"\2\16\2\0\26\16\1\0\7\16\1\0\2\16\1\0\2\16\1\0"+
"\2\16\2\0\1\17\1\0\5\17\4\0\2\17\2\0\3\17\3\0"+
"\1\17\7\0\4\16\1\0\1\16\7\0\14\17\3\16\1\17\13\0"+
"\3\17\1\0\11\16\1\0\3\16\1\0\26\16\1\0\7\16\1\0"+
"\2\16\1\0\5\16\2\0\1\17\1\16\10\17\1\0\3\17\1\0"+
"\3\17\2\0\1\16\17\0\2\16\2\17\2\0\12\17\1\0\1\16"+
"\17\0\3\17\1\0\10\16\2\0\2\16\2\0\26\16\1\0\7\16"+
"\1\0\2\16\1\0\5\16\2\0\1\17\1\16\7\17\2\0\2\17"+
"\2\0\3\17\10\0\2\17\4\0\2\16\1\0\3\16\2\17\2\0"+
"\12\17\1\0\1\16\20\0\1\17\1\16\1\0\6\16\3\0\3\16"+
"\1\0\4\16\3\0\2\16\1\0\1\16\1\0\2\16\3\0\2\16"+
"\3\0\3\16\3\0\14\16\4\0\5\17\3\0\3\17\1\0\4\17"+
"\2\0\1\16\6\0\1\17\16\0\12\17\11\0\1\16\7\0\3\17"+
"\1\0\10\16\1\0\3\16\1\0\27\16\1\0\12\16\1\0\5\16"+
"\3\0\1\16\7\17\1\0\3\17\1\0\4\17\7\0\2\17\1\0"+
"\2\16\6\0\2\16\2\17\2\0\12\17\22\0\2\17\1\0\10\16"+
"\1\0\3\16\1\0\27\16\1\0\12\16\1\0\5\16\2\0\1\17"+
"\1\16\7\17\1\0\3\17\1\0\4\17\7\0\2\17\7\0\1\16"+
"\1\0\2\16\2\17\2\0\12\17\1\0\2\16\17\0\2\17\1\0"+
"\10\16\1\0\3\16\1\0\51\16\2\0\1\16\7\17\1\0\3\17"+
"\1\0\4\17\1\16\10\0\1\17\10\0\2\16\2\17\2\0\12\17"+
"\12\0\6\16\2\0\2\17\1\0\22\16\3\0\30\16\1\0\11\16"+
"\1\0\1\16\2\0\7\16\3\0\1\17\4\0\6\17\1\0\1\17"+
"\1\0\10\17\22\0\2\17\15\0\60\16\1\17\2\16\7\17\4\0"+
"\10\16\10\17\1\0\12\17\47\0\2\16\1\0\1\16\2\0\2\16"+
"\1\0\1\16\2\0\1\16\6\0\4\16\1\0\7\16\1\0\3\16"+
"\1\0\1\16\1\0\1\16\2\0\2\16\1\0\4\16\1\17\2\16"+
"\6\17\1\0\2\17\1\16\2\0\5\16\1\0\1\16\1\0\6\17"+
"\2\0\12\17\2\0\4\16\40\0\1\16\27\0\2\17\6\0\12\17"+
"\13\0\1\17\1\0\1\17\1\0\1\17\4\0\2\17\10\16\1\0"+
"\44\16\4\0\24\17\1\0\2\17\5\16\13\17\1\0\44\17\11\0"+
"\1\17\71\0\53\16\24\17\1\16\12\17\6\0\6\16\4\17\4\16"+
"\3\17\1\16\3\17\2\16\7\17\3\16\4\17\15\16\14\17\1\16"+
"\17\17\2\0\46\16\1\0\1\16\5\0\1\16\2\0\53\16\1\0"+
"\u014d\16\1\0\4\16\2\0\7\16\1\0\1\16\1\0\4\16\2\0"+
"\51\16\1\0\4\16\2\0\41\16\1\0\4\16\2\0\7\16\1\0"+
"\1\16\1\0\4\16\2\0\17\16\1\0\71\16\1\0\4\16\2\0"+
"\103\16\2\0\3\17\40\0\20\16\20\0\125\16\14\0\u026c\16\2\0"+
"\21\16\1\0\32\16\5\0\113\16\3\0\3\16\17\0\15\16\1\0"+
"\4\16\3\17\13\0\22\16\3\17\13\0\22\16\2\17\14\0\15\16"+
"\1\0\3\16\1\0\2\17\14\0\64\16\40\17\3\0\1\16\3\0"+
"\2\16\1\17\2\0\12\17\41\0\3\17\2\0\12\17\6\0\130\16"+
"\10\0\51\16\1\17\1\16\5\0\106\16\12\0\35\16\3\0\14\17"+
"\4\0\14\17\12\0\12\17\36\16\2\0\5\16\13\0\54\16\4\0"+
"\21\17\7\16\2\17\6\0\12\17\46\0\27\16\5\17\4\0\65\16"+
"\12\17\1\0\35\17\2\0\13\17\6\0\12\17\15\0\1\16\130\0"+
"\5\17\57\16\21\17\7\16\4\0\12\17\21\0\11\17\14\0\3\17"+
"\36\16\15\17\2\16\12\17\54\16\16\17\14\0\44\16\24\17\10\0"+
"\12\17\3\0\3\16\12\17\44\16\122\0\3\17\1\0\25\17\4\16"+
"\1\17\4\16\3\17\2\16\11\0\300\16\47\17\25\0\4\17\u0116\16"+
"\2\0\6\16\2\0\46\16\2\0\6\16\2\0\10\16\1\0\1\16"+
"\1\0\1\16\1\0\1\16\1\0\37\16\2\0\65\16\1\0\7\16"+
"\1\0\1\16\3\0\3\16\1\0\7\16\3\0\4\16\2\0\6\16"+
"\4\0\15\16\5\0\3\16\1\0\7\16\16\0\5\17\32\0\5\17"+
"\20\0\2\16\23\0\1\16\13\0\5\17\5\0\6\17\1\0\1\16"+
"\15\0\1\16\20\0\15\16\3\0\33\16\25\0\15\17\4\0\1\17"+
"\3\0\14\17\21\0\1\16\4\0\1\16\2\0\12\16\1\0\1\16"+
"\3\0\5\16\6\0\1\16\1\0\1\16\1\0\1\16\1\0\4\16"+
"\1\0\13\16\2\0\4\16\5\0\5\16\4\0\1\16\21\0\51\16"+
"\u0a77\0\57\16\1\0\57\16\1\0\205\16\6\0\4\16\3\17\2\16"+
"\14\0\46\16\1\0\1\16\5\0\1\16\2\0\70\16\7\0\1\16"+
"\17\0\1\17\27\16\11\0\7\16\1\0\7\16\1\0\7\16\1\0"+
"\7\16\1\0\7\16\1\0\7\16\1\0\7\16\1\0\7\16\1\0"+
"\40\17\57\0\1\16\u01d5\0\3\16\31\0\11\16\6\17\1\0\5\16"+
"\2\0\5\16\4\0\126\16\2\0\2\17\2\0\3\16\1\0\132\16"+
"\1\0\4\16\5\0\51\16\3\0\136\16\21\0\33\16\65\0\20\16"+
"\u0200\0\u19b6\16\112\0\u51cd\16\63\0\u048d\16\103\0\56\16\2\0\u010d\16"+
"\3\0\20\16\12\17\2\16\24\0\57\16\1\17\4\0\12\17\1\0"+
"\31\16\7\0\1\17\120\16\2\17\45\0\11\16\2\0\147\16\2\0"+
"\4\16\1\0\4\16\14\0\13\16\115\0\12\16\1\17\3\16\1\17"+
"\4\16\1\17\27\16\5\17\20\0\1\16\7\0\64\16\14\0\2\17"+
"\62\16\21\17\13\0\12\17\6\0\22\17\6\16\3\0\1\16\4\0"+
"\12\17\34\16\10\17\2\0\27\16\15\17\14\0\35\16\3\0\4\17"+
"\57\16\16\17\16\0\1\16\12\17\46\0\51\16\16\17\11\0\3\16"+
"\1\17\10\16\2\17\2\0\12\17\6\0\27\16\3\0\1\16\1\17"+
"\4\0\60\16\1\17\1\16\3\17\2\16\2\17\5\16\2\17\1\16"+
"\1\17\1\16\30\0\3\16\2\0\13\16\5\17\2\0\3\16\2\17"+
"\12\0\6\16\2\0\6\16\2\0\6\16\11\0\7\16\1\0\7\16"+
"\221\0\43\16\10\17\1\0\2\17\2\0\12\17\6\0\u2ba4\16\14\0"+
"\27\16\4\0\61\16\u2104\0\u016e\16\2\0\152\16\46\0\7\16\14\0"+
"\5\16\5\0\1\16\1\17\12\16\1\0\15\16\1\0\5\16\1\0"+
"\1\16\1\0\2\16\1\0\2\16\1\0\154\16\41\0\u016b\16\22\0"+
"\100\16\2\0\66\16\50\0\15\16\3\0\20\17\20\0\7\17\14\0"+
"\2\16\30\0\3\16\31\0\1\16\6\0\5\16\1\0\207\16\2\0"+
"\1\17\4\0\1\16\13\0\12\17\7\0\32\16\4\0\1\16\1\0"+
"\32\16\13\0\131\16\3\0\6\16\2\0\6\16\2\0\6\16\2\0"+
"\3\16\3\0\2\16\3\0\2\16\22\0\3\17\4\0";
/**
* Translates characters to character classes
*/
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
/**
* Translates DFA states to action switch labels.
*/
private static final int [] ZZ_ACTION = zzUnpackAction();
private static final String ZZ_ACTION_PACKED_0 =
"\1\0\1\1\1\2\1\1\1\3\1\4\1\1\1\5"+
"\1\6\1\7\1\10\1\11\1\12\1\13\1\14\3\6"+
"\1\15\1\16\1\3\2\0\1\4\1\0\3\6\1\0"+
"\1\5\3\6\1\16\1\0\1\17\1\6\1\20\1\0"+
"\1\5\1\21";
private static int [] zzUnpackAction() {
int [] result = new int[41];
int offset = 0;
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAction(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/**
* Translates a state to a row index in the transition table
*/
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
private static final String ZZ_ROWMAP_PACKED_0 =
"\0\0\0\37\0\76\0\135\0\174\0\233\0\272\0\331"+
"\0\370\0\37\0\37\0\37\0\37\0\37\0\37\0\u0117"+
"\0\u0136\0\u0155\0\u0174\0\u0193\0\37\0\u01b2\0\u01d1\0\37"+
"\0\u01f0\0\u020f\0\u022e\0\u024d\0\u026c\0\u028b\0\u02aa\0\u02c9"+
"\0\u02e8\0\37\0\u0307\0\370\0\u0326\0\370\0\u0345\0\u0345"+
"\0\370";
private static int [] zzUnpackRowMap() {
int [] result = new int[41];
int offset = 0;
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
return result;
}
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int high = packed.charAt(i++) << 16;
result[j++] = high | packed.charAt(i++);
}
return j;
}
/**
* The transition table of the DFA
*/
private static final int [] ZZ_TRANS = zzUnpackTrans();
private static final String ZZ_TRANS_PACKED_0 =
"\1\2\3\3\1\4\1\2\1\5\1\2\1\6\1\7"+
"\1\10\1\2\1\11\1\2\1\11\1\2\1\12\1\13"+
"\1\14\1\15\1\16\1\17\1\20\3\11\1\21\3\11"+
"\1\22\40\0\3\3\37\0\1\23\1\24\31\0\1\5"+
"\2\0\3\5\1\25\1\26\27\5\1\6\2\0\4\6"+
"\1\27\1\30\26\6\12\0\1\10\36\0\1\10\1\31"+
"\35\0\1\11\1\0\1\11\1\0\2\11\6\0\11\11"+
"\12\0\1\11\1\0\1\11\1\0\2\11\6\0\1\11"+
"\1\32\7\11\12\0\1\11\1\0\1\11\1\0\2\11"+
"\6\0\5\11\1\33\3\11\12\0\1\11\1\0\1\11"+
"\1\0\2\11\6\0\2\11\1\34\6\11\2\23\1\0"+
"\34\23\5\24\1\35\31\24\1\5\2\0\34\5\1\6"+
"\2\0\34\6\12\0\1\36\36\0\1\11\1\0\1\11"+
"\1\0\2\11\6\0\2\11\1\37\6\11\12\0\1\11"+
"\1\0\1\11\1\0\2\11\6\0\6\11\1\40\2\11"+
"\12\0\1\11\1\0\1\11\1\0\2\11\6\0\6\11"+
"\1\41\2\11\4\24\1\42\1\35\31\24\12\0\1\36"+
"\1\0\1\43\14\0\1\43\17\0\1\11\1\0\1\11"+
"\1\0\2\11\6\0\3\11\1\44\5\11\12\0\1\11"+
"\1\0\1\11\1\0\2\11\6\0\7\11\1\45\1\11"+
"\12\0\1\11\1\0\1\11\1\0\2\11\6\0\6\11"+
"\1\46\2\11\11\0\1\47\1\50\2\0\1\47\33\0"+
"\1\11\1\0\1\11\1\0\2\11\6\0\3\11\1\51"+
"\5\11\12\0\1\50\24\0";
private static int [] zzUnpackTrans() {
int [] result = new int[868];
int offset = 0;
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
return result;
}
private static int zzUnpackTrans(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
value--;
do result[j++] = value; while (--count > 0);
}
return j;
}
/* error codes */
private static final int ZZ_UNKNOWN_ERROR = 0;
private static final int ZZ_NO_MATCH = 1;
private static final int ZZ_PUSHBACK_2BIG = 2;
private static final char[] EMPTY_BUFFER = new char[0];
private static final int YYEOF = -1;
private static java.io.Reader zzReader = null; // Fake
/* error messages for the codes above */
private static final String ZZ_ERROR_MSG[] = {
"Unkown internal scanner error",
"Error: could not match input",
"Error: pushback value was too large"
};
/**
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
*/
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
private static final String ZZ_ATTRIBUTE_PACKED_0 =
"\1\0\1\11\7\1\6\11\5\1\1\11\2\0\1\11"+
"\1\0\3\1\1\0\4\1\1\11\1\0\3\1\1\0"+
"\2\1";
private static int [] zzUnpackAttribute() {
int [] result = new int[41];
int offset = 0;
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/** the current state of the DFA */
private int zzState;
/** the current lexical state */
private int zzLexicalState = YYINITIAL;
/** this buffer contains the current text to be matched and is
the source of the yytext() string */
private CharSequence zzBuffer = "";
/** this buffer may contains the current text array to be matched when it is cheap to acquire it */
private char[] zzBufferArray;
/** the textposition at the last accepting state */
private int zzMarkedPos;
/** the textposition at the last state to be included in yytext */
private int zzPushbackPos;
/** the current text position in the buffer */
private int zzCurrentPos;
/** startRead marks the beginning of the yytext() string in the buffer */
private int zzStartRead;
/** endRead marks the last character in the buffer, that has been read
from input */
private int zzEndRead;
/**
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
*/
private boolean zzAtBOL = true;
/** zzAtEOF == true <=> the scanner is at the EOF */
private boolean zzAtEOF;
/* user code: */
public _JsonLexer() {
this((java.io.Reader)null);
}
public _JsonLexer(java.io.Reader in) {
this.zzReader = in;
}
/**
* Creates a new scanner.
* There is also java.io.Reader version of this constructor.
*
* @param in the java.io.Inputstream to read input from.
*/
public _JsonLexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
/**
* Unpacks the compressed character translation table.
*
* @param packed the packed character translation table
* @return the unpacked character translation table
*/
private static char [] zzUnpackCMap(String packed) {
char [] map = new char[0x10000];
int i = 0; /* index in packed string */
int j = 0; /* index in unpacked array */
while (i < 2216) {
int count = packed.charAt(i++);
char value = packed.charAt(i++);
do map[j++] = value; while (--count > 0);
}
return map;
}
public final int getTokenStart(){
return zzStartRead;
}
public final int getTokenEnd(){
return getTokenStart() + yylength();
}
public void reset(CharSequence buffer, int start, int end,int initialState){
zzBuffer = buffer;
zzBufferArray = com.intellij.util.text.CharArrayUtil.fromSequenceWithoutCopying(buffer);
zzCurrentPos = zzMarkedPos = zzStartRead = start;
zzPushbackPos = 0;
zzAtEOF = false;
zzAtBOL = true;
zzEndRead = end;
yybegin(initialState);
}
/**
* Refills the input buffer.
*
* @return <code>false</code>, iff there was new input.
*
* @exception java.io.IOException if any I/O-Error occurs
*/
private boolean zzRefill() throws java.io.IOException {
return true;
}
/**
* Returns the current lexical state.
*/
public final int yystate() {
return zzLexicalState;
}
/**
* Enters a new lexical state
*
* @param newState the new lexical state
*/
public final void yybegin(int newState) {
zzLexicalState = newState;
}
/**
* Returns the text matched by the current regular expression.
*/
public final CharSequence yytext() {
return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
}
/**
* Returns the character at position <tt>pos</tt> from the
* matched text.
*
* It is equivalent to yytext().charAt(pos), but faster
*
* @param pos the position of the character to fetch.
* A value from 0 to yylength()-1.
*
* @return the character at position pos
*/
public final char yycharat(int pos) {
return zzBufferArray != null ? zzBufferArray[zzStartRead+pos]:zzBuffer.charAt(zzStartRead+pos);
}
/**
* Returns the length of the matched text region.
*/
public final int yylength() {
return zzMarkedPos-zzStartRead;
}
/**
* Reports an error that occured while scanning.
*
* In a wellformed scanner (no or only correct usage of
* yypushback(int) and a match-all fallback rule) this method
* will only be called with things that "Can't Possibly Happen".
* If this method is called, something is seriously wrong
* (e.g. a JFlex bug producing a faulty scanner etc.).
*
* Usual syntax/scanner level error handling should be done
* in error fallback rules.
*
* @param errorCode the code of the errormessage to display
*/
private void zzScanError(int errorCode) {
String message;
try {
message = ZZ_ERROR_MSG[errorCode];
}
catch (ArrayIndexOutOfBoundsException e) {
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
}
throw new Error(message);
}
/**
* Pushes the specified amount of characters back into the input stream.
*
* They will be read again by then next call of the scanning method
*
* @param number the number of characters to be read again.
* This number must not be greater than yylength()!
*/
public void yypushback(int number) {
if ( number > yylength() )
zzScanError(ZZ_PUSHBACK_2BIG);
zzMarkedPos -= number;
}
/**
* Resumes scanning until the next regular expression is matched,
* the end of input is encountered or an I/O-Error occurs.
*
* @return the next token
* @exception java.io.IOException if any I/O-Error occurs
*/
public IElementType advance() throws java.io.IOException {
int zzInput;
int zzAction;
// cached fields:
int zzCurrentPosL;
int zzMarkedPosL;
int zzEndReadL = zzEndRead;
CharSequence zzBufferL = zzBuffer;
char[] zzBufferArrayL = zzBufferArray;
char [] zzCMapL = ZZ_CMAP;
int [] zzTransL = ZZ_TRANS;
int [] zzRowMapL = ZZ_ROWMAP;
int [] zzAttrL = ZZ_ATTRIBUTE;
while (true) {
zzMarkedPosL = zzMarkedPos;
zzAction = -1;
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
zzState = ZZ_LEXSTATE[zzLexicalState];
zzForAction: {
while (true) {
if (zzCurrentPosL < zzEndReadL)
zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
else if (zzAtEOF) {
zzInput = YYEOF;
break zzForAction;
}
else {
// store back cached positions
zzCurrentPos = zzCurrentPosL;
zzMarkedPos = zzMarkedPosL;
boolean eof = zzRefill();
// get translated positions and possibly new buffer
zzCurrentPosL = zzCurrentPos;
zzMarkedPosL = zzMarkedPos;
zzBufferL = zzBuffer;
zzEndReadL = zzEndRead;
if (eof) {
zzInput = YYEOF;
break zzForAction;
}
else {
zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
}
}
int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
if (zzNext == -1) break zzForAction;
zzState = zzNext;
int zzAttributes = zzAttrL[zzState];
if ( (zzAttributes & 1) == 1 ) {
zzAction = zzState;
zzMarkedPosL = zzCurrentPosL;
if ( (zzAttributes & 8) == 8 ) break zzForAction;
}
}
}
// store back cached position
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 8:
{ return R_CURLY;
}
case 18: break;
case 7:
{ return L_CURLY;
}
case 19: break;
case 16:
{ return NULL;
}
case 20: break;
case 6:
{ return INDENTIFIER;
}
case 21: break;
case 9:
{ return L_BRACKET;
}
case 22: break;
case 13:
{ return LINE_COMMENT;
}
case 23: break;
case 11:
{ return COMMA;
}
case 24: break;
case 2:
{ return com.intellij.psi.TokenType.WHITE_SPACE;
}
case 25: break;
case 3:
{ return DOUBLE_QUOTED_STRING;
}
case 26: break;
case 1:
{ return com.intellij.psi.TokenType.BAD_CHARACTER;
}
case 27: break;
case 15:
{ return TRUE;
}
case 28: break;
case 12:
{ return COLON;
}
case 29: break;
case 4:
{ return SINGLE_QUOTED_STRING;
}
case 30: break;
case 5:
{ return NUMBER;
}
case 31: break;
case 17:
{ return FALSE;
}
case 32: break;
case 14:
{ return BLOCK_COMMENT;
}
case 33: break;
case 10:
{ return R_BRACKET;
}
case 34: break;
default:
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
zzAtEOF = true;
return null;
}
else {
zzScanError(ZZ_NO_MATCH);
}
}
}
}
}
@@ -0,0 +1,13 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonArray extends JsonContainer {
@NotNull
List<JsonValue> getValueList();
}
@@ -0,0 +1,10 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonBooleanLiteral extends JsonLiteral {
}
@@ -0,0 +1,10 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonContainer extends JsonValue {
}
@@ -0,0 +1,60 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiNamedElement;
public class JsonElementVisitor extends PsiElementVisitor {
public void visitArray(@NotNull JsonArray o) {
visitContainer(o);
}
public void visitBooleanLiteral(@NotNull JsonBooleanLiteral o) {
visitLiteral(o);
}
public void visitContainer(@NotNull JsonContainer o) {
visitValue(o);
}
public void visitLiteral(@NotNull JsonLiteral o) {
visitValue(o);
}
public void visitNullLiteral(@NotNull JsonNullLiteral o) {
visitLiteral(o);
}
public void visitNumberLiteral(@NotNull JsonNumberLiteral o) {
visitLiteral(o);
}
public void visitObject(@NotNull JsonObject o) {
visitContainer(o);
}
public void visitProperty(@NotNull JsonProperty o) {
visitElement(o);
// visitPsiNamedElement(o);
}
public void visitReferenceExpression(@NotNull JsonReferenceExpression o) {
visitValue(o);
}
public void visitStringLiteral(@NotNull JsonStringLiteral o) {
visitLiteral(o);
}
public void visitValue(@NotNull JsonValue o) {
visitElement(o);
}
public void visitElement(@NotNull JsonElement o) {
visitElement((PsiElement)o);
}
}
@@ -0,0 +1,12 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonLiteral extends JsonValue {
boolean isQuotedString();
}
@@ -0,0 +1,10 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonNullLiteral extends JsonLiteral {
}
@@ -0,0 +1,13 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonNumberLiteral extends JsonLiteral {
@NotNull
PsiElement getNumber();
}
@@ -0,0 +1,16 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonObject extends JsonContainer {
@NotNull
List<JsonProperty> getPropertyList();
@Nullable
JsonProperty findProperty(String name);
}
@@ -0,0 +1,20 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
public interface JsonProperty extends JsonElement, PsiNamedElement {
@NotNull
String getName();
@NotNull
JsonValue getNameElement();
@Nullable
JsonValue getValue();
}
@@ -0,0 +1,13 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonReferenceExpression extends JsonValue {
@NotNull
PsiElement getIndentifier();
}
@@ -0,0 +1,16 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonStringLiteral extends JsonLiteral {
@Nullable
PsiElement getDoubleQuotedString();
@Nullable
PsiElement getSingleQuotedString();
}
@@ -0,0 +1,10 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface JsonValue extends JsonElement {
}
@@ -0,0 +1,30 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonArrayImpl extends JsonContainerImpl implements JsonArray {
public JsonArrayImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitArray(this);
else super.accept(visitor);
}
@Override
@NotNull
public List<JsonValue> getValueList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JsonValue.class);
}
}
@@ -0,0 +1,24 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonBooleanLiteralImpl extends JsonLiteralImpl implements JsonBooleanLiteral {
public JsonBooleanLiteralImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitBooleanLiteral(this);
else super.accept(visitor);
}
}
@@ -0,0 +1,24 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonContainerImpl extends JsonValueImpl implements JsonContainer {
public JsonContainerImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitContainer(this);
else super.accept(visitor);
}
}
@@ -0,0 +1,28 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonLiteralImpl extends JsonLiteralMixin implements JsonLiteral {
public JsonLiteralImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitLiteral(this);
else super.accept(visitor);
}
public boolean isQuotedString() {
return JsonPsiImplUtils.isQuotedString(this);
}
}
@@ -0,0 +1,24 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonNullLiteralImpl extends JsonLiteralImpl implements JsonNullLiteral {
public JsonNullLiteralImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitNullLiteral(this);
else super.accept(visitor);
}
}
@@ -0,0 +1,30 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonNumberLiteralImpl extends JsonLiteralImpl implements JsonNumberLiteral {
public JsonNumberLiteralImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitNumberLiteral(this);
else super.accept(visitor);
}
@Override
@NotNull
public PsiElement getNumber() {
return findNotNullChildByType(NUMBER);
}
}
@@ -0,0 +1,35 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonObjectImpl extends JsonContainerImpl implements JsonObject {
public JsonObjectImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitObject(this);
else super.accept(visitor);
}
@Override
@NotNull
public List<JsonProperty> getPropertyList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JsonProperty.class);
}
@Nullable
public JsonProperty findProperty(String name) {
return JsonPsiImplUtils.findProperty(this, name);
}
}
@@ -0,0 +1,39 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonPropertyImpl extends JsonPropertyMixin implements JsonProperty {
public JsonPropertyImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitProperty(this);
else super.accept(visitor);
}
@NotNull
public String getName() {
return JsonPsiImplUtils.getName(this);
}
@NotNull
public JsonValue getNameElement() {
return JsonPsiImplUtils.getNameElement(this);
}
@Nullable
public JsonValue getValue() {
return JsonPsiImplUtils.getValue(this);
}
}
@@ -0,0 +1,30 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonReferenceExpressionImpl extends JsonValueImpl implements JsonReferenceExpression {
public JsonReferenceExpressionImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitReferenceExpression(this);
else super.accept(visitor);
}
@Override
@NotNull
public PsiElement getIndentifier() {
return findNotNullChildByType(INDENTIFIER);
}
}
@@ -0,0 +1,36 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonStringLiteralImpl extends JsonLiteralImpl implements JsonStringLiteral {
public JsonStringLiteralImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitStringLiteral(this);
else super.accept(visitor);
}
@Override
@Nullable
public PsiElement getDoubleQuotedString() {
return findChildByType(DOUBLE_QUOTED_STRING);
}
@Override
@Nullable
public PsiElement getSingleQuotedString() {
return findChildByType(SINGLE_QUOTED_STRING);
}
}
@@ -0,0 +1,24 @@
// This is a generated file. Not intended for manual editing.
package com.intellij.json.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.json.JsonElementTypes.*;
import com.intellij.json.psi.*;
public class JsonValueImpl extends JsonElementImpl implements JsonValue {
public JsonValueImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JsonElementVisitor) ((JsonElementVisitor)visitor).visitValue(this);
else super.accept(visitor);
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="core-api" />
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="xml-openapi" />
</component>
</module>
@@ -0,0 +1,6 @@
<html>
<body>
<font face="verdana" size="-1">This inspection checks that *.json files comply with JSON specification (RFC-4627).<br>
</font>
</body>
</html>
@@ -0,0 +1,33 @@
package com.intellij.json;
import com.intellij.lang.BracePair;
import com.intellij.lang.PairedBraceMatcher;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonBraceMatcher implements PairedBraceMatcher {
private static BracePair[] PAIRS = {
new BracePair(JsonElementTypes.L_BRACKET, JsonElementTypes.R_BRACKET, true),
new BracePair(JsonElementTypes.L_CURLY, JsonElementTypes.R_CURLY, true)
};
@Override
public BracePair[] getPairs() {
return PAIRS;
}
@Override
public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
return true;
}
@Override
public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
return openingBraceOffset;
}
}
@@ -0,0 +1,36 @@
package com.intellij.json;
import com.intellij.CommonBundle;
import com.intellij.reference.SoftReference;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;
import java.lang.ref.Reference;
import java.util.ResourceBundle;
/**
* @author Mikhail Golubev
*/
public class JsonBundle {
private static Reference<ResourceBundle> ourBundle;
@NonNls private static final String BUNDLE = "com.intellij.json.JsonBundle";
private JsonBundle() {
// empty
}
public static String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, @NotNull Object... params) {
return CommonBundle.message(getBundle(), key, params);
}
private static ResourceBundle getBundle() {
ResourceBundle bundle = SoftReference.dereference(ourBundle);
if (bundle == null) {
bundle = ResourceBundle.getBundle(BUNDLE);
ourBundle = new SoftReference<ResourceBundle>(bundle);
}
return bundle;
}
}
@@ -0,0 +1,18 @@
msg.missing.closing.quote=Missing closing quote
msg.illegal.escape.sequence=Illegal escape sequence
msg.illegal.unicode.escape.sequence=Illegal unicode escape sequence
msg.compliance.problem.comments=JSON standard does not allow comments. Use JSMin or similar tool to remove comments before parsing.
msg.compliance.problem.single.quoted.strings=JSON standard does not allow single quoted strings
msg.compliance.problem.illegal.top.level.value=JSON standard allows only object or array as top-level value
msg.compliance.problem.identifier=JSON standard does not allow identifiers
msg.compliance.problem.illegal.property.key=JSON standard allows only double quoted string as property key
msg.compliance.problem.trailing.comma=JSON standard does not allow trailing comma
name.json.inspection.group=JSON
name.standard.compliance.inspection=Compliance with JSON standard
name.add.double.quotes.quickfix=Wrap with double quotes
name.surround.with.object.literal=object literal
option.warn.about.comments.name=Warn about comments in JSON
@@ -0,0 +1,11 @@
package com.intellij.json;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JsonElementType extends IElementType {
public JsonElementType(@NotNull @NonNls String debugName) {
super(debugName, JsonLanguage.INSTANCE);
}
}
@@ -0,0 +1,45 @@
package com.intellij.json;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.fileTypes.LanguageFileType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
/**
* @author Mikhail Golubev
*/
public class JsonFileType extends LanguageFileType{
public static final JsonFileType INSTANCE = new JsonFileType();
public static final String DEFAULT_EXTENSION = "json";
public JsonFileType() {
super(JsonLanguage.INSTANCE);
}
@NotNull
@Override
public String getName() {
return "JSON";
}
@NotNull
@Override
public String getDescription() {
return "JSON language";
}
@NotNull
@Override
public String getDefaultExtension() {
return DEFAULT_EXTENSION;
}
@Nullable
@Override
public Icon getIcon() {
// TODO: add JSON icon instead
return AllIcons.FileTypes.Json;
}
}
@@ -0,0 +1,15 @@
package com.intellij.json;
import com.intellij.openapi.fileTypes.FileTypeConsumer;
import com.intellij.openapi.fileTypes.FileTypeFactory;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonFileTypeFactory extends FileTypeFactory {
@Override
public void createFileTypes(@NotNull FileTypeConsumer consumer) {
consumer.consume(JsonFileType.INSTANCE, JsonFileType.DEFAULT_EXTENSION);
}
}
@@ -0,0 +1,16 @@
package com.intellij.json;
import com.intellij.lang.Language;
public class JsonLanguage extends Language {
public static final JsonLanguage INSTANCE = new JsonLanguage();
private JsonLanguage() {
super("JSON", "application/json");
}
@Override
public boolean isCaseSensitive() {
return true;
}
}
@@ -0,0 +1,38 @@
/*
* @author max
*/
package com.intellij.json;
import com.intellij.lang.refactoring.NamesValidator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
public class JsonNamesValidator implements NamesValidator {
private final JsonLexer myLexer = new JsonLexer();
@Override
public synchronized boolean isKeyword(@NotNull String name, Project project) {
myLexer.start(name);
return JsonParserDefinition.JSON_KEYWORDS.contains( myLexer.getTokenType() ) && myLexer.getTokenEnd() == name.length();
}
@Override
public synchronized boolean isIdentifier(@NotNull String name, final Project project) {
if (!StringUtil.startsWithChar(name,'\'') && !StringUtil.startsWithChar(name,'\"')) {
name = "\"" + name;
}
if (!StringUtil.endsWithChar(name,'"') && !StringUtil.endsWithChar(name,'\"')) {
name += "\"";
}
myLexer.start(name);
IElementType type = myLexer.getTokenType();
return myLexer.getTokenEnd() == name.length() && (type == JsonElementTypes.DOUBLE_QUOTED_STRING ||
type == JsonElementTypes.SINGLE_QUOTED_STRING);
}
}
@@ -0,0 +1,84 @@
package com.intellij.json;
import com.intellij.json.psi.impl.JsonFileImpl;
import com.intellij.lang.ASTNode;
import com.intellij.lang.ParserDefinition;
import com.intellij.lang.PsiParser;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import static com.intellij.json.JsonElementTypes.*;
public class JsonParserDefinition implements ParserDefinition {
public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE);
public static final TokenSet STRING_LITERALS = TokenSet.create(SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING);
public static final IFileElementType FILE = new IFileElementType(JsonLanguage.INSTANCE);
public static final TokenSet JSON_BRACES = TokenSet.create(L_CURLY, R_CURLY);
public static final TokenSet JSON_BRACKETS = TokenSet.create(L_BRACKET, R_BRACKET);
public static final TokenSet JSON_CONTAINERS = TokenSet.create(OBJECT, ARRAY);
public static final TokenSet JSON_BOOLEANS = TokenSet.create(TRUE, FALSE);
public static final TokenSet JSON_KEYWORDS = TokenSet.create(TRUE, FALSE, NULL);
public static final TokenSet JSON_LITERALS = TokenSet.create(STRING_LITERAL, NUMBER_LITERAL, NULL_LITERAL, TRUE, FALSE);
public static final TokenSet JSON_VALUES = TokenSet.orSet(JSON_CONTAINERS, JSON_LITERALS);
public static final TokenSet JSON_COMMENTARIES = TokenSet.create(BLOCK_COMMENT, LINE_COMMENT);
@NotNull
@Override
public Lexer createLexer(Project project) {
return new JsonLexer();
}
@Override
public PsiParser createParser(Project project) {
return new JsonParser();
}
@Override
public IFileElementType getFileNodeType() {
return FILE;
}
@NotNull
@Override
public TokenSet getWhitespaceTokens() {
return WHITE_SPACES;
}
@NotNull
@Override
public TokenSet getCommentTokens() {
return JSON_COMMENTARIES;
}
@NotNull
@Override
public TokenSet getStringLiteralElements() {
return STRING_LITERALS;
}
@NotNull
@Override
public PsiElement createElement(ASTNode astNode) {
return Factory.createElement(astNode);
}
@Override
public PsiFile createFile(FileViewProvider fileViewProvider) {
return new JsonFileImpl(fileViewProvider);
}
@Override
public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode astNode, ASTNode astNode2) {
return SpaceRequirements.MAY;
}
}
@@ -0,0 +1,12 @@
package com.intellij.json;
import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler;
/**
* @author Mikhail Golubev
*/
public class JsonQuoteHandler extends SimpleTokenSetQuoteHandler {
public JsonQuoteHandler() {
super(JsonParserDefinition.STRING_LITERALS);
}
}
@@ -0,0 +1,73 @@
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));
}
}
}
@@ -0,0 +1,11 @@
package com.intellij.json;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JsonTokenType extends IElementType {
public JsonTokenType(@NotNull @NonNls String debugName) {
super(debugName, JsonLanguage.INSTANCE);
}
}
+37
View File
@@ -0,0 +1,37 @@
package com.intellij.json;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonUtil {
private JsonUtil() {
// empty
}
/**
* Clone of C# "as" operator.
* Checks if expression has correct type and casts it if it has. Returns null otherwise.
* It saves coder from "instanceof / cast" chains.
*
* Copied from PyCharm's {@code PyUtil}.
*
* @param expression expression to check
* @param cls class to cast
* @param <T> class to cast
* @return expression casted to appropriate type (if could be casted). Null otherwise.
*/
@Nullable
@SuppressWarnings("unchecked")
public static <T> T as(@Nullable final Object expression, @NotNull final Class<T> cls) {
if (expression == null) {
return null;
}
if (cls.isAssignableFrom(expression.getClass())) {
return (T)expression;
}
return null;
}
}
@@ -0,0 +1,49 @@
package com.intellij.json.breadcrumbs;
import com.intellij.json.JsonLanguage;
import com.intellij.lang.Language;
import com.intellij.psi.PsiElement;
import com.intellij.xml.breadcrumbs.BreadcrumbsInfoProvider;
import com.intellij.json.psi.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonBreadcrumbsProvider extends BreadcrumbsInfoProvider {
private static final Language[] LANGUAGES = new Language[]{JsonLanguage.INSTANCE};
@Override
public Language[] getLanguages() {
return LANGUAGES;
}
@Override
public boolean acceptElement(@NotNull PsiElement e) {
return e instanceof JsonProperty;
}
@NotNull
@Override
public String getElementInfo(@NotNull PsiElement e) {
if (e instanceof JsonProperty) {
return ((JsonProperty)e).getName();
}
//else if (isArrayElement(e)) {
// List<JsonValue> elements = ((JsonArray)e.getParent()).getValueList();
// for (int i = 0; i < elements.size(); i++) {
// if (e == elements.get(i)) {
// return String.valueOf(i);
// }
// }
//}
throw new AssertionError("Breadcrumbs can be extracted only from JsonProperty elements");
}
@Nullable
@Override
public String getElementTooltip(@NotNull PsiElement e) {
return null;
}
}
@@ -0,0 +1,52 @@
package com.intellij.json.codeinsight;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.json.psi.JsonArray;
import com.intellij.json.psi.JsonProperty;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author Mikhail Golubev
*/
public class JsonCompletionContributor extends CompletionContributor {
private static final Logger LOG = Logger.getInstance(JsonCompletionContributor.class);
private static final PsiElementPattern.Capture<PsiElement> AFTER_COLON_IN_PROPERTY = psiElement()
.afterLeaf(":").withSuperParent(2, JsonProperty.class);
private static final PsiElementPattern.Capture<PsiElement> AFTER_COMMA_OR_BRACKET_IN_ARRAY = psiElement()
.afterLeaf("[", ",").withSuperParent(2, JsonArray.class);
@Override
public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
LOG.debug(DebugUtil.psiToString(parameters.getPosition().getContainingFile(), true));
super.fillCompletionVariants(parameters, result);
}
public JsonCompletionContributor() {
extend(CompletionType.BASIC, AFTER_COLON_IN_PROPERTY, MyKeywordsCompletionProvider.INSTANCE);
extend(CompletionType.BASIC, AFTER_COMMA_OR_BRACKET_IN_ARRAY, MyKeywordsCompletionProvider.INSTANCE);
}
private static class MyKeywordsCompletionProvider extends CompletionProvider<CompletionParameters> {
private static final MyKeywordsCompletionProvider INSTANCE = new MyKeywordsCompletionProvider();
private static final String[] KEYWORDS = new String[]{"null", "true", "false"};
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result) {
for (String keyword : KEYWORDS) {
result.addElement(LookupElementBuilder.create(keyword).bold());
}
}
}
}
@@ -0,0 +1,141 @@
package com.intellij.json.codeinsight;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.json.JsonBundle;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* Compliance checks include
* <ul>
* <li>Usage of line and block commentaries</li>
* <li>Usage of single quoted strings</li>
* <li>Usage of identifiers (unqouted words)</li>
* <li>Not double quoted string literal is used as property key</li>
* </ul>
*
* @author Mikhail Golubev
*/
public class JsonStandardComplianceInspection extends LocalInspectionTool {
public boolean myWarnAboutComments = true;
@NotNull
public String getDisplayName() {
return JsonBundle.message("name.standard.compliance.inspection");
}
@NotNull
@Override
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JsonElementVisitor() {
@Override
public void visitComment(PsiComment comment) {
if (myWarnAboutComments) {
holder.registerProblem(comment, JsonBundle.message("msg.compliance.problem.comments"), ProblemHighlightType.WEAK_WARNING);
}
}
@Override
public void visitStringLiteral(@NotNull JsonStringLiteral stringLiteral) {
if (stringLiteral.getText().startsWith("'")) {
holder.registerProblem(stringLiteral, JsonBundle.message("msg.compliance.problem.single.quoted.strings"), new AddDoubleQuotesFix());
}
super.visitStringLiteral(stringLiteral);
}
@Override
public void visitLiteral(@NotNull JsonLiteral literal) {
if (literal.getParent() instanceof JsonFile) {
holder.registerProblem(literal, JsonBundle.message("msg.compliance.problem.illegal.top.level.value"));
}
if (JsonPsiUtil.isPropertyKey(literal) && !(literal.getText().startsWith("\""))) {
holder.registerProblem(literal, JsonBundle.message("msg.compliance.problem.illegal.property.key"), new AddDoubleQuotesFix());
}
}
@Override
public void visitReferenceExpression(@NotNull JsonReferenceExpression reference) {
holder.registerProblem(reference, JsonBundle.message("msg.compliance.problem.identifier"), new AddDoubleQuotesFix());
}
@Override
public void visitArray(@NotNull JsonArray array) {
final PsiElement trailingComma = findTrailingComma(array, JsonElementTypes.R_BRACKET);
if (trailingComma != null) {
holder.registerProblem(trailingComma, JsonBundle.message("msg.compliance.problem.trailing.comma"));
}
}
@Override
public void visitObject(@NotNull JsonObject object) {
final PsiElement trailingComma = findTrailingComma(object, JsonElementTypes.R_CURLY);
if (trailingComma != null) {
holder.registerProblem(trailingComma, JsonBundle.message("msg.compliance.problem.trailing.comma"));
}
}
};
}
@Nullable
private static PsiElement findTrailingComma(@NotNull JsonContainer container, @NotNull IElementType ending) {
final PsiElement lastChild = container.getLastChild();
if (lastChild.getNode().getElementType() != ending) {
return null;
}
final PsiElement beforeEnding = PsiTreeUtil.skipSiblingsBackward(lastChild, PsiComment.class, PsiWhiteSpace.class);
if (beforeEnding != null && beforeEnding.getNode().getElementType() == JsonElementTypes.COMMA) {
return beforeEnding;
}
return null;
}
@Override
public JComponent createOptionsPanel() {
final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this);
optionsPanel.addCheckbox(JsonBundle.message("option.warn.about.comments.name"), "myWarnAboutComments");
return optionsPanel;
}
private static class AddDoubleQuotesFix implements LocalQuickFix {
@NotNull
@Override
public String getName() {
return JsonBundle.message("name.add.double.quotes.quickfix");
}
@NotNull
@Override
public String getFamilyName() {
return getName();
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
assert element instanceof JsonLiteral || element instanceof JsonReferenceExpression;
final String content = StringUtil.stripQuotesAroundValue(element.getText());
element.replace(new JsonElementGenerator(project).createStringLiteral(content));
}
}
}
@@ -0,0 +1,79 @@
package com.intellij.json.codeinsight;
import com.intellij.json.JsonBundle;
import com.intellij.json.psi.JsonStringLiteral;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonStringLiteralAnnotator implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (element instanceof JsonStringLiteral) {
String text = element.getText();
int offset = element.getTextOffset();
int length = text.length();
// Check that string literal closed properly
if (length <= 1 || text.charAt(0) != text.charAt(length - 1) || quoteEscaped(text, length - 1)) {
holder.createErrorAnnotation(element.getTextRange(), JsonBundle.message("msg.missing.closing.quote"));
}
// Check escape sequences validity
int pos = 1;
while (pos < length) {
if (text.charAt(pos) == '\\') {
if (pos >= length - 1) {
TextRange range = new TextRange(offset + pos, offset + pos + 1);
holder.createErrorAnnotation(range, JsonBundle.message("msg.illegal.escape.sequence"));
break;
}
char next = text.charAt(pos + 1);
switch (next) {
case '"':
case '\\':
case '/':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
pos += 2;
break;
case 'u':
int i = pos + 2;
for (; i < pos + 6; i++) {
if (i == length || !StringUtil.isHexDigit(text.charAt(i))) {
TextRange range = new TextRange(offset + pos, offset + i);
holder.createErrorAnnotation(range, JsonBundle.message("msg.illegal.unicode.escape.sequence"));
break;
}
}
pos = i;
break;
default:
TextRange range = new TextRange(offset + pos, offset + pos + 2);
holder.createErrorAnnotation(range, JsonBundle.message("msg.illegal.escape.sequence"));
pos += 2;
}
}
else {
pos++;
}
}
}
}
private static boolean quoteEscaped(String text, int quotePos) {
int count = 0;
for (int i = quotePos - 1; i >= 0 && text.charAt(i) == '\\'; i--) {
count++;
}
return count % 2 != 0;
}
}
@@ -0,0 +1,41 @@
package com.intellij.json.editor;
import com.intellij.lang.Commenter;
import org.jetbrains.annotations.Nullable;
/**
* JSON standard (RFC 4627) doesn't allow comments in documents, but they are added for compatibility with legacy JSON integration.
*
* @author Mikhail Golubev
*/
public class JsonCommenter implements Commenter {
@Nullable
@Override
public String getLineCommentPrefix() {
return "//";
}
@Nullable
@Override
public String getBlockCommentPrefix() {
return "/*";
}
@Nullable
@Override
public String getBlockCommentSuffix() {
return "*/";
}
@Nullable
@Override
public String getCommentedBlockCommentPrefix() {
return null;
}
@Nullable
@Override
public String getCommentedBlockCommentSuffix() {
return null;
}
}
@@ -0,0 +1,87 @@
package com.intellij.json.editor.folding;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.JsonLiteral;
import com.intellij.json.psi.JsonObject;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonValue;
import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.FoldingBuilder;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public class JsonFoldingBuilder implements FoldingBuilder, DumbAware {
@NotNull
@Override
public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) {
final List<FoldingDescriptor> descriptors = new ArrayList<FoldingDescriptor>();
collectDescriptorsRecursively(node, document, descriptors);
return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
}
private static void collectDescriptorsRecursively(@NotNull ASTNode node,
@NotNull Document document,
@NotNull List<FoldingDescriptor> descriptors) {
final IElementType type = node.getElementType();
if ((type == JsonElementTypes.OBJECT || type == JsonElementTypes.ARRAY) && spanMultipleLines(node, document)) {
descriptors.add(new FoldingDescriptor(node, node.getTextRange()));
}
for (ASTNode child : node.getChildren(null)) {
collectDescriptorsRecursively(child, document, descriptors);
}
}
@Nullable
@Override
public String getPlaceholderText(@NotNull ASTNode node) {
final IElementType type = node.getElementType();
if (type == JsonElementTypes.OBJECT) {
final JsonObject object = node.getPsi(JsonObject.class);
final List<JsonProperty> properties = object.getPropertyList();
JsonProperty candidate = null;
for (JsonProperty property : properties) {
final String name = property.getName();
final JsonValue value = property.getValue();
if (value instanceof JsonLiteral) {
if ("id".equals(name) || "name".equals(name)) {
candidate = property;
break;
}
if (candidate == null) {
candidate = property;
}
}
}
if (candidate != null) {
//noinspection ConstantConditions
return "{\"" + candidate.getName() + "\": " + candidate.getValue().getText() + "...}";
}
return "{...}";
}
else if (type == JsonElementTypes.ARRAY) {
return "[...]";
}
return "...";
}
@Override
public boolean isCollapsedByDefault(@NotNull ASTNode node) {
return false;
}
private static boolean spanMultipleLines(@NotNull ASTNode node, @NotNull Document document) {
final TextRange range = node.getTextRange();
return document.getLineNumber(range.getStartOffset()) < document.getLineNumber(range.getEndOffset());
}
}
@@ -0,0 +1,88 @@
package com.intellij.json.editor.lineMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineMover;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonLineMover extends LineMover {
private boolean myShouldAddComma = false;
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
myShouldAddComma = false;
if (!(file instanceof JsonFile) || !super.checkAvailable(editor, file, info, down)) {
return false;
}
final Pair<PsiElement, PsiElement> movedElementRange = getElementRange(editor, file, info.toMove);
final Pair<PsiElement, PsiElement> destElementRange = getElementRange(editor, file, info.toMove2);
if (!isValidElementRange(movedElementRange) || !isValidElementRange(destElementRange)) {
return false;
}
if (movedElementRange.getFirst().getParent() != destElementRange.getSecond().getParent()) {
return false;
}
final PsiElement commonParent = movedElementRange.getFirst().getParent();
final PsiElement lowerRightElement = down ? destElementRange.getSecond() : movedElementRange.getSecond();
// Destination rightmost element is not closing brace or bracket
if (lowerRightElement instanceof JsonElement) {
if (commonParent instanceof JsonArray && notFollowedByNextElementOrComma(lowerRightElement, JsonValue.class) ||
commonParent instanceof JsonObject && notFollowedByNextElementOrComma(lowerRightElement, JsonProperty.class)) {
myShouldAddComma = true;
}
}
return true;
}
@Override
public void beforeMove(@NotNull Editor editor, @NotNull MoveInfo info, boolean down) {
if (myShouldAddComma) {
final Document document = editor.getDocument();
final int lineBelow = down ? info.toMove2.endLine - 1 : info.toMove.endLine - 1;
document.insertString(document.getLineEndOffset(lineBelow), ",");
final int lineAbove = down ? info.toMove.endLine - 1 : info.toMove2.endLine - 1;
final int lineAboveEndOffset = document.getLineEndOffset(lineAbove);
final String aboveLineEnding = document.getText(new TextRange(lineAboveEndOffset - 1, lineAboveEndOffset));
if (aboveLineEnding.equals(",")) {
document.deleteString(lineAboveEndOffset - 1, lineAboveEndOffset);
}
final Project project = editor.getProject();
assert project != null;
PsiDocumentManager.getInstance(project).commitDocument(document);
}
}
private static boolean notFollowedByNextElementOrComma(@NotNull PsiElement anchor, @NotNull Class<? extends PsiElement> nextElementType) {
return PsiTreeUtil.getNextSiblingOfType(anchor, nextElementType) == null &&
TreeUtil.findSibling(anchor.getNode(), JsonElementTypes.COMMA) == null;
}
private static boolean isValidElementRange(@Nullable Pair<PsiElement, PsiElement> elementRange) {
if (elementRange == null) {
return false;
}
return elementRange.getFirst().getParent() == elementRange.getSecond().getParent();
}
}
@@ -0,0 +1,123 @@
package com.intellij.json.editor.smartEnter;
import com.intellij.json.psi.JsonArray;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonValue;
import com.intellij.lang.SmartEnterProcessorWithFixers;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import static com.intellij.json.JsonElementTypes.COLON;
import static com.intellij.json.JsonElementTypes.COMMA;
/**
* This processor allows
* <ul>
* <li>Insert colon after key inside object property</li>
* <li>Insert comma after array element or object property</li>
* </ul>
*
* @author Mikhail Golubev
*/
public class JsonSmartEnterProcessor extends SmartEnterProcessorWithFixers {
public static final Logger LOG = Logger.getInstance(JsonSmartEnterProcessor.class);
private boolean myShouldAddNewline = false;
public JsonSmartEnterProcessor() {
addFixers(new JsonObjectPropertyFixer(), new JsonArrayElementFixer());
addEnterProcessors(new JsonEnterProcessor());
}
@Override
protected void collectAdditionalElements(@NotNull PsiElement element, @NotNull List<PsiElement> result) {
// include all parents as well
PsiElement parent = element.getParent();
while (parent != null && !(parent instanceof JsonFile)) {
result.add(parent);
parent = parent.getParent();
}
}
private static boolean terminatedOnCurrentLine(@NotNull Editor editor, @NotNull PsiElement element) {
final Document document = editor.getDocument();
final int caretOffset = editor.getCaretModel().getCurrentCaret().getOffset();
final int elementEndOffset = element.getTextRange().getEndOffset();
if (document.getLineNumber(elementEndOffset) != document.getLineNumber(caretOffset)) {
return false;
}
// Skip empty PsiError elements if comma is missing
PsiElement nextLeaf = PsiTreeUtil.nextLeaf(element, true);
return nextLeaf == null || (nextLeaf instanceof PsiWhiteSpace && nextLeaf.getText().contains("\n"));
}
private static boolean isFollowedByTerminal(@NotNull PsiElement element, IElementType type) {
final PsiElement nextLeaf = PsiTreeUtil.nextVisibleLeaf(element);
return nextLeaf != null && nextLeaf.getNode().getElementType() == type;
}
private static class JsonArrayElementFixer extends SmartEnterProcessorWithFixers.Fixer<JsonSmartEnterProcessor> {
@Override
public void apply(@NotNull Editor editor, @NotNull JsonSmartEnterProcessor processor, @NotNull PsiElement element)
throws IncorrectOperationException {
if (element instanceof JsonValue && element.getParent() instanceof JsonArray) {
final JsonValue arrayElement = (JsonValue)element;
if (terminatedOnCurrentLine(editor, arrayElement) && !isFollowedByTerminal(element, COMMA)) {
editor.getDocument().insertString(arrayElement.getTextRange().getEndOffset(), ",");
processor.myShouldAddNewline = true;
}
}
}
}
private class JsonObjectPropertyFixer extends SmartEnterProcessorWithFixers.Fixer<JsonSmartEnterProcessor> {
@Override
public void apply(@NotNull Editor editor, @NotNull JsonSmartEnterProcessor processor, @NotNull PsiElement element)
throws IncorrectOperationException {
if (element instanceof JsonProperty) {
final JsonValue propertyValue = ((JsonProperty)element).getValue();
if (propertyValue != null) {
if (terminatedOnCurrentLine(editor, propertyValue) && !isFollowedByTerminal(propertyValue, COMMA)) {
editor.getDocument().insertString(propertyValue.getTextRange().getEndOffset(), ",");
processor.myShouldAddNewline = true;
}
}
else {
final JsonValue propertyKey = ((JsonProperty)element).getNameElement();
final int keyEndOffset = propertyKey.getTextRange().getEndOffset();
//processor.myFirstErrorOffset = keyEndOffset;
if (terminatedOnCurrentLine(editor, propertyKey) && !isFollowedByTerminal(propertyKey, COLON)) {
processor.myFirstErrorOffset = keyEndOffset + 2;
editor.getDocument().insertString(keyEndOffset, ": ");
}
}
}
}
}
private class JsonEnterProcessor extends SmartEnterProcessorWithFixers.FixEnterProcessor {
@Override
public boolean doEnter(PsiElement atCaret, PsiFile file, @NotNull Editor editor, boolean modified) {
if (myShouldAddNewline) {
try {
plainEnter(editor);
}
finally {
myShouldAddNewline = false;
}
}
return true;
}
}
}
@@ -0,0 +1,54 @@
package com.intellij.json.findUsages;
import com.intellij.json.psi.JsonProperty;
import com.intellij.lang.HelpID;
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonFindUsagesProvider implements FindUsagesProvider {
@Nullable
@Override
public WordsScanner getWordsScanner() {
return new JsonWordScanner();
}
@Override
public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
return psiElement instanceof PsiNamedElement;
}
@Nullable
@Override
public String getHelpId(@NotNull PsiElement psiElement) {
return HelpID.FIND_OTHER_USAGES;
}
@NotNull
@Override
public String getType(@NotNull PsiElement element) {
if (element instanceof JsonProperty) {
return "property";
}
return "";
}
@NotNull
@Override
public String getDescriptiveName(@NotNull PsiElement element) {
final String name = element instanceof PsiNamedElement ? ((PsiNamedElement)element).getName() : null;
return name != null ? name : "<unnamed>";
}
@NotNull
@Override
public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
return getDescriptiveName(element);
}
}
@@ -0,0 +1,19 @@
package com.intellij.json.findUsages;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.JsonLexer;
import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
import com.intellij.psi.tree.TokenSet;
import static com.intellij.json.JsonParserDefinition.JSON_COMMENTARIES;
import static com.intellij.json.JsonParserDefinition.JSON_LITERALS;
/**
* @author Mikhail Golubev
*/
public class JsonWordScanner extends DefaultWordsScanner {
public JsonWordScanner() {
super(new JsonLexer(), TokenSet.create(JsonElementTypes.INDENTIFIER), JSON_COMMENTARIES, JSON_LITERALS);
setMayHaveFileRefsInLiterals(true);
}
}
@@ -0,0 +1,205 @@
package com.intellij.json.formatter;
import com.intellij.formatting.*;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.JsonLanguage;
import com.intellij.json.JsonParserDefinition;
import com.intellij.json.psi.JsonProperty;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.TokenType;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.json.JsonParserDefinition.JSON_BRACES;
import static com.intellij.json.JsonParserDefinition.JSON_BRACKETS;
/**
* Mostly based on PyBlock implementation.
*
* @author Mikhail Golubev
*/
public class JsonBlock implements ASTBlock {
private static final TokenSet OPEN_BRACES = TokenSet.create(JsonElementTypes.L_BRACKET, JsonElementTypes.L_CURLY);
private static final TokenSet CLOSE_BRACES = TokenSet.create(JsonElementTypes.R_BRACKET, JsonElementTypes.R_CURLY);
private static final TokenSet BRACES = TokenSet.orSet(OPEN_BRACES, CLOSE_BRACES);
private JsonBlock myParent;
private ASTNode myNode;
private PsiElement myPsiElement;
private Alignment myAlignment;
private Indent myIndent;
private Wrap myWrap;
private CodeStyleSettings mySettings;
private SpacingBuilder mySpacingBuilder;
// lazy initialized on first call to #getSubBlocks()
private List<Block> mySubBlocks = null;
private Alignment myChildAlignment = Alignment.createAlignment();
public JsonBlock(@Nullable JsonBlock parent,
@NotNull ASTNode node,
@NotNull CodeStyleSettings settings,
@Nullable Alignment alignment,
@NotNull Indent indent,
@Nullable Wrap wrap) {
myParent = parent;
myNode = node;
myPsiElement = node.getPsi();
myAlignment = alignment;
myIndent = indent;
myWrap = wrap;
mySettings = settings;
mySpacingBuilder = JsonFormattingBuilderModel.createSpacingBuilder(settings);
}
@Override
public ASTNode getNode() {
return myNode;
}
@NotNull
@Override
public TextRange getTextRange() {
return myNode.getTextRange();
}
@NotNull
@Override
public List<Block> getSubBlocks() {
if (mySubBlocks == null) {
mySubBlocks = ContainerUtil.mapNotNull(myNode.getChildren(null), new Function<ASTNode, Block>() {
@Override
public Block fun(ASTNode node) {
if (isWhitespaceOrEmpty(node)) {
return null;
}
return makeSubBlock(node);
}
});
}
return mySubBlocks;
}
private Block makeSubBlock(@NotNull ASTNode childNode) {
IElementType childNodeType = childNode.getElementType();
Indent indent = Indent.getNoneIndent();
Alignment alignment = null;
Wrap wrap = null;
if (isContainer() && childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) {
if (!FormatterUtil.isPrecededBy(childNode, OPEN_BRACES)) {
wrap = Wrap.createWrap(WrapType.ALWAYS, true);
}
alignment = myChildAlignment;
indent = Indent.getNormalIndent();
}
return new JsonBlock(this, childNode, mySettings, alignment, indent, wrap);
}
@Nullable
@Override
public Wrap getWrap() {
return myWrap;
}
@Nullable
@Override
public Indent getIndent() {
return myIndent;
}
@Nullable
@Override
public Alignment getAlignment() {
return myAlignment;
}
@Nullable
@Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
final CommonCodeStyleSettings commonSettings = mySettings.getCommonSettings(JsonLanguage.INSTANCE);
final JsonCodeStyleSettings customSettings = mySettings.getCustomSettings(JsonCodeStyleSettings.class);
final IElementType leftChildType = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode.getElementType() : null;
final IElementType rightChildType = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode.getElementType() : null;
if (leftChildType != null && rightChildType != null) {
if (JSON_BRACES.contains(leftChildType) ^ JSON_BRACES.contains(rightChildType)) {
final int numSpaces = customSettings.SPACE_WITHIN_BRACES ? 1 : 0;
return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(),
commonSettings.KEEP_LINE_BREAKS,
commonSettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (JSON_BRACKETS.contains(leftChildType) ^ JSON_BRACKETS.contains(rightChildType)) {
final int numSpaces = commonSettings.SPACE_WITHIN_BRACKETS ? 1 : 0;
return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(),
commonSettings.KEEP_LINE_BREAKS,
commonSettings.KEEP_BLANK_LINES_IN_CODE);
}
}
return mySpacingBuilder.getSpacing(this, child1, child2);
}
@NotNull
@Override
public ChildAttributes getChildAttributes(int newChildIndex) {
JsonBlock prevChildBlock = newChildIndex > 0 ? (JsonBlock)mySubBlocks.get(newChildIndex - 1) : null;
ASTNode prevChildNode = prevChildBlock != null? prevChildBlock.myNode : null;
if (myNode.getElementType() == JsonParserDefinition.FILE) {
return new ChildAttributes(Indent.getNoneIndent(), null);
}
if (isContainer() && prevChildNode != null) {
// correctly indent first element after opening brace
if (OPEN_BRACES.contains(prevChildNode.getElementType()) || prevChildNode.getElementType() == JsonElementTypes.COMMA) {
return new ChildAttributes(Indent.getNormalIndent(), myChildAlignment);
}
}
// // TODO find out why inside object then cursor is after '"a": []<cursor>', myNode is instance of JsonArray
// if (isContainer() && prevChildBlock != null) {
// return ChildAttributes.DELEGATE_TO_PREV_CHILD;
// }
return new ChildAttributes(Indent.getNormalIndent(), null);
}
@Override
public boolean isIncomplete() {
IElementType nodeType = myNode.getElementType();
ASTNode lastChildNode = myNode.getLastChildNode();
if (nodeType == JsonElementTypes.OBJECT) {
return lastChildNode != null && lastChildNode.getElementType() == JsonElementTypes.R_CURLY;
}
else if (nodeType == JsonElementTypes.ARRAY) {
return lastChildNode != null && lastChildNode.getElementType() == JsonElementTypes.R_BRACKET;
}
else if (myPsiElement instanceof JsonProperty) {
return ((JsonProperty)myPsiElement).getValue() != null;
}
return false;
}
@Override
public boolean isLeaf() {
return myNode.getFirstChildNode() == null;
}
private static boolean isWhitespaceOrEmpty(ASTNode node) {
return node.getElementType() == TokenType.WHITE_SPACE || node.getTextLength() == 0;
}
private boolean isContainer() {
return JsonParserDefinition.JSON_CONTAINERS.contains(myNode.getElementType());
}
}
@@ -0,0 +1,21 @@
package com.intellij.json.formatter;
import com.intellij.json.JsonLanguage;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
/**
* @author Mikhail Golubev
*/
public class JsonCodeStyleSettings extends CustomCodeStyleSettings {
// Standard option has awkward description "Code braces"
public boolean SPACE_WITHIN_BRACES = false;
public boolean SPACE_AFTER_COLON = true;
public boolean SPACE_BEFORE_COLON = false;
public JsonCodeStyleSettings(CodeStyleSettings container) {
super(JsonLanguage.INSTANCE.getID(), container);
}
}
@@ -0,0 +1,56 @@
package com.intellij.json.formatter;
import com.intellij.application.options.CodeStyleAbstractConfigurable;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.application.options.TabbedLanguageCodeStylePanel;
import com.intellij.json.JsonLanguage;
import com.intellij.lang.Language;
import com.intellij.openapi.options.Configurable;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
@NotNull
@Override
public Configurable createSettingsPage(CodeStyleSettings settings, CodeStyleSettings originalSettings) {
return new CodeStyleAbstractConfigurable(settings, originalSettings, "JSON") {
@Override
protected CodeStyleAbstractPanel createPanel(CodeStyleSettings settings) {
final Language language = JsonLanguage.INSTANCE;
final CodeStyleSettings currentSettings = getCurrentSettings();
return new TabbedLanguageCodeStylePanel(language, currentSettings, settings) {
@Override
protected void initTabs(CodeStyleSettings settings) {
addIndentOptionsTab(settings);
addSpacesTab(settings);
addBlankLinesTab(settings);
}
};
}
@Nullable
@Override
public String getHelpTopic() {
return null;
}
};
}
@Nullable
@Override
public String getConfigurableDisplayName() {
return JsonLanguage.INSTANCE.getDisplayName();
}
@Nullable
@Override
public CustomCodeStyleSettings createCustomSettings(CodeStyleSettings settings) {
return new JsonCodeStyleSettings(settings);
}
}
@@ -0,0 +1,13 @@
package com.intellij.json.formatter;
import com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesHandler;
/**
* @author Mikhail Golubev
*/
public class JsonEnterBetweenBracesHandler extends EnterBetweenBracesHandler {
@Override
protected boolean isBracePair(char c1, char c2) {
return (c1 == '{' && c2 == '}') || (c1 == '[' && c2 == ']');
}
}
@@ -0,0 +1,65 @@
package com.intellij.json.formatter;
import com.intellij.formatting.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.json.JsonLanguage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.json.JsonElementTypes.*;
/**
* @author Mikhail Golubev
*/
public class JsonFormattingBuilderModel implements FormattingModelBuilder {
private static final Logger LOG = Logger.getInstance(JsonFormattingBuilderModel.class);
@NotNull
@Override
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
if (LOG.isDebugEnabled()) {
LOG.debug("PSI Tree:\n" + DebugUtil.psiToString(element, false));
}
LOG.debug("Right margin: " + settings.getRightMargin(JsonLanguage.INSTANCE));
JsonBlock block = new JsonBlock(null, element.getNode(), settings, null, Indent.getNoneIndent(), null);
if (LOG.isDebugEnabled()) {
StringBuilder builder = new StringBuilder();
FormattingModelDumper.dumpFormattingModel(block, 2, builder);
LOG.debug("Format Model:\n" + builder.toString());
}
return FormattingModelProvider.createFormattingModelForPsiFile(element.getContainingFile(), block, settings);
}
@Nullable
@Override
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
return null;
}
// create spacing model once for all subsequent blocks
static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) {
JsonCodeStyleSettings jsonSettings = settings.getCustomSettings(JsonCodeStyleSettings.class);
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(JsonLanguage.INSTANCE);
int spacesBeforeComma = commonSettings.SPACE_BEFORE_COMMA ? 1 : 0;
int spacesBeforeColon = jsonSettings.SPACE_BEFORE_COLON ? 1 : 0;
int spacesAfterColon = jsonSettings.SPACE_AFTER_COLON ? 1 : 0;
// not allow to keep line breaks before colon/comma, because it looks horrible
return new SpacingBuilder(settings, JsonLanguage.INSTANCE)
.before(COLON).spacing(spacesBeforeColon, spacesBeforeColon, 0, false, 0)
.after(COLON).spacing(spacesAfterColon, spacesAfterColon, 0, false, 0)
.withinPair(L_BRACKET, R_BRACKET).spaceIf(commonSettings.SPACE_WITHIN_BRACKETS)
.withinPair(L_CURLY, R_CURLY).spaceIf(jsonSettings.SPACE_WITHIN_BRACES)
.before(COMMA).spacing(spacesBeforeComma, spacesBeforeComma, 0, false, 0)
.after(COMMA).spaceIf(commonSettings.SPACE_AFTER_COMMA);
}
}
@@ -0,0 +1,75 @@
package com.intellij.json.formatter;
import com.intellij.application.options.IndentOptionsEditor;
import com.intellij.application.options.SmartIndentOptionsEditor;
import com.intellij.lang.Language;
import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.json.JsonLanguage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable.SPACES_OTHER;
import static com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable.SPACES_WITHIN;
/**
* @author Mikhail Golubev
*/
public class JsonLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
private static final String SAMPLE = "{\n" +
" \"json literals are\": {\n" +
" \"strings\": [\"foo\", \"bar\", \"\\u0062\\u0061\\u0072\"],\n" +
" \"numbers\": [42, 6.62606975e-34],\n" +
" \"boolean values\": [true, false],\n" +
" \"and\": {\"null\": null}\n" +
" }\n" +
"}";
@Override
public void customizeSettings(@NotNull CodeStyleSettingsCustomizable consumer, @NotNull SettingsType settingsType) {
if (settingsType == SettingsType.SPACING_SETTINGS) {
consumer.showStandardOptions("SPACE_WITHIN_BRACKETS",
"SPACE_AFTER_COMMA",
"SPACE_BEFORE_COMMA"
);
consumer.showCustomOption(JsonCodeStyleSettings.class, "SPACE_WITHIN_BRACES", "Braces", SPACES_WITHIN);
consumer.showCustomOption(JsonCodeStyleSettings.class, "SPACE_BEFORE_COLON", "Before ':'", SPACES_OTHER);
consumer.showCustomOption(JsonCodeStyleSettings.class, "SPACE_AFTER_COLON", "After ':'", SPACES_OTHER);
}
if (settingsType == SettingsType.BLANK_LINES_SETTINGS) {
consumer.showStandardOptions("KEEP_BLANK_LINES_IN_CODE");
}
super.customizeSettings(consumer, settingsType);
}
@NotNull
@Override
public Language getLanguage() {
return JsonLanguage.INSTANCE;
}
@Nullable
@Override
public IndentOptionsEditor getIndentOptionsEditor() {
// TODO: read sources of this one carefully
return new SmartIndentOptionsEditor();
}
@Override
public String getCodeSample(@NotNull SettingsType settingsType) {
return SAMPLE;
}
@Nullable
@Override
public CommonCodeStyleSettings getDefaultCommonSettings() {
CommonCodeStyleSettings commonSettings = new CommonCodeStyleSettings(JsonLanguage.INSTANCE);
CommonCodeStyleSettings.IndentOptions indentOptions = commonSettings.initIndentOptions();
indentOptions.INDENT_SIZE = 2;
// strip all blank lines by default
commonSettings.KEEP_BLANK_LINES_IN_CODE = 0;
return commonSettings;
}
}
@@ -0,0 +1,10 @@
package com.intellij.json.psi;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
/**
* @author Mikhail Golubev
*/
public interface JsonElement extends PsiElement, NavigatablePsiElement {
}
@@ -0,0 +1,58 @@
package com.intellij.json.psi;
import com.intellij.json.JsonFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonElementGenerator {
private final Project myProject;
public JsonElementGenerator(@NotNull Project project) {
myProject = project;
}
/**
* Create lightweight in-memory {@link com.intellij.json.psi.JsonFile} filled with {@code content}.
*
* @param content content of the file to be created
* @return created file
*/
@NotNull
public PsiFile createDummyFile(@NotNull String content) {
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(myProject);
return psiFileFactory.createFileFromText("dummy." + JsonFileType.INSTANCE.getDefaultExtension(), JsonFileType.INSTANCE, content);
}
/**
* Create JSON value from supplied content.
*
* @param content properly escaped text of JSON value, e.g. Java literal {@code "\"new\\nline\""} if you want to create string literal
* @param <T> type of the JSON value desired
* @return element created from given text
*
* @see #createStringLiteral(String)
*/
@NotNull
public <T extends JsonValue> T createValue(@NotNull String content) {
final PsiFile file = createDummyFile("{\"foo\": " + content + "}");
//noinspection unchecked,ConstantConditions
return (T)((JsonObject)file.getFirstChild()).getPropertyList().get(0).getValue();
}
/**
* Create JSON string literal from supplied <em>unescaped</em> content.
*
* @param unescapedContent unescaped content of string literal, e.g. Java literal {@code "new\nline"} (compare with {@link #createValue(String)}).
* @return JSON string literal created from given text
*/
@NotNull
public JsonStringLiteral createStringLiteral(@NotNull String unescapedContent) {
return createValue('"' + StringUtil.escapeStringCharacters(unescapedContent) + '"');
}
}
@@ -0,0 +1,17 @@
package com.intellij.json.psi;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public interface JsonFile extends JsonElement, PsiFile {
/**
* Returns {@link JsonArray} or {@link JsonObject} value according to JSON standard.
*
* @return top-level JSON element if any or {@code null} otherwise
*/
@Nullable
JsonValue getTopLevelValue();
}
@@ -0,0 +1,25 @@
package com.intellij.json.psi;
import com.intellij.json.JsonElementTypes;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.parser.GeneratedParserUtilBase;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonParserUtil extends GeneratedParserUtilBase {
public static boolean notTrailingComma(@NotNull PsiBuilder builder, int level) {
if (builder.getTokenType() != JsonElementTypes.COMMA) {
return false;
}
final IElementType afterComma = builder.lookAhead(1);
if (afterComma == JsonElementTypes.R_BRACKET || afterComma == JsonElementTypes.R_CURLY) {
builder.error("trailing comma");
}
builder.advanceLexer();
return true;
}
}
@@ -0,0 +1,42 @@
package com.intellij.json.psi;
import com.intellij.json.JsonElementTypes;
import com.intellij.lang.ASTNode;
import com.intellij.psi.TokenType;
public class JsonPsiChangeUtils {
public static void removeCommaSeparatedFromList(final ASTNode myNode, final ASTNode parent) {
ASTNode from = myNode, to = myNode.getTreeNext();
boolean seenComma = false;
ASTNode toCandidate = to;
while (toCandidate != null && toCandidate.getElementType() == TokenType.WHITE_SPACE) {
toCandidate = toCandidate.getTreeNext();
}
if (toCandidate != null && toCandidate.getElementType() == JsonElementTypes.COMMA) {
toCandidate = toCandidate.getTreeNext();
to = toCandidate;
seenComma = true;
if (to != null && to.getElementType() == TokenType.WHITE_SPACE) {
to = to.getTreeNext();
}
}
if (!seenComma) {
ASTNode treePrev = from.getTreePrev();
while (treePrev != null && treePrev.getElementType() == TokenType.WHITE_SPACE) {
from = treePrev;
treePrev = treePrev.getTreePrev();
}
if (treePrev != null && treePrev.getElementType() == JsonElementTypes.COMMA) {
from = treePrev;
}
}
parent.removeRange(from, to);
}
}
@@ -0,0 +1,49 @@
package com.intellij.json.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
/**
* Various helper methods for working with PSI of JSON language.
*
* @author Mikhail Golubev
*/
@SuppressWarnings("UnusedDeclaration")
public class JsonPsiUtil {
private JsonPsiUtil() {
// empty
}
/**
* Checks that PSI element represents item of JSON array.
*
* @param element PSI element to check
* @return whether this PSI element is array element
*/
public static boolean isArrayElement(@NotNull PsiElement element) {
return element instanceof JsonValue && element.getParent() instanceof JsonArray;
}
/**
* Checks that PSI element represents key of JSON property (key-value pair of JSON object)
*
* @param element PSI element to check
* @return whether this PSI element is property key
*/
public static boolean isPropertyKey(@NotNull PsiElement element) {
final PsiElement parent = element.getParent();
return parent instanceof JsonProperty && element == ((JsonProperty)parent).getNameElement();
}
/**
* Checks that PSI element represents value of JSON property (key-value pair of JSON object)
*
* @param element PSI element to check
* @return whether this PSI element is property value
*/
public static boolean isPropertyValue(@NotNull PsiElement element) {
final PsiElement parent = element.getParent();
return parent instanceof JsonProperty && element == ((JsonProperty)parent).getValue();
}
}
@@ -0,0 +1,32 @@
package com.intellij.json.psi;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.AbstractElementManipulator;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
public class JsonStringLiteralManipulator extends AbstractElementManipulator<JsonStringLiteral> {
@Override
public JsonStringLiteral handleContentChange(@NotNull JsonStringLiteral element, @NotNull TextRange range, String newContent)
throws IncorrectOperationException {
assert new TextRange(0, element.getTextLength()).contains(range);
final String originalContent = element.getText();
final TextRange withoutQuotes = getRangeInElement(element);
final JsonElementGenerator generator = new JsonElementGenerator(element.getProject());
final String replacement = originalContent.substring(withoutQuotes.getStartOffset(), range.getStartOffset()) +
newContent +
originalContent.substring(range.getEndOffset(), withoutQuotes.getEndOffset());
return generator.createStringLiteral(replacement);
}
@NotNull
@Override
public TextRange getRangeInElement(@NotNull JsonStringLiteral element) {
final String content = element.getText();
final int startOffset = content.startsWith("'") || content.startsWith("\"") ? 1 : 0;
final int endOffset = content.length() > 0 && (content.endsWith("'") || content.endsWith("\"")) ? -1 : 0;
return new TextRange(startOffset, content.length() + endOffset);
}
}
@@ -0,0 +1,23 @@
package com.intellij.json.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.json.psi.JsonElement;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonElementImpl extends ASTWrapperPsiElement implements JsonElement {
public JsonElementImpl(@NotNull ASTNode node) {
super(node);
}
@Override
public String toString() {
final String className = getClass().getSimpleName();
return StringUtil.trimEnd(className, "Impl");
}
}
@@ -0,0 +1,38 @@
package com.intellij.json.psi.impl;
import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.json.JsonFileType;
import com.intellij.json.JsonLanguage;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonValue;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class JsonFileImpl extends PsiFileBase implements JsonFile {
public JsonFileImpl(FileViewProvider fileViewProvider) {
super(fileViewProvider, JsonLanguage.INSTANCE);
}
@NotNull
@Override
public FileType getFileType() {
return JsonFileType.INSTANCE;
}
@Nullable
@Override
public JsonValue getTopLevelValue() {
return PsiTreeUtil.getChildOfType(this, JsonValue.class);
}
@Override
public String toString() {
final VirtualFile virtualFile = getVirtualFile();
return String.format("JsonFile: " + (virtualFile != null? virtualFile.getName() : "<unknown>"));
}
}
@@ -0,0 +1,33 @@
package com.intellij.json.psi.impl;
import com.intellij.json.psi.JsonLiteral;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import org.jetbrains.annotations.NotNull;
abstract class JsonLiteralMixin extends JsonElementImpl implements JsonLiteral {
private final Object myRefLock = new Object();
private volatile PsiReference[] myRefs;
private volatile long myModCount = -1;
protected JsonLiteralMixin(ASTNode node) {
super(node);
}
@NotNull
@Override
public PsiReference[] getReferences() {
final long count = getManager().getModificationTracker().getModificationCount();
if (count != myModCount) {
synchronized (myRefLock) {
if (count != myModCount) {
myRefs = ReferenceProvidersRegistry.getReferencesFromProviders(this);
myModCount = count;
}
}
}
return myRefs;
}
}
@@ -0,0 +1,42 @@
package com.intellij.json.psi.impl;
import com.intellij.json.psi.JsonElementGenerator;
import com.intellij.json.psi.JsonProperty;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
abstract class JsonPropertyMixin extends JsonElementImpl implements JsonProperty {
public JsonPropertyMixin(@NotNull ASTNode node) {
super(node);
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
final JsonElementGenerator generator = new JsonElementGenerator(getProject());
// Strip only both quotes in case user wants some exotic name like key'
getNameElement().replace(generator.createStringLiteral(StringUtil.unquoteString(name)));
return this;
}
@Override
public PsiReference getReference() {
return new JsonPropertyNameReference(this);
}
@NotNull
@Override
public PsiReference[] getReferences() {
final PsiReference[] fromProviders = ReferenceProvidersRegistry.getReferencesFromProviders(this);
return ArrayUtil.prepend(new JsonPropertyNameReference(this), fromProviders);
}
}
@@ -0,0 +1,79 @@
package com.intellij.json.psi.impl;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonValue;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.ElementManipulators;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonPropertyNameReference implements PsiReference {
private final JsonProperty myProperty;
public JsonPropertyNameReference(@NotNull JsonProperty property) {
myProperty = property;
}
@Override
public PsiElement getElement() {
return myProperty;
}
@Override
public TextRange getRangeInElement() {
final JsonValue nameElement = myProperty.getNameElement();
// Either value of string with quotes stripped or element's text as is
return ElementManipulators.getValueTextRange(nameElement);
}
@Nullable
@Override
public PsiElement resolve() {
return myProperty;
}
@NotNull
@Override
public String getCanonicalText() {
return myProperty.getName();
}
@Override
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
return myProperty.setName(newElementName);
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
return null;
}
@Override
public boolean isReferenceTo(PsiElement element) {
if (!(element instanceof JsonProperty)) {
return false;
}
// May reference to the property with the same name for compatibility with JavaScript JSON support
final JsonProperty otherProperty = (JsonProperty)element;
final PsiElement selfResolve = resolve();
return otherProperty.getName().equals(getCanonicalText()) && selfResolve != otherProperty;
}
@NotNull
@Override
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public boolean isSoft() {
return true;
}
}
@@ -0,0 +1,58 @@
package com.intellij.json.psi.impl;
import com.intellij.json.JsonParserDefinition;
import com.intellij.json.psi.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class JsonPsiImplUtils {
@NotNull
public static String getName(@NotNull JsonProperty property) {
return StringUtil.stripQuotesAroundValue(property.getNameElement().getText());
}
/**
* Actually only JSON string literal should be accepted as valid name of property according to standard,
* but for compatibility with JavaScript integration any JSON literals as well as identifiers (unquoted words)
* are possible and highlighted as error later.
*
* @see com.intellij.json.codeinsight.JsonStandardComplianceInspection
*/
@NotNull
public static JsonValue getNameElement(@NotNull JsonProperty property) {
final PsiElement firstChild = property.getFirstChild();
assert firstChild instanceof JsonLiteral || firstChild instanceof JsonReferenceExpression;
return (JsonValue)firstChild;
}
@Nullable
public static JsonValue getValue(@NotNull JsonProperty property) {
return PsiTreeUtil.getNextSiblingOfType(getNameElement(property), JsonValue.class);
}
public static boolean isQuotedString(@NotNull JsonLiteral literal) {
return literal.getNode().findChildByType(JsonParserDefinition.STRING_LITERALS) != null;
}
public static void delete(@NotNull JsonProperty property) {
final ASTNode myNode = property.getNode();
JsonPsiChangeUtils.removeCommaSeparatedFromList(myNode, myNode.getTreeParent());
}
@Nullable
public static JsonProperty findProperty(@NotNull JsonObject object, @NotNull String name) {
final Collection<JsonProperty> properties = PsiTreeUtil.findChildrenOfType(object, JsonProperty.class);
for (JsonProperty property : properties) {
if (property.getName().equals(name)) {
return property;
}
}
return null;
}
}
@@ -0,0 +1,14 @@
package com.intellij.json.psi.impl;
import com.intellij.json.psi.JsonElementVisitor;
import com.intellij.psi.PsiElement;
/**
* @author Mikhail Golubev
*/
public class JsonRecursiveElementVisitor extends JsonElementVisitor {
public void visitElement(final PsiElement element) {
element.acceptChildren(this);
}
}
@@ -0,0 +1,27 @@
package com.intellij.json.structureView;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
import com.intellij.lang.PsiStructureViewFactory;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonStructureViewBuilderFactory implements PsiStructureViewFactory {
@Nullable
@Override
public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
return new TreeBasedStructureViewBuilder() {
@NotNull
@Override
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
return new JsonStructureViewModel(psiFile, editor);
}
};
}
}
@@ -0,0 +1,101 @@
package com.intellij.json.structureView;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.json.psi.JsonElement;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonObject;
import com.intellij.json.psi.JsonProperty;
import com.intellij.navigation.ItemPresentation;
import com.intellij.util.Function;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author Mikhail Golubev
*/
public class JsonStructureViewElement implements StructureViewTreeElement {
private final JsonElement myElement;
public JsonStructureViewElement(@NotNull JsonElement element) {
assert element instanceof JsonFile || element instanceof JsonProperty;
myElement = element;
}
@Override
public JsonElement getValue() {
return myElement;
}
@Override
public void navigate(boolean requestFocus) {
myElement.navigate(requestFocus);
}
@Override
public boolean canNavigate() {
return myElement.canNavigate();
}
@Override
public boolean canNavigateToSource() {
return myElement.canNavigateToSource();
}
@NotNull
@Override
public ItemPresentation getPresentation() {
if (myElement instanceof JsonProperty) {
return new ItemPresentation() {
@Nullable
@Override
public String getPresentableText() {
return ((JsonProperty)myElement).getName();
}
@Nullable
@Override
public String getLocationString() {
return null;
}
@Nullable
@Override
public Icon getIcon(boolean unused) {
return PlatformIcons.PROPERTY_ICON;
}
};
}
else if (myElement instanceof JsonFile) {
//noinspection ConstantConditions
return myElement.getPresentation();
}
throw new AssertionError("Attempting to create presentation for illegal element: " + myElement);
}
@NotNull
@Override
public TreeElement[] getChildren() {
JsonElement value = null;
if (myElement instanceof JsonFile) {
value = ((JsonFile)myElement).getTopLevelValue();
}
else if (myElement instanceof JsonProperty) {
value = ((JsonProperty)myElement).getValue();
}
if (value instanceof JsonObject) {
final JsonObject object = ((JsonObject)value);
return ContainerUtil.map2Array(object.getPropertyList(), TreeElement.class, new Function<JsonProperty, TreeElement>() {
@Override
public TreeElement fun(JsonProperty property) {
return new JsonStructureViewElement(property);
}
});
}
return EMPTY_ARRAY;
}
}
@@ -0,0 +1,45 @@
package com.intellij.json.structureView;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewModelBase;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.util.treeView.smartTree.Sorter;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonProperty;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public class JsonStructureViewModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider, StructureViewModel.ExpandInfoProvider{
public JsonStructureViewModel(@NotNull PsiFile psiFile, @Nullable Editor editor) {
super(psiFile, editor, new JsonStructureViewElement((JsonFile)psiFile));
withSorters(Sorter.ALPHA_SORTER);
withSuitableClasses(JsonFile.class, JsonProperty.class);
}
@Override
public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
return false;
}
@Override
public boolean isAlwaysLeaf(StructureViewTreeElement element) {
return false;
}
@Override
public boolean isAutoExpand(@NotNull StructureViewTreeElement element) {
final Object value = element.getValue();
return value instanceof PsiFile || value instanceof JsonProperty;
}
@Override
public boolean isSmartExpand() {
return false;
}
}
@@ -0,0 +1,78 @@
package com.intellij.json.surroundWith;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.JsonElement;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonValue;
import com.intellij.lang.surroundWith.SurroundDescriptor;
import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public class JsonSurroundDescriptor implements SurroundDescriptor {
private static final Surrounder[] ourSurrounders = new Surrounder[]{
new JsonWithObjectLiteralSurrounder()
};
@NotNull
@Override
public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) {
PsiElement firstElement = file.findElementAt(startOffset);
PsiElement lastElement = file.findElementAt(endOffset - 1);
// Extend selection beyond possible delimiters
while (firstElement != null &&
(firstElement instanceof PsiWhiteSpace || firstElement.getNode().getElementType() == JsonElementTypes.COMMA)) {
firstElement = firstElement.getNextSibling();
}
while (lastElement != null &&
(lastElement instanceof PsiWhiteSpace || lastElement.getNode().getElementType() == JsonElementTypes.COMMA)) {
lastElement = lastElement.getPrevSibling();
}
if (firstElement != null) {
startOffset = firstElement.getTextRange().getStartOffset();
}
if (lastElement != null) {
endOffset = lastElement.getTextRange().getEndOffset();
}
final JsonElement property = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JsonProperty.class);
if (property != null) {
final List<JsonElement> properties = ContainerUtil.newArrayList(property);
PsiElement nextSibling = property.getNextSibling();
while (nextSibling != null && nextSibling.getTextRange().getEndOffset() <= endOffset) {
if (nextSibling instanceof JsonProperty) {
properties.add((JsonProperty)nextSibling);
}
nextSibling = nextSibling.getNextSibling();
}
return properties.toArray(new PsiElement[properties.size()]);
}
final JsonValue value = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JsonValue.class);
if (value != null) {
return new PsiElement[]{value};
}
return PsiElement.EMPTY_ARRAY;
}
@NotNull
@Override
public Surrounder[] getSurrounders() {
return ourSurrounders;
}
@Override
public boolean isExclusive() {
return false;
}
}
@@ -0,0 +1,87 @@
package com.intellij.json.surroundWith;
import com.intellij.json.JsonBundle;
import com.intellij.json.psi.*;
import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* This surrounder ported from JavaScript allows to wrap single JSON value or several consecutive JSON properties
* in object literal.
* <p/>
* Examples:
* <ol>
* <li>{@code [42]} converts to <code>[{"property": 42}]</code></li>
* <li><pre>
* {
* "foo": 42,
* "bar": false
* }
* </pre> converts to <pre>
* {
* "property": {
* "foo": 42,
* "bar": false
* }
* }
* </pre></li>
* </ol>
*
* @author Mikhail Golubev
*/
public class JsonWithObjectLiteralSurrounder implements Surrounder {
@Override
public String getTemplateDescription() {
return JsonBundle.message("name.surround.with.object.literal");
}
@Override
public boolean isApplicable(@NotNull PsiElement[] elements) {
return !JsonPsiUtil.isPropertyKey(elements[0]);
}
@Nullable
@Override
public TextRange surroundElements(@NotNull Project project,
@NotNull Editor editor,
@NotNull PsiElement[] elements) throws IncorrectOperationException {
if (!isApplicable(elements)) {
return null;
}
final JsonElementGenerator generator = new JsonElementGenerator(project);
final PsiElement firstElement = elements[0];
final JsonElement newNameElement;
if (firstElement instanceof JsonValue) {
assert elements.length == 1 : "Only single JSON value can be wrapped in object literal";
JsonObject replacement = generator.createValue("{\n\"property\": " + firstElement.getText() + "\n}");
replacement = (JsonObject)firstElement.replace(replacement);
newNameElement = replacement.getPropertyList().get(0).getNameElement();
}
else {
assert firstElement instanceof JsonProperty;
final JsonProperty firstProperty = (JsonProperty)elements[0];
final JsonProperty lastProperty = (JsonProperty)elements[elements.length - 1];
final TextRange replacedRange = new TextRange(firstProperty.getTextOffset(), lastProperty.getTextRange().getEndOffset());
final String propertiesText = replacedRange.substring(firstProperty.getContainingFile().getText());
if (firstProperty != lastProperty) {
final PsiElement parent = firstProperty.getParent();
parent.deleteChildRange(firstProperty.getNextSibling(), lastProperty);
}
final JsonObject tempJsonObject = generator.createValue("{\"property\": {\n" + propertiesText + "\n}}");
JsonProperty replacement = tempJsonObject.getPropertyList().get(0);
replacement = (JsonProperty)firstProperty.replace(replacement);
newNameElement = replacement.getNameElement();
}
final TextRange rangeWithQuotes = newNameElement.getTextRange();
return new TextRange(rangeWithQuotes.getStartOffset() + 1, rangeWithQuotes.getEndOffset() - 1);
}
}
+112
View File
@@ -0,0 +1,112 @@
{
parserClass = 'com.intellij.json.JsonParser'
parserUtilClass = "com.intellij.json.psi.JsonParserUtil"
psiPackage = 'com.intellij.json.psi'
psiImplPackage = 'com.intellij.json.psi.impl'
elementTypeHolderClass = 'com.intellij.json.JsonElementTypes'
elementTypeClass = 'com.intellij.json.JsonElementType'
psiClassPrefix = "Json"
psiVisitorName = "JsonElementVisitor"
psiImplUtilClass = 'com.intellij.json.psi.impl.JsonPsiImplUtils'
tokenTypeClass = 'com.intellij.json.JsonTokenType'
implements = "com.intellij.json.psi.JsonElement"
extends = "com.intellij.json.psi.impl.JsonElementImpl"
tokens = [
L_CURLY='{'
R_CURLY='}'
L_BRACKET='['
R_BRACKET=']'
COMMA=','
COLON=':'
LINE_COMMENT='regexp://.*'
// "/*" ([^*]|\*+[^*/])* (\*+"/")?
BLOCK_COMMENT='regexp:/\*([^*]|\*+[^*/])*(\*+/)?'
// else /\*(?:[^*]|\*[^/])*\*+/
// unclosed string literal matches till the line's end
// any escape sequences included, illegal escapes are indicated by SyntaxHighlighter
// and JsonStringLiteralAnnotator
DOUBLE_QUOTED_STRING="regexp:\"([^\\\"\r\n]|\\[^\r\n])*\"?"
SINGLE_QUOTED_STRING="regexp:'([^\\\'\r\n]|\\[^\r\n])*'?"
// STRING='regexp:"([^\\"\r\n]|\\([\\"/bfnrt]|u[a-fA-F0-9]{4}))*"?'
NUMBER='regexp:-?\d+(\.\d+([eE][+-]?\d+)?)?'
TRUE='true'
FALSE='false'
NULL='null'
// Actually not defined in RFC 4627, but may be used for JSON5 and helps with
// auto completion of keywords.
INDENTIFIER='regexp:[:jletter:] [:jletterdigit:]*'
]
extends("container|literal|reference_expression")=value
extends("array|object")=container
extends("string_literal|number_literal|boolean_literal|null_literal")=literal
implements("property")=[
"com.intellij.json.psi.JsonElement"
"com.intellij.psi.PsiNamedElement"
]
}
// For compatibility we allow any value at root level (see JsonStandardComplianceAnnotator)
json ::= value
object ::= '{' object_element* '}' {
pin=1
methods=[
findProperty
]
}
// Hackity-hack to parse array elements and properties even if separating commas are missing,
// TODO: Find out if there is any simpler way to do so in GrammarKit
private object_element ::= property (','|&'}') {
recoverWhile = not_brace_or_next_value
pin = 1
}
property ::= property_name (':' value) {
methods=[
getName
getNameElement
getValue
// suppress getValueList() accessor
value=""
]
mixin="com.intellij.json.psi.impl.JsonPropertyMixin"
pin(".*")=1
}
private property_name ::= literal | reference_expression
array ::= '[' array_element* ']' { pin=1 }
private array_element ::= value (','|&']') {
recoverWhile = not_bracket_or_next_value
pin=1
}
string_literal ::= SINGLE_QUOTED_STRING | DOUBLE_QUOTED_STRING
number_literal ::= NUMBER
boolean_literal ::= TRUE | FALSE
null_literal ::= NULL
literal ::= string_literal | number_literal | boolean_literal | null_literal {
methods=[isQuotedString]
mixin="com.intellij.json.psi.impl.JsonLiteralMixin"
}
fake container ::= object | literal
reference_expression ::= INDENTIFIER
value ::= object | array | literal | reference_expression
// Recoveries
private not_bracket_or_next_value ::= !(']'|value)
private not_brace_or_next_value ::= !('}'|value)
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="testFramework" scope="TEST" />
<orderEntry type="module" module-name="json" scope="TEST" />
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
</component>
</module>
@@ -0,0 +1,24 @@
package com.intellij.json;
import com.intellij.openapi.actionSystem.IdeActions;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonCommenterTest extends JsonTestCase {
private void doTest(@NotNull String actionId) {
myFixture.configureByFile("commenter/" + getTestName(false) + ".json");
myFixture.performEditorAction(actionId);
myFixture.checkResultByFile("commenter/" + getTestName(false) + "_after.json", true);
}
public void testLineComment() {
doTest(IdeActions.ACTION_COMMENT_LINE);
}
public void testBlockComment() {
doTest(IdeActions.ACTION_COMMENT_BLOCK);
}
}
@@ -0,0 +1,53 @@
package com.intellij.json;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.util.ArrayUtil;
/**
* @author Mikhail Golubev
*/
public class JsonCompletionTest extends JsonTestCase {
private static final String[] ALL_KEYWORDS = new String[]{"true", "false", "null"};
private static final String[] NOTHING = ArrayUtil.EMPTY_STRING_ARRAY;
private void doTest(String... variants) {
myFixture.testCompletionVariants("completion/" + getTestName(false) + ".json", variants);
}
private void doTestSingleVariant() {
myFixture.configureByFile("completion/" + getTestName(false) + ".json");
final LookupElement[] variants = myFixture.completeBasic();
assertNull(variants);
myFixture.checkResultByFile("completion/" + getTestName(false) + "_after.json" );
}
public void testInsideArrayElement1() throws Exception {
doTest(ALL_KEYWORDS);
}
public void testInsideArrayElement2() throws Exception {
doTest(ALL_KEYWORDS);
}
public void testInsidePropertyKey1() throws Exception {
doTest(NOTHING);
}
public void testInsidePropertyKey2() throws Exception {
doTest(NOTHING);
}
public void testInsidePropertyValue() throws Exception {
doTest(ALL_KEYWORDS);
}
// Moved from JavaScript
public void testKeywords() {
doTestSingleVariant();
}
public void testKeywords_2() {
doTestSingleVariant();
}
}
@@ -0,0 +1,34 @@
package com.intellij.json;
/**
* @author Mikhail Golubev
*/
public class JsonFoldingTest extends JsonTestCase {
private void doTest() {
myFixture.testFolding(getTestDataPath() + "/folding/" + getTestName(false) + ".json");
}
public void testArrayFolding() {
doTest();
}
public void testObjectFolding() {
doTest();
}
// Moved from JavaScript
public void testObjectLiteral2() {
doTest();
}
public void testObjectLiteral3() {
doTest();
}
public void testObjectLiteral4() {
doTest();
}
}
@@ -0,0 +1,109 @@
package com.intellij.json;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.FormatterTestCase;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.TestLoggerFactory;
/**
* @author Mikhail Golubev
*/
public class JsonFormattingTest extends FormatterTestCase {
static {
Logger.setFactory(TestLoggerFactory.class);
}
@Override
protected void setUp() throws Exception {
IdeaTestCase.initPlatformPrefix();
super.setUp();
}
@Override
protected String getTestName(boolean ignored) {
// always use uppercase first letter for consistency
return super.getTestName(false);
}
@Override
protected String getBasePath() {
return "formatting";
}
@Override
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath() + "/json/tests/testData/";
}
@Override
protected String getFileExtension() {
return "json";
}
public void testContainerElementsAlignment() throws Exception {
doTest();
}
public void testBlankLinesStripping() throws Exception {
doTest();
}
public void testSpacesInsertion() throws Exception {
doTest();
}
public void testWrapping() throws Exception {
final CodeStyleSettings settings = getSettings();
settings.setRightMargin(JsonLanguage.INSTANCE, 20);
doTest();
}
// Moved from JavaScript
public void testWeb3830() throws Exception {
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings();
final CommonCodeStyleSettings.IndentOptions indentOptions = settings.getCommonSettings(JsonLanguage.INSTANCE).getIndentOptions();
final int indent = indentOptions.INDENT_SIZE;
final boolean useTabs = indentOptions.USE_TAB_CHARACTER;
final int tabSize = indentOptions.TAB_SIZE;
try {
indentOptions.INDENT_SIZE = 8;
indentOptions.USE_TAB_CHARACTER = true;
indentOptions.TAB_SIZE = 8;
doTest();
}
finally {
indentOptions.INDENT_SIZE = indent;
indentOptions.USE_TAB_CHARACTER = useTabs;
indentOptions.TAB_SIZE = tabSize;
}
}
public void testReformatJSon() throws Exception {
final CommonCodeStyleSettings.IndentOptions indentOptions = getSettings().getCommonSettings(JsonLanguage.INSTANCE).getIndentOptions();
final int oldIndentSize = indentOptions.INDENT_SIZE;
try {
indentOptions.INDENT_SIZE = 4;
doTest();
}
finally {
indentOptions.INDENT_SIZE = oldIndentSize;
}
}
public void testReformatJSon2() throws Exception {
final CommonCodeStyleSettings.IndentOptions indentOptions = getSettings().getCommonSettings(JsonLanguage.INSTANCE).getIndentOptions();
final int oldIndentSize = indentOptions.INDENT_SIZE;
try {
indentOptions.INDENT_SIZE = 4;
doTest();
}
finally {
indentOptions.INDENT_SIZE = oldIndentSize;
}
}
}
@@ -0,0 +1,57 @@
package com.intellij.json;
import com.intellij.json.codeinsight.JsonStandardComplianceInspection;
/**
* @author Mikhail Golubev
*/
public class JsonHighlightingTest extends JsonTestCase {
private void doTest() {
doTestHighlighting(true, true, true);
}
private long doTestHighlighting(boolean checkInfo, boolean checkWeakWarning, boolean checkWarning) {
return myFixture.testHighlighting(checkWarning, checkInfo, checkWeakWarning, "/highlighting/" + getTestName(false) + ".json");
}
private void enableStandardComplianceInspection(boolean checkComments) {
final JsonStandardComplianceInspection inspection = new JsonStandardComplianceInspection();
inspection.myWarnAboutComments = checkComments;
myFixture.enableInspections(inspection);
}
public void testStringLiterals() {
doTest();
}
public void testComplianceProblemsTopLevelValue() {
enableStandardComplianceInspection(true);
doTest();
}
public void testComplianceProblems() {
enableStandardComplianceInspection(true);
doTest();
}
// Moved from JavaScript
public void testJSON_with_comment() throws Exception {
enableStandardComplianceInspection(false);
doTest();
}
public void testJSON() throws Exception {
enableStandardComplianceInspection(true);
doTest();
}
// TODO: JSON semantic highlighting?
/*
public void testSemanticHighlighting() throws Exception {
doTest();
}
*/
}
@@ -0,0 +1,49 @@
package com.intellij.json;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
/**
* @author Mikhail Golubev
*/
public class JsonLineMoverTest extends JsonTestCase {
private void doTest(boolean down) {
final String testName = getTestName(false);
if (down) {
myFixture.configureByFile("mover/" + testName + ".json");
myFixture.performEditorAction(IdeActions.ACTION_MOVE_STATEMENT_DOWN_ACTION);
myFixture.checkResultByFile("mover/" + testName + "_afterDown.json", true);
}
else {
myFixture.configureByFile("mover/" + testName + ".json");
myFixture.performEditorAction(IdeActions.ACTION_MOVE_STATEMENT_UP_ACTION);
myFixture.checkResultByFile("mover/" + testName + "_afterUp.json", true);
}
}
public void testLastArrayElementMovedUp() {
doTest(false);
}
public void testLastObjectPropertyMovedUp() {
doTest(false);
}
public void testArraySelectionMovedDown() {
doTest(true);
}
public void testObjectSelectionMovedDown() {
doTest(true);
}
// Moved from JavaScript
public void testWeb_10585() {
doTest(false);
FileDocumentManager.getInstance().reloadFromDisk(myFixture.getDocument(myFixture.getFile()));
doTest(true);
}
}
@@ -0,0 +1,96 @@
package com.intellij.json;
import com.intellij.testFramework.ParsingTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.TestDataPath;
/**
* @author Mikhail Golubev
*/
@TestDataPath("$CONTENT_ROOT/testData/psi/")
public class JsonParsingTest extends ParsingTestCase {
public JsonParsingTest() {
super("psi", "json", new JsonParserDefinition());
}
@Override
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath() + "/json/tests/testData";
}
private void doTest() {
doTest(true);
}
public void testKeywords() throws Exception {
doTest();
}
public void testNestedArrayLiterals() {
doTest();
}
public void testNestedObjectLiterals() {
doTest();
}
public void testTopLevelStringLiteral() {
doTest();
}
public void testStringLiterals() {
doTest();
}
public void testComments() {
doTest();
}
public void testIncompleteObjectProperties() {
doTest();
}
public void testMissingCommaBetweenArrayElements() {
doTest();
}
public void testMissingCommaBetweenObjectProperties() {
doTest();
}
public void testNonStandardPropertyKeys() {
doTest();
}
public void testTrailingCommas() {
doTest();
}
// Moved from JavaScript
public void testSimple1() {
doTest();
}
public void testSimple2() {
doTest();
}
public void testSimple4() {
doTest();
}
// TODO: ask about these tests
//public void testSimple3() {
// doTest();
//}
//
//public void testReal1() {
// doTest();
//}
//
//public void testReal2() {
// doTest();
//}
}
@@ -0,0 +1,52 @@
package com.intellij.json;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.json.codeinsight.JsonStandardComplianceInspection;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class JsonQuickFixTest extends JsonTestCase {
protected void doTest(@NotNull Class<? extends LocalInspectionTool> inspectionClass, @NotNull String hint) {
final String testFileName = "quickfix/" + getTestName(false);
myFixture.enableInspections(inspectionClass);
myFixture.configureByFile(testFileName + ".json");
myFixture.checkHighlighting(true, false, false);
final IntentionAction intentionAction = myFixture.getAvailableIntention(hint);
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(testFileName + "_after.json", true);
}
public void testWrapInDoubleQuotes() {
checkWrapInDoubleQuotes("{n<caret>ull: false}", "{\"null\": false}");
checkWrapInDoubleQuotes("{t<caret>rue: false}", "{\"true\": false}");
checkWrapInDoubleQuotes("{4<caret>2: false}", "{\"42\": false}");
checkWrapInDoubleQuotes("{fo<caret>o: false}", "{\"foo\": false}");
checkWrapInDoubleQuotes("{'fo<caret>o': false}", "{\"foo\": false}");
checkWrapInDoubleQuotes("{\"foo\": b<caret>ar}", "{\"foo\": \"bar\"}");
checkWrapInDoubleQuotes("{\"foo\": 'b<caret>ar'}", "{\"foo\": \"bar\"}");
}
private void checkWrapInDoubleQuotes(@NotNull String before, @NotNull String after) {
myFixture.configureByText(JsonFileType.INSTANCE, before);
myFixture.enableInspections(JsonStandardComplianceInspection.class);
final IntentionAction intentionAction = myFixture.getAvailableIntention(JsonBundle.message("name.add.double.quotes.quickfix"));
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResult(after);
}
// Moved from JavaScript
public void testJSON2() {
doTest(JsonStandardComplianceInspection.class, JsonBundle.message("name.add.double.quotes.quickfix"));
}
public void testJSON3() {
doTest(JsonStandardComplianceInspection.class, JsonBundle.message("name.add.double.quotes.quickfix"));
}
}
@@ -0,0 +1,28 @@
package com.intellij.json;
/**
* @author Mikhail Golubev
*/
public class JsonRenameTest extends JsonTestCase {
private void doTest(final String newName) {
myFixture.configureByFile("rename/" + getTestName(false) + ".json");
myFixture.renameElementAtCaret(newName);
myFixture.checkResultByFile("rename/" + getTestName(false) + "_after.json");
}
public void testPropertyNameRequiresEscaping() {
doTest("\"/\\\b\f\n\r\t\0\u001B'");
}
// Moved from JavaScript
public void testDuplicateProperties() {
doTest("aaa2");
}
public void testDuplicatePropertiesQuotedName() {
doTest("\"aaa2\"");
}
}
@@ -0,0 +1,46 @@
package com.intellij.json;
import com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessor;
import com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessors;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public class JsonSmartEnterTest extends JsonTestCase {
public void doTest() {
myFixture.configureByFile("smartEnter/" + getTestName(false) + ".json");
final List<SmartEnterProcessor> processors = SmartEnterProcessors.INSTANCE.forKey(JsonLanguage.INSTANCE);
new WriteCommandAction(myFixture.getProject()) {
@Override
protected void run(@NotNull Result result) throws Throwable {
final Editor editor = myFixture.getEditor();
for (SmartEnterProcessor processor : processors) {
processor.process(myFixture.getProject(), editor, myFixture.getFile());
}
}
}.execute();
myFixture.checkResultByFile("smartEnter/" + getTestName(false) + "_after.json", true);
}
public void testCommaInsertedAfterArrayElement() {
doTest();
}
public void testCommaInsertedAfterProperty() {
doTest();
}
public void testCommaInsertedAfterPropertyWithMultilineValue() {
doTest();
}
public void testColonInsertedAfterPropertyKey() {
doTest();
}
}
@@ -0,0 +1,69 @@
package com.intellij.json;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.lang.LanguageStructureViewBuilder;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Consumer;
import com.intellij.util.PlatformIcons;
import static com.intellij.testFramework.PlatformTestUtil.assertTreeEqual;
/**
* @author Mikhail Golubev
*/
public class JsonStructureViewTest extends JsonTestCase {
private void doTest(final String expected) {
myFixture.configureByFile("structureView/" + getTestName(false) + ".json");
myFixture.testStructureView(new Consumer<StructureViewComponent>() {
@Override
public void consume(StructureViewComponent component) {
assertTreeEqual(component.getTree(), expected);
}
});
}
public void testSimpleStructure() {
doTest("-SimpleStructure.json\n" +
" aaa\n" +
" -bbb\n" +
" ccc\n");
}
// Moved from JavaScript
public void testJsonStructure() {
myFixture.configureByFile("structureView/SimpleStructure.json");
final StructureViewBuilder builder = LanguageStructureViewBuilder.INSTANCE.getStructureViewBuilder(myFixture.getFile());
assertNotNull(builder);
StructureViewComponent component = null;
try {
final FileEditor editor = FileEditorManager.getInstance(getProject()).getSelectedEditor(myFixture.getFile().getVirtualFile());
component = (StructureViewComponent)builder.createStructureView(editor, myFixture.getProject());
final StructureViewModel model = component.getTreeModel();
TreeElement[] children = model.getRoot().getChildren();
assertEquals(2, children.length);
assertEquals("aaa", children[0].getPresentation().getPresentableText());
assertEquals(PlatformIcons.PROPERTY_ICON, children[0].getPresentation().getIcon(false));
assertEquals("bbb", children[1].getPresentation().getPresentableText());
assertEquals(PlatformIcons.PROPERTY_ICON, children[1].getPresentation().getIcon(false));
children = children[1].getChildren();
assertEquals(1, children.length);
assertEquals("ccc", children[0].getPresentation().getPresentableText());
assertEquals(PlatformIcons.PROPERTY_ICON, children[0].getPresentation().getIcon(false));
}
finally {
if (component != null) {
Disposer.dispose(component);
}
}
}
}
@@ -0,0 +1,44 @@
package com.intellij.json;
import com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler;
import com.intellij.json.surroundWith.JsonWithObjectLiteralSurrounder;
import com.intellij.openapi.command.WriteCommandAction;
/**
* @author Mikhail Golubev
*/
public class JsonSurroundWithTest extends JsonTestCase {
private void doTest() {
myFixture.configureByFile("/surround/" + getTestName(false) + ".json");
new WriteCommandAction.Simple(myFixture.getProject()) {
@Override
protected void run() {
SurroundWithHandler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), new JsonWithObjectLiteralSurrounder());
}
}.execute();
myFixture.checkResultByFile("/surround/" + getTestName(false) + "_after.json", true);
}
public void testSingleValue() {
doTest();
}
public void testSingleProperty() {
doTest();
}
public void testMultipleProperties() {
doTest();
}
public void testCannotSurroundPropertyKey() {
doTest();
}
// Moved from JavaScript
public void testObjectLiteral() {
doTest();
}
}

Some files were not shown because too many files have changed in this diff Show More