mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
+2
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
+4
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+6
-6
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
Reference in New Issue
Block a user