correct .env syntax

GitOrigin-RevId: 0d72d9e7503e35ca29ecb4a67d9792ecd9b8c824
This commit is contained in:
adelf
2018-08-24 21:14:10 +03:00
committed by intellij-monorepo-bot
parent 9bfcf5a79e
commit 8a3427049d
11 changed files with 174 additions and 61 deletions

View File

@@ -26,6 +26,8 @@ class _DotEnvLexer implements FlexLexer {
/** lexical states */
public static final int YYINITIAL = 0;
public static final int WAITING_VALUE = 2;
public static final int WAITING_QUOTED_VALUE = 4;
public static final int WAITING_COMMENT = 6;
/**
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
@@ -34,7 +36,7 @@ class _DotEnvLexer implements FlexLexer {
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = {
0, 0, 1, 1
0, 0, 1, 1, 2, 2, 3, 3
};
/**
@@ -56,8 +58,8 @@ class _DotEnvLexer implements FlexLexer {
/* The ZZ_CMAP_A table has 320 entries */
static final char ZZ_CMAP_A[] = zzUnpackCMap(
"\11\0\1\4\1\2\1\1\1\5\1\3\22\0\1\7\2\0\1\10\13\0\1\11\12\0\1\12\2\0\1\12\36"+
"\0\1\6\50\0\1\1\242\0\2\1\26\0");
"\11\0\1\4\1\2\1\1\1\5\1\3\22\0\1\7\1\0\1\6\1\11\26\0\1\12\2\0\1\12\36\0\1"+
"\10\50\0\1\1\242\0\2\1\26\0");
/**
* Translates DFA states to action switch labels.
@@ -65,11 +67,12 @@ class _DotEnvLexer implements FlexLexer {
private static final int [] ZZ_ACTION = zzUnpackAction();
private static final String ZZ_ACTION_PACKED_0 =
"\2\0\2\1\1\2\1\3\1\4\1\1\1\5\2\6"+
"\2\7\1\3\1\7\1\0\2\4\1\2\1\6";
"\4\0\2\1\1\2\1\3\1\4\1\5\2\6\2\7"+
"\1\10\1\7\1\3\1\11\2\12\1\13\1\12\3\11"+
"\1\0\2\4\1\2\1\6\1\2";
private static int [] zzUnpackAction() {
int [] result = new int[20];
int [] result = new int[31];
int offset = 0;
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
return result;
@@ -95,11 +98,12 @@ class _DotEnvLexer implements FlexLexer {
private static final String ZZ_ROWMAP_PACKED_0 =
"\0\0\0\13\0\26\0\41\0\54\0\67\0\102\0\115"+
"\0\130\0\143\0\156\0\171\0\54\0\204\0\217\0\67"+
"\0\232\0\245\0\156\0\260";
"\0\130\0\143\0\156\0\171\0\204\0\102\0\143\0\217"+
"\0\232\0\156\0\245\0\260\0\143\0\273\0\306\0\321"+
"\0\334\0\115\0\347\0\362\0\171\0\375\0\321";
private static int [] zzUnpackRowMap() {
int [] result = new int[20];
int [] result = new int[31];
int offset = 0;
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
return result;
@@ -122,22 +126,28 @@ class _DotEnvLexer implements FlexLexer {
private static final int [] ZZ_TRANS = zzUnpackTrans();
private static final String ZZ_TRANS_PACKED_0 =
"\1\3\1\4\1\5\1\4\2\5\1\6\1\5\1\7"+
"\1\10\1\11\1\12\1\13\2\5\1\14\1\15\1\16"+
"\1\17\3\12\2\3\1\0\1\3\2\0\1\20\1\0"+
"\2\3\1\0\1\3\1\4\1\5\1\4\2\5\1\20"+
"\1\5\2\3\2\0\5\5\1\0\1\5\12\0\1\3"+
"\3\0\2\7\1\0\1\3\2\21\1\22\1\21\2\7"+
"\1\21\2\3\1\0\1\3\2\0\1\20\1\0\1\3"+
"\1\7\14\0\2\12\2\0\10\12\1\23\2\5\2\23"+
"\1\12\1\23\4\12\1\24\2\5\2\14\1\12\1\14"+
"\4\12\3\0\1\12\1\0\5\12\1\0\3\5\2\17"+
"\1\0\1\17\3\0\2\21\2\0\11\21\2\0\3\21"+
"\1\7\3\21\1\12\1\24\2\5\2\24\1\12\1\24"+
"\3\12";
"\1\5\1\6\1\7\1\6\2\7\1\5\1\7\1\10"+
"\1\11\1\12\1\13\1\14\2\7\1\15\1\16\1\17"+
"\1\20\1\21\1\22\1\13\1\23\1\24\2\7\2\24"+
"\1\25\1\24\1\26\2\23\1\27\1\30\2\7\1\31"+
"\1\30\1\27\1\31\3\27\2\5\1\0\1\5\2\0"+
"\1\5\1\0\1\32\1\5\1\0\1\5\1\6\1\7"+
"\1\6\2\7\1\5\1\7\1\32\1\5\2\0\5\7"+
"\1\0\1\7\12\0\1\5\3\0\2\11\1\0\1\5"+
"\2\33\1\11\1\33\1\34\1\11\1\33\13\0\2\13"+
"\2\0\5\13\1\0\2\13\1\35\2\7\2\35\1\13"+
"\1\35\1\13\1\0\2\13\1\36\2\7\2\15\1\13"+
"\1\15\1\13\1\0\1\13\1\0\3\7\2\20\1\0"+
"\1\20\3\0\1\13\3\0\1\13\1\0\5\13\2\23"+
"\2\0\2\23\1\0\1\23\1\26\3\23\1\24\2\7"+
"\2\24\1\0\1\24\1\26\4\23\2\0\4\23\1\26"+
"\2\23\2\27\2\0\10\27\1\37\2\7\2\37\1\27"+
"\1\37\4\27\1\31\2\7\2\31\1\27\1\31\3\27"+
"\2\33\2\0\11\33\2\0\3\33\1\11\3\33\1\13"+
"\1\36\2\7\2\36\1\13\1\36\1\13\1\0\1\13";
private static int [] zzUnpackTrans() {
int [] result = new int[187];
int [] result = new int[264];
int offset = 0;
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
return result;
@@ -175,10 +185,11 @@ class _DotEnvLexer implements FlexLexer {
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
private static final String ZZ_ATTRIBUTE_PACKED_0 =
"\2\0\6\1\1\11\6\1\1\0\4\1";
"\4\0\5\1\1\11\4\1\1\11\5\1\1\11\4\1"+
"\1\0\5\1";
private static int [] zzUnpackAttribute() {
int [] result = new int[20];
int [] result = new int[31];
int offset = 0;
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
return result;
@@ -482,37 +493,57 @@ class _DotEnvLexer implements FlexLexer {
{ yybegin(YYINITIAL); return DotEnvTypes.KEY_CHARS;
}
// fall through
case 8: break;
case 12: break;
case 2:
{ yybegin(YYINITIAL); return TokenType.WHITE_SPACE;
}
// fall through
case 9: break;
case 13: break;
case 3:
{ return TokenType.BAD_CHARACTER;
}
// fall through
case 10: break;
case 14: break;
case 4:
{ yybegin(YYINITIAL); return DotEnvTypes.COMMENT;
}
// fall through
case 11: break;
case 15: break;
case 5:
{ yybegin(WAITING_VALUE); return DotEnvTypes.SEPARATOR;
}
// fall through
case 12: break;
case 16: break;
case 6:
{ yybegin(YYINITIAL); return DotEnvTypes.VALUE_CHARS;
}
// fall through
case 13: break;
case 17: break;
case 7:
{ yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE;
}
// fall through
case 14: break;
case 18: break;
case 8:
{ yybegin(WAITING_QUOTED_VALUE); return DotEnvTypes.QUOTE;
}
// fall through
case 19: break;
case 9:
{ yybegin(WAITING_COMMENT); return DotEnvTypes.COMMENT;
}
// fall through
case 20: break;
case 10:
{ yybegin(WAITING_QUOTED_VALUE); return DotEnvTypes.VALUE_CHARS;
}
// fall through
case 21: break;
case 11:
{ yybegin(WAITING_COMMENT); return DotEnvTypes.QUOTE;
}
// fall through
case 22: break;
default:
zzScanError(ZZ_NO_MATCH);
}

View File

@@ -78,19 +78,19 @@ public class DotEnvParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// (key SEPARATOR value?) | key
// (key SEPARATOR value? COMMENT?) | key COMMENT?
public static boolean property(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "property")) return false;
if (!nextTokenIs(b, KEY_CHARS)) return false;
boolean r;
Marker m = enter_section_(b);
r = property_0(b, l + 1);
if (!r) r = key(b, l + 1);
if (!r) r = property_1(b, l + 1);
exit_section_(b, m, PROPERTY, r);
return r;
}
// key SEPARATOR value?
// key SEPARATOR value? COMMENT?
private static boolean property_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "property_0")) return false;
boolean r;
@@ -98,6 +98,7 @@ public class DotEnvParser implements PsiParser, LightPsiParser {
r = key(b, l + 1);
r = r && consumeToken(b, SEPARATOR);
r = r && property_0_2(b, l + 1);
r = r && property_0_3(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
@@ -109,16 +110,68 @@ public class DotEnvParser implements PsiParser, LightPsiParser {
return true;
}
/* ********************************************************** */
// VALUE_CHARS
public static boolean value(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "value")) return false;
if (!nextTokenIs(b, VALUE_CHARS)) return false;
// COMMENT?
private static boolean property_0_3(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "property_0_3")) return false;
consumeToken(b, COMMENT);
return true;
}
// key COMMENT?
private static boolean property_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "property_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, VALUE_CHARS);
exit_section_(b, m, VALUE, r);
r = key(b, l + 1);
r = r && property_1_1(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// COMMENT?
private static boolean property_1_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "property_1_1")) return false;
consumeToken(b, COMMENT);
return true;
}
/* ********************************************************** */
// VALUE_CHARS | QUOTE VALUE_CHARS? QUOTE?
public static boolean value(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "value")) return false;
if (!nextTokenIs(b, "<value>", QUOTE, VALUE_CHARS)) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, VALUE, "<value>");
r = consumeToken(b, VALUE_CHARS);
if (!r) r = value_1(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
// QUOTE VALUE_CHARS? QUOTE?
private static boolean value_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "value_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, QUOTE);
r = r && value_1_1(b, l + 1);
r = r && value_1_2(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// VALUE_CHARS?
private static boolean value_1_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "value_1_1")) return false;
consumeToken(b, VALUE_CHARS);
return true;
}
// QUOTE?
private static boolean value_1_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "value_1_2")) return false;
consumeToken(b, QUOTE);
return true;
}
}

View File

@@ -15,6 +15,7 @@ public interface DotEnvTypes {
IElementType COMMENT = new DotEnvTokenType("COMMENT");
IElementType CRLF = new DotEnvTokenType("CRLF");
IElementType KEY_CHARS = new DotEnvTokenType("KEY_CHARS");
IElementType QUOTE = new DotEnvTokenType("QUOTE");
IElementType SEPARATOR = new DotEnvTokenType("SEPARATOR");
IElementType VALUE_CHARS = new DotEnvTokenType("VALUE_CHARS");

View File

@@ -23,9 +23,10 @@ public class DotEnvPsiElementsVisitor extends PsiRecursiveElementVisitor {
}
private void visitProperty(DotEnvProperty property) {
EnvironmentKeyValue keyValue = EnvironmentVariablesUtil.getKeyValueFromString(property.getText());
collectedItems.add(new KeyValuePsiElement(keyValue.getKey(), keyValue.getValue(), property));
collectedItems.add(new KeyValuePsiElement(
property.getKey().getText(),
property.getValue() != null ? property.getValue().getText() : "",
property));
}
public Collection<KeyValuePsiElement> getCollectedItems() {

View File

@@ -12,7 +12,6 @@ import org.jetbrains.annotations.Nullable;
public class DotEnvCommenter implements Commenter, SelfManagingCommenter<CommenterDataHolder> {
private static final String HASH_COMMENT_PREFIX = "#";
private static final String SLASH_COMMENT_PREFIX = "//";
public String getLineCommentPrefix() {
return HASH_COMMENT_PREFIX;
@@ -56,17 +55,12 @@ public class DotEnvCommenter implements Commenter, SelfManagingCommenter<Comment
@Override
public void uncommentLine(int line, int offset, @NotNull Document document, @NotNull CommenterDataHolder data) {
if(document.getText().charAt(offset) == '#') {
document.deleteString(offset, offset + HASH_COMMENT_PREFIX.length());
} else {
document.deleteString(offset, offset + SLASH_COMMENT_PREFIX.length());
}
document.deleteString(offset, offset + 1);
}
@Override
public boolean isLineCommented(int line, int offset, @NotNull Document document, @NotNull CommenterDataHolder data) {
return CharArrayUtil.regionMatches(document.getCharsSequence(), offset, HASH_COMMENT_PREFIX) ||
CharArrayUtil.regionMatches(document.getCharsSequence(), offset, SLASH_COMMENT_PREFIX);
return CharArrayUtil.regionMatches(document.getCharsSequence(), offset, HASH_COMMENT_PREFIX);
}
@Nullable

View File

@@ -17,13 +17,20 @@ import static ru.adelf.idea.dotenv.psi.DotEnvTypes.*;
CRLF=\R
WHITE_SPACE=[\ \t\f]
FIRST_VALUE_CHARACTER=[^ \n\f\r\\] | "\\".
VALUE_CHARACTER=[^\r\n]
END_OF_LINE_COMMENT=("#"|"//")[^\r\n]*
FIRST_VALUE_CHARACTER=[^ \n\f\r\"\\] | "\\".
VALUE_CHARACTER=[^\r\n\#]
QUOTED_VALUE_CHARACTER=[^\r\n\"]
QUOTED_QUOTE="\\\""
ANY_CHARACTER=[^\r\n]
END_OF_LINE_COMMENT=("#")[^\r\n]*
SEPARATOR=[:=]
KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ "
QUOTE=[\"]
COMMENT=["#"]
%state WAITING_VALUE
%state WAITING_QUOTED_VALUE
%state WAITING_COMMENT
%%
@@ -37,8 +44,20 @@ KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ "
<WAITING_VALUE> {WHITE_SPACE}+ { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; }
<WAITING_VALUE> {QUOTE} { yybegin(WAITING_QUOTED_VALUE); return DotEnvTypes.QUOTE; }
<WAITING_VALUE> {COMMENT} { yybegin(WAITING_COMMENT); return DotEnvTypes.COMMENT; }
<WAITING_VALUE> {FIRST_VALUE_CHARACTER}{VALUE_CHARACTER}* { yybegin(YYINITIAL); return DotEnvTypes.VALUE_CHARS; }
<WAITING_QUOTED_VALUE> ({QUOTED_VALUE_CHARACTER}|{QUOTED_QUOTE})+ { yybegin(WAITING_QUOTED_VALUE); return DotEnvTypes.VALUE_CHARS; }
<WAITING_QUOTED_VALUE> {QUOTE} { yybegin(WAITING_COMMENT); return DotEnvTypes.QUOTE; }
<WAITING_COMMENT> {CRLF}({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_COMMENT> {ANY_CHARACTER}+ { yybegin(WAITING_COMMENT); return DotEnvTypes.COMMENT; }
({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
[^] { return TokenType.BAD_CHARACTER; }

View File

@@ -19,6 +19,6 @@ private item_ ::= (property|COMMENT|CRLF)
key ::= KEY_CHARS
value ::= VALUE_CHARS
value ::= VALUE_CHARS | QUOTE VALUE_CHARS? QUOTE?
property ::= (key SEPARATOR value?) | key
property ::= (key SEPARATOR value? COMMENT?) | key COMMENT?

View File

@@ -18,6 +18,6 @@ public class DotEnvKeyValuesIndex extends EnvironmentVariablesIndex {
@NotNull
@Override
String getIndexKey(KeyValuePsiElement keyValue) {
return keyValue.getKey() + "=" + keyValue.getValue();
return keyValue.getKey().trim() + "=" + keyValue.getValue().trim();
}
}

View File

@@ -17,6 +17,6 @@ public class DotEnvKeysIndex extends EnvironmentVariablesIndex {
@NotNull
@Override
String getIndexKey(KeyValuePsiElement keyValue) {
return keyValue.getKey();
return keyValue.getKey().trim();
}
}

View File

@@ -29,6 +29,14 @@ public class DotEnvFileTest extends DotEnvLightCodeInsightFixtureTestCase {
assertIndexContains(DotEnvKeyValuesIndex.KEY,"OFFSET_KEY=offset");
}
public void testEnvCommentedVars() {
assertIndexContains(DotEnvKeyValuesIndex.KEY,"COMMENTED_VAR=123");
assertIndexContains(DotEnvKeyValuesIndex.KEY,"COMMENTED_VAR2=\"123 #comment\"");
assertIndexContains(DotEnvKeyValuesIndex.KEY,"COMMENTED_VAR3=\"123 #com\\\"ment\"");
assertIndexContains(DotEnvKeyValuesIndex.KEY,"COMMENTED_VAR4=\"1\"");
}
public void testEnvComments() {
assertIndexNotContains(DotEnvKeysIndex.KEY,"Comment", "#Comment", "#Another comment");
}

View File

@@ -9,4 +9,10 @@ TEST3= 3
EMPTY_KEY
OFFSET_KEY = offset
OFFSET_KEY = offset
COMMENTED_VAR=123 #comment
COMMENTED_VAR2="123 #comment"
COMMENTED_VAR3="123 #com\"ment"
COMMENTED_VAR4="1"this should be commented