diff --git a/src/main/java/org/nixos/idea/lang/NixParserDefinition.java b/src/main/java/org/nixos/idea/lang/NixParserDefinition.java index d952a630..fd2b978e 100644 --- a/src/main/java/org/nixos/idea/lang/NixParserDefinition.java +++ b/src/main/java/org/nixos/idea/lang/NixParserDefinition.java @@ -77,6 +77,14 @@ public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode r if (leftType == NixTypes.DOLLAR && rightType == NixTypes.LCURLY) { return SpaceRequirements.MUST_NOT; } + else if (leftType == NixTypes.PATH_SEGMENT) { + // path segment, antiquotation or PATH_END on the right + return SpaceRequirements.MUST_NOT; + } + else if (rightType == NixTypes.PATH_END) { + // path segment or antiquotation on the left + return SpaceRequirements.MUST_NOT; + } else if (NixTypeUtil.MIGHT_COLLAPSE_WITH_ID.contains(leftType) && NixTypeUtil.MIGHT_COLLAPSE_WITH_ID.contains(rightType)) { return SpaceRequirements.MUST; diff --git a/src/main/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighter.java b/src/main/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighter.java index f6ab155c..805139eb 100644 --- a/src/main/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighter.java +++ b/src/main/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighter.java @@ -66,8 +66,7 @@ public class NixSyntaxHighlighter extends SyntaxHighlighterBase { // Literals entry(NixTypes.INT, NixTextAttributes.NUMBER), entry(NixTypes.FLOAT, NixTextAttributes.NUMBER), - entry(NixTypes.PATH, NixTextAttributes.PATH), - entry(NixTypes.HPATH, NixTextAttributes.PATH), + entry(NixTypes.PATH_SEGMENT, NixTextAttributes.PATH), entry(NixTypes.SPATH, NixTextAttributes.PATH), entry(NixTypes.URI, NixTextAttributes.URI), // String literals diff --git a/src/main/java/org/nixos/idea/psi/NixTypeUtil.java b/src/main/java/org/nixos/idea/psi/NixTypeUtil.java index c49629a8..97d7afc3 100644 --- a/src/main/java/org/nixos/idea/psi/NixTypeUtil.java +++ b/src/main/java/org/nixos/idea/psi/NixTypeUtil.java @@ -24,9 +24,9 @@ public final class NixTypeUtil { NixTypes.ID, NixTypes.INT, NixTypes.FLOAT, - NixTypes.PATH, - NixTypes.HPATH, NixTypes.SPATH, + NixTypes.PATH_SEGMENT, + NixTypes.PATH_END, NixTypes.URI)); private NixTypeUtil() {} // Cannot be instantiated diff --git a/src/main/java/org/nixos/idea/psi/impl/NixParserUtil.java b/src/main/java/org/nixos/idea/psi/impl/NixParserUtil.java index 0697e9ca..98926f88 100644 --- a/src/main/java/org/nixos/idea/psi/impl/NixParserUtil.java +++ b/src/main/java/org/nixos/idea/psi/impl/NixParserUtil.java @@ -3,6 +3,7 @@ import com.intellij.lang.PsiBuilder; import com.intellij.lang.parser.GeneratedParserUtilBase; import com.intellij.openapi.util.Key; +import com.intellij.psi.TokenType; import org.jetbrains.annotations.NotNull; public final class NixParserUtil extends GeneratedParserUtilBase { diff --git a/src/main/lang/Nix.bnf b/src/main/lang/Nix.bnf index cb0b98c8..bc4052db 100644 --- a/src/main/lang/Nix.bnf +++ b/src/main/lang/Nix.bnf @@ -169,7 +169,9 @@ expr_simple ::= | list | legacy_let identifier ::= ID -literal ::= INT | FLOAT | PATH | HPATH | SPATH | URI +literal ::= INT | FLOAT | URI | path +;{ extends("path")=literal } +path ::= SPATH | PATH_SEGMENT (PATH_SEGMENT | antiquotation)* PATH_END parens ::= LPAREN expr recover_parens RPAREN { pin=1 } set ::= [ REC ] LCURLY recover_set (bind recover_set)* RCURLY { pin=2 } list ::= LBRAC recover_list (expr_select recover_list)* RBRAC { pin=1 } diff --git a/src/main/lang/Nix.flex b/src/main/lang/Nix.flex index 23f0edc6..201a4004 100644 --- a/src/main/lang/Nix.flex +++ b/src/main/lang/Nix.flex @@ -43,15 +43,17 @@ import static org.nixos.idea.psi.NixTypes.*; %function advance %type IElementType %unicode -%state BLOCK STRING IND_STRING ANTIQUOTATION_START ANTIQUOTATION +%state BLOCK STRING IND_STRING ANTIQUOTATION_START ANTIQUOTATION PATH ANY=[^] ID=[a-zA-Z_][a-zA-Z0-9_'-]* INT=[0-9]+ FLOAT=(([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)? -PATH=[a-zA-Z0-9._+-]*(\/[a-zA-Z0-9._+-]+)+\/? -HPATH=\~(\/[a-zA-Z0-9._+-]+)+\/? -SPATH=\<[a-zA-Z0-9._+-]+(\/[a-zA-Z0-9._+-]+)*\> +PATH_CHAR=[a-zA-Z0-9\.\_\-\+] +PATH={PATH_CHAR}*(\/{PATH_CHAR}+)+\/? +PATH_SEG={PATH_CHAR}*\/ +HPATH_START=\~\/ +SPATH=\<{PATH_CHAR}+(\/{PATH_CHAR}+)*\> URI=[a-zA-Z][a-zA-Z0-9.+-]*\:[a-zA-Z0-9%/?:@&=+$,\-_.!~*']+ WHITE_SPACE=[\ \t\r\n]+ @@ -91,6 +93,16 @@ MCOMMENT=\/\*([^*]|\*[^\/])*\*\/ "}" { popState(BLOCK); return RCURLY; } } + { + "$"/"{" { pushState(ANTIQUOTATION_START); return DOLLAR; } + {PATH_SEG} { return PATH_SEGMENT; } + {PATH_CHAR}+ { return PATH_SEGMENT; } + // anything else, e.g. whitespace, stops lexing of a PATH + // we're delegating back to the parent state + // PATH_END is an empty-length token to signal the end of the path + [^] { popState(PATH); yypushback(yylength()); return PATH_END; } +} + { "if" { return IF; } "then" { return THEN; } @@ -146,8 +158,10 @@ MCOMMENT=\/\*([^*]|\*[^\/])*\*\/ {ID} { return ID; } {INT} { return INT; } {FLOAT} { return FLOAT; } - {PATH} { return PATH; } - {HPATH} { return HPATH; } + "/" / "${" { pushState(PATH); return PATH_SEGMENT; } + {PATH} + | {PATH_SEG} + | {HPATH_START} { pushState(PATH); return PATH_SEGMENT; } {SPATH} { return SPATH; } {URI} { return URI; } diff --git a/src/test/java/org/nixos/idea/lang/ParsingTest.java b/src/test/java/org/nixos/idea/lang/ParsingTest.java index d4bdeca8..39365b81 100644 --- a/src/test/java/org/nixos/idea/lang/ParsingTest.java +++ b/src/test/java/org/nixos/idea/lang/ParsingTest.java @@ -145,10 +145,13 @@ public void testWith() { @Override protected void tearDown() throws Exception { - // Ensure that the parser does not generate errors even when the errors have - // accidentally been added to the expected result. - ensureNoErrorElements(); - super.tearDown(); + try { + // Ensure that the parser does not generate errors even when the errors have + // accidentally been added to the expected result. + ensureNoErrorElements(); + } finally { + super.tearDown(); + } } @Override diff --git a/src/test/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterTest.java b/src/test/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterTest.java index 90e9765b..831d32a7 100644 --- a/src/test/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterTest.java +++ b/src/test/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterTest.java @@ -3,6 +3,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Test; @@ -15,12 +16,12 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static java.util.function.Predicate.not; +import static org.junit.jupiter.api.Assertions.*; final class NixSyntaxHighlighterTest { + private static final TokenSet EMPTY_LENGTH_TOKENS = TokenSet.create(NixTypes.PATH_END); + @Test void testAttributesKeysForUnknownTokenType() { TextAttributesKey[] tokenHighlights = new NixSyntaxHighlighter().getTokenHighlights(TokenType.CODE_FRAGMENT); @@ -38,9 +39,10 @@ void testAttributesKeysForKnownTokenTypes(@NotNull IElementType tokenType) { () -> assertNotNull(tokenHighlights[index], String.format("tokenHighlights[%d]", index)))); } - static @NotNull Stream> testAttributesKeysForKnownTokenTypes() { + static @NotNull Stream> testAttributesKeysForKnownTokenTypes() { return Stream.concat( Stream.of(Named.of("TokenType.BAD_CHARACTER", TokenType.BAD_CHARACTER)), - ReflectionUtils.getPublicStaticFieldValues(NixTypes.class, NixTokenType.class)); + ReflectionUtils.getPublicStaticFieldValues(NixTypes.class, NixTokenType.class) + ).filter(not(named -> EMPTY_LENGTH_TOKENS.contains(named.getPayload()))); } } diff --git a/src/test/testData/ParsingTest/List.lexer.txt b/src/test/testData/ParsingTest/List.lexer.txt index 15071197..a7d0ddb5 100644 --- a/src/test/testData/ParsingTest/List.lexer.txt +++ b/src/test/testData/ParsingTest/List.lexer.txt @@ -2,7 +2,8 @@ WHITE_SPACE (' ') INT ('123') WHITE_SPACE (' ') -PATH ('./foo.nix') +PATH_SEGMENT ('./foo.nix') +PATH_END ('') WHITE_SPACE (' ') STRING_OPEN ('"') STR ('abc') diff --git a/src/test/testData/ParsingTest/List.txt b/src/test/testData/ParsingTest/List.txt index 72a95a7c..3cb82593 100644 --- a/src/test/testData/ParsingTest/List.txt +++ b/src/test/testData/ParsingTest/List.txt @@ -5,8 +5,8 @@ Nix File(0,36) NixLiteralImpl(LITERAL)(2,5) PsiElement(INT)('123')(2,5) PsiWhiteSpace(' ')(5,6) - NixLiteralImpl(LITERAL)(6,15) - PsiElement(PATH)('./foo.nix')(6,15) + NixPathImpl(PATH)(6,15) + PsiElement(PATH_SEGMENT)('./foo.nix')(6,15) PsiWhiteSpace(' ')(15,16) NixStdStringImpl(STD_STRING)(16,21) PsiElement(STRING_OPEN)('"')(16,17) @@ -33,4 +33,4 @@ Nix File(0,36) PsiWhiteSpace(' ')(32,33) PsiElement(})('}')(33,34) PsiWhiteSpace(' ')(34,35) - PsiElement(])(']')(35,36) + PsiElement(])(']')(35,36) \ No newline at end of file diff --git a/src/test/testData/ParsingTest/ListWithFunction.lexer.txt b/src/test/testData/ParsingTest/ListWithFunction.lexer.txt index 740eae95..50ed0dff 100644 --- a/src/test/testData/ParsingTest/ListWithFunction.lexer.txt +++ b/src/test/testData/ParsingTest/ListWithFunction.lexer.txt @@ -2,7 +2,8 @@ WHITE_SPACE (' ') INT ('123') WHITE_SPACE (' ') -PATH ('./foo.nix') +PATH_SEGMENT ('./foo.nix') +PATH_END ('') WHITE_SPACE (' ') STRING_OPEN ('"') STR ('abc') diff --git a/src/test/testData/ParsingTest/ListWithFunction.txt b/src/test/testData/ParsingTest/ListWithFunction.txt index c79684d9..572f4405 100644 --- a/src/test/testData/ParsingTest/ListWithFunction.txt +++ b/src/test/testData/ParsingTest/ListWithFunction.txt @@ -5,8 +5,8 @@ Nix File(0,38) NixLiteralImpl(LITERAL)(2,5) PsiElement(INT)('123')(2,5) PsiWhiteSpace(' ')(5,6) - NixLiteralImpl(LITERAL)(6,15) - PsiElement(PATH)('./foo.nix')(6,15) + NixPathImpl(PATH)(6,15) + PsiElement(PATH_SEGMENT)('./foo.nix')(6,15) PsiWhiteSpace(' ')(15,16) NixStdStringImpl(STD_STRING)(16,21) PsiElement(STRING_OPEN)('"')(16,17) @@ -37,4 +37,4 @@ Nix File(0,38) PsiElement(})('}')(34,35) PsiElement())(')')(35,36) PsiWhiteSpace(' ')(36,37) - PsiElement(])(']')(37,38) + PsiElement(])(']')(37,38) \ No newline at end of file diff --git a/src/test/testData/ParsingTest/Path.lexer.txt b/src/test/testData/ParsingTest/Path.lexer.txt index dd22b198..2ed6d351 100644 --- a/src/test/testData/ParsingTest/Path.lexer.txt +++ b/src/test/testData/ParsingTest/Path.lexer.txt @@ -1,11 +1,123 @@ [ ('[') WHITE_SPACE ('\n') -PATH ('/bin/sh') +PATH_SEGMENT ('/bin/sh') +PATH_END ('') WHITE_SPACE ('\n') -PATH ('./builder.sh') +PATH_SEGMENT ('./builder.sh') +PATH_END ('') WHITE_SPACE ('\n') -HPATH ('~/foo') +PATH_SEGMENT ('~/') +PATH_SEGMENT ('foo') +PATH_END ('') WHITE_SPACE ('\n') SPATH ('') WHITE_SPACE ('\n') -] (']') +SCOMMENT ('# antiquotations') +WHITE_SPACE ('\n') +PATH_SEGMENT ('/') +$ ('$') +{ ('{') +ID ('fileName') +} ('}') +PATH_END ('') +WHITE_SPACE ('\n') +PATH_SEGMENT ('/') +$ ('$') +{ ('{') +ID ('fileName') +} ('}') +PATH_SEGMENT ('/') +PATH_END ('') +WHITE_SPACE ('\n') +PATH_SEGMENT ('./') +$ ('$') +{ ('{') +ID ('foo') +} ('}') +PATH_SEGMENT ('-') +$ ('$') +{ ('{') +ID ('bar') +} ('}') +PATH_SEGMENT ('.nix') +PATH_END ('') +WHITE_SPACE ('\n') +PATH_SEGMENT ('./') +$ ('$') +{ ('{') +ID ('foo') +} ('}') +PATH_SEGMENT ('-') +$ ('$') +{ ('{') +ID ('bar') +} ('}') +PATH_SEGMENT ('/') +PATH_END ('') +WHITE_SPACE ('\n') +STRING_OPEN ('"') +$ ('$') +{ ('{') +PATH_SEGMENT ('./foo.txt') +PATH_END ('') +} ('}') +STRING_CLOSE ('"') +WHITE_SPACE ('\n\n') +SCOMMENT ('# whitespace must not be part of paths') +WHITE_SPACE ('\n') +PATH_SEGMENT ('prefix/dir/file.txt') +PATH_END ('') +WHITE_SPACE (' ') +PATH_SEGMENT ('next/path/element') +PATH_END ('') +WHITE_SPACE ('\n\n') +SCOMMENT ('# At least one slash (/) must appear before any interpolated expression for the result to be recognized as a path.') +WHITE_SPACE ('\n') +PATH_SEGMENT ('a/b') +PATH_END ('') +WHITE_SPACE ('\n\n') +SCOMMENT ('# https://nixos.org/manual/nix/stable/language/values.html#type-path') +WHITE_SPACE ('\n') +SCOMMENT ('# a.${foo}/b.${bar} is a syntactically valid division operation.') +WHITE_SPACE ('\n') +SCOMMENT ('# but the Nix parser seems to handle this differently:') +WHITE_SPACE ('\n') +SCOMMENT ('# https://github.com/NixOS/nix-idea/issues/59#issuecomment-1494786812') +WHITE_SPACE ('\n') +ID ('a') +. ('.') +$ ('$') +{ ('{') +ID ('foo') +} ('}') +PATH_SEGMENT ('/b.') +$ ('$') +{ ('{') +ID ('bar') +} ('}') +PATH_END ('') +WHITE_SPACE ('\n\n') +SCOMMENT ('# ./a.${foo}/b.${bar} is a path.') +WHITE_SPACE ('\n') +PATH_SEGMENT ('./a.') +$ ('$') +{ ('{') +ID ('foo') +} ('}') +PATH_SEGMENT ('/') +PATH_SEGMENT ('b.') +$ ('$') +{ ('{') +ID ('bar') +} ('}') +PATH_END ('') +WHITE_SPACE ('\n\n') +SCOMMENT ('# trailing slashes') +WHITE_SPACE ('\n') +PATH_SEGMENT ('/dir/subdir/') +PATH_END ('') +WHITE_SPACE ('\n') +PATH_SEGMENT ('./dir/subdir/') +PATH_END ('') +WHITE_SPACE ('\n') +] (']') \ No newline at end of file diff --git a/src/test/testData/ParsingTest/Path.nix b/src/test/testData/ParsingTest/Path.nix index 13d575cd..f7d444cf 100644 --- a/src/test/testData/ParsingTest/Path.nix +++ b/src/test/testData/ParsingTest/Path.nix @@ -3,4 +3,29 @@ ./builder.sh ~/foo +# antiquotations +/${fileName} +/${fileName}/ +./${foo}-${bar}.nix +./${foo}-${bar}/ +"${./foo.txt}" + +# whitespace must not be part of paths +prefix/dir/file.txt next/path/element + +# At least one slash (/) must appear before any interpolated expression for the result to be recognized as a path. +a/b + +# https://nixos.org/manual/nix/stable/language/values.html#type-path +# a.${foo}/b.${bar} is a syntactically valid division operation. +# but the Nix parser seems to handle this differently: +# https://github.com/NixOS/nix-idea/issues/59#issuecomment-1494786812 +a.${foo}/b.${bar} + +# ./a.${foo}/b.${bar} is a path. +./a.${foo}/b.${bar} + +# trailing slashes +/dir/subdir/ +./dir/subdir/ ] diff --git a/src/test/testData/ParsingTest/Path.txt b/src/test/testData/ParsingTest/Path.txt index 02797658..0803eba4 100644 --- a/src/test/testData/ParsingTest/Path.txt +++ b/src/test/testData/ParsingTest/Path.txt @@ -1,17 +1,152 @@ -Nix File(0,40) - NixListImpl(LIST)(0,40) +Nix File(0,717) + NixListImpl(LIST)(0,717) PsiElement([)('[')(0,1) PsiWhiteSpace('\n')(1,2) - NixLiteralImpl(LITERAL)(2,9) - PsiElement(PATH)('/bin/sh')(2,9) + NixPathImpl(PATH)(2,9) + PsiElement(PATH_SEGMENT)('/bin/sh')(2,9) PsiWhiteSpace('\n')(9,10) - NixLiteralImpl(LITERAL)(10,22) - PsiElement(PATH)('./builder.sh')(10,22) + NixPathImpl(PATH)(10,22) + PsiElement(PATH_SEGMENT)('./builder.sh')(10,22) PsiWhiteSpace('\n')(22,23) - NixLiteralImpl(LITERAL)(23,28) - PsiElement(HPATH)('~/foo')(23,28) + NixPathImpl(PATH)(23,28) + PsiElement(PATH_SEGMENT)('~/')(23,25) + PsiElement(PATH_SEGMENT)('foo')(25,28) PsiWhiteSpace('\n')(28,29) - NixLiteralImpl(LITERAL)(29,38) + NixPathImpl(PATH)(29,38) PsiElement(SPATH)('')(29,38) PsiWhiteSpace('\n')(38,39) - PsiElement(])(']')(39,40) + PsiComment(SCOMMENT)('# antiquotations')(39,55) + PsiWhiteSpace('\n')(55,56) + NixPathImpl(PATH)(56,68) + PsiElement(PATH_SEGMENT)('/')(56,57) + NixAntiquotationImpl(ANTIQUOTATION)(57,68) + PsiElement($)('$')(57,58) + PsiElement({)('{')(58,59) + NixIdentifierImpl(IDENTIFIER)(59,67) + PsiElement(ID)('fileName')(59,67) + PsiElement(})('}')(67,68) + PsiWhiteSpace('\n')(68,69) + NixPathImpl(PATH)(69,82) + PsiElement(PATH_SEGMENT)('/')(69,70) + NixAntiquotationImpl(ANTIQUOTATION)(70,81) + PsiElement($)('$')(70,71) + PsiElement({)('{')(71,72) + NixIdentifierImpl(IDENTIFIER)(72,80) + PsiElement(ID)('fileName')(72,80) + PsiElement(})('}')(80,81) + PsiElement(PATH_SEGMENT)('/')(81,82) + PsiWhiteSpace('\n')(82,83) + NixPathImpl(PATH)(83,102) + PsiElement(PATH_SEGMENT)('./')(83,85) + NixAntiquotationImpl(ANTIQUOTATION)(85,91) + PsiElement($)('$')(85,86) + PsiElement({)('{')(86,87) + NixIdentifierImpl(IDENTIFIER)(87,90) + PsiElement(ID)('foo')(87,90) + PsiElement(})('}')(90,91) + PsiElement(PATH_SEGMENT)('-')(91,92) + NixAntiquotationImpl(ANTIQUOTATION)(92,98) + PsiElement($)('$')(92,93) + PsiElement({)('{')(93,94) + NixIdentifierImpl(IDENTIFIER)(94,97) + PsiElement(ID)('bar')(94,97) + PsiElement(})('}')(97,98) + PsiElement(PATH_SEGMENT)('.nix')(98,102) + PsiWhiteSpace('\n')(102,103) + NixPathImpl(PATH)(103,119) + PsiElement(PATH_SEGMENT)('./')(103,105) + NixAntiquotationImpl(ANTIQUOTATION)(105,111) + PsiElement($)('$')(105,106) + PsiElement({)('{')(106,107) + NixIdentifierImpl(IDENTIFIER)(107,110) + PsiElement(ID)('foo')(107,110) + PsiElement(})('}')(110,111) + PsiElement(PATH_SEGMENT)('-')(111,112) + NixAntiquotationImpl(ANTIQUOTATION)(112,118) + PsiElement($)('$')(112,113) + PsiElement({)('{')(113,114) + NixIdentifierImpl(IDENTIFIER)(114,117) + PsiElement(ID)('bar')(114,117) + PsiElement(})('}')(117,118) + PsiElement(PATH_SEGMENT)('/')(118,119) + PsiWhiteSpace('\n')(119,120) + NixStdStringImpl(STD_STRING)(120,134) + PsiElement(STRING_OPEN)('"')(120,121) + NixAntiquotationImpl(ANTIQUOTATION)(121,133) + PsiElement($)('$')(121,122) + PsiElement({)('{')(122,123) + NixPathImpl(PATH)(123,132) + PsiElement(PATH_SEGMENT)('./foo.txt')(123,132) + PsiElement(})('}')(132,133) + PsiElement(STRING_CLOSE)('"')(133,134) + PsiWhiteSpace('\n\n')(134,136) + PsiComment(SCOMMENT)('# whitespace must not be part of paths')(136,174) + PsiWhiteSpace('\n')(174,175) + NixPathImpl(PATH)(175,194) + PsiElement(PATH_SEGMENT)('prefix/dir/file.txt')(175,194) + PsiWhiteSpace(' ')(194,195) + NixPathImpl(PATH)(195,212) + PsiElement(PATH_SEGMENT)('next/path/element')(195,212) + PsiWhiteSpace('\n\n')(212,214) + PsiComment(SCOMMENT)('# At least one slash (/) must appear before any interpolated expression for the result to be recognized as a path.')(214,328) + PsiWhiteSpace('\n')(328,329) + NixPathImpl(PATH)(329,332) + PsiElement(PATH_SEGMENT)('a/b')(329,332) + PsiWhiteSpace('\n\n')(332,334) + PsiComment(SCOMMENT)('# https://nixos.org/manual/nix/stable/language/values.html#type-path')(334,402) + PsiWhiteSpace('\n')(402,403) + PsiComment(SCOMMENT)('# a.${foo}/b.${bar} is a syntactically valid division operation.')(403,469) + PsiWhiteSpace('\n')(469,470) + PsiComment(SCOMMENT)('# but the Nix parser seems to handle this differently:')(470,524) + PsiWhiteSpace('\n')(524,525) + PsiComment(SCOMMENT)('# https://github.com/NixOS/nix-idea/issues/59#issuecomment-1494786812')(525,596) + PsiWhiteSpace('\n')(596,597) + NixExprSelectImpl(EXPR_SELECT)(597,605) + NixIdentifierImpl(IDENTIFIER)(597,598) + PsiElement(ID)('a')(597,598) + PsiElement(.)('.')(598,599) + NixAttrPathImpl(ATTR_PATH)(599,605) + NixStringAttrImpl(STRING_ATTR)(599,605) + NixAntiquotationImpl(ANTIQUOTATION)(599,605) + PsiElement($)('$')(599,600) + PsiElement({)('{')(600,601) + NixIdentifierImpl(IDENTIFIER)(601,604) + PsiElement(ID)('foo')(601,604) + PsiElement(})('}')(604,605) + NixPathImpl(PATH)(605,614) + PsiElement(PATH_SEGMENT)('/b.')(605,608) + NixAntiquotationImpl(ANTIQUOTATION)(608,614) + PsiElement($)('$')(608,609) + PsiElement({)('{')(609,610) + NixIdentifierImpl(IDENTIFIER)(610,613) + PsiElement(ID)('bar')(610,613) + PsiElement(})('}')(613,614) + PsiWhiteSpace('\n\n')(614,616) + PsiComment(SCOMMENT)('# ./a.${foo}/b.${bar} is a path.')(616,648) + PsiWhiteSpace('\n')(648,649) + NixPathImpl(PATH)(649,668) + PsiElement(PATH_SEGMENT)('./a.')(649,653) + NixAntiquotationImpl(ANTIQUOTATION)(653,659) + PsiElement($)('$')(653,654) + PsiElement({)('{')(654,655) + NixIdentifierImpl(IDENTIFIER)(655,658) + PsiElement(ID)('foo')(655,658) + PsiElement(})('}')(658,659) + PsiElement(PATH_SEGMENT)('/')(659,660) + PsiElement(PATH_SEGMENT)('b.')(660,662) + NixAntiquotationImpl(ANTIQUOTATION)(662,668) + PsiElement($)('$')(662,663) + PsiElement({)('{')(663,664) + NixIdentifierImpl(IDENTIFIER)(664,667) + PsiElement(ID)('bar')(664,667) + PsiElement(})('}')(667,668) + PsiWhiteSpace('\n\n')(668,670) + PsiComment(SCOMMENT)('# trailing slashes')(670,688) + PsiWhiteSpace('\n')(688,689) + NixPathImpl(PATH)(689,701) + PsiElement(PATH_SEGMENT)('/dir/subdir/')(689,701) + PsiWhiteSpace('\n')(701,702) + NixPathImpl(PATH)(702,715) + PsiElement(PATH_SEGMENT)('./dir/subdir/')(702,715) + PsiWhiteSpace('\n')(715,716) + PsiElement(])(']')(716,717) \ No newline at end of file diff --git a/src/test/testData/ParsingTest/Set.lexer.txt b/src/test/testData/ParsingTest/Set.lexer.txt index 765942b4..2a713c44 100644 --- a/src/test/testData/ParsingTest/Set.lexer.txt +++ b/src/test/testData/ParsingTest/Set.lexer.txt @@ -34,7 +34,8 @@ ID ('key') WHITE_SPACE (' ') = ('=') WHITE_SPACE (' ') -PATH ('./.') +PATH_SEGMENT ('./.') +PATH_END ('') ; (';') WHITE_SPACE ('\n ') ⁠inherit ('inherit') diff --git a/src/test/testData/ParsingTest/Set.txt b/src/test/testData/ParsingTest/Set.txt index abd2e491..187ced86 100644 --- a/src/test/testData/ParsingTest/Set.txt +++ b/src/test/testData/ParsingTest/Set.txt @@ -57,8 +57,8 @@ Nix File(0,119) PsiWhiteSpace(' ')(55,56) PsiElement(=)('=')(56,57) PsiWhiteSpace(' ')(57,58) - NixLiteralImpl(LITERAL)(58,61) - PsiElement(PATH)('./.')(58,61) + NixPathImpl(PATH)(58,61) + PsiElement(PATH_SEGMENT)('./.')(58,61) PsiElement(;)(';')(61,62) PsiWhiteSpace('\n ')(62,65) NixBindInheritImpl(BIND_INHERIT)(65,75)