diff --git a/ide/languages.env/src/org/netbeans/modules/languages/env/EnvFileResolver.java b/ide/languages.env/src/org/netbeans/modules/languages/env/EnvFileResolver.java index ba9c66e09beb..0f4431bbec0a 100644 --- a/ide/languages.env/src/org/netbeans/modules/languages/env/EnvFileResolver.java +++ b/ide/languages.env/src/org/netbeans/modules/languages/env/EnvFileResolver.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.languages.env; +import java.util.Set; import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NonNull; import org.openide.awt.ActionID; @@ -92,9 +93,16 @@ @ServiceProvider(service = MIMEResolver.class) public class EnvFileResolver extends MIMEResolver { + public static final String ENV_EXT = "env"; //NOI18N + public static final String DOT_ENV = "." + ENV_EXT; //NOI18N public static final String MIME_TYPE = "text/x-env"; //NOI18N + /** + * extensions to exclude from mime association + */ + private static final Set EXCLUDED_EXTENSIONS = Set.of("lexer", "errors"); //NOI18N + public EnvFileResolver() { super(MIME_TYPE); } @@ -103,17 +111,17 @@ public EnvFileResolver() { @Override public String findMIMEType(@NonNull final FileObject fo) { final String nameWithExt = fo.getNameExt().toLowerCase(); + final String ext = fo.getExt(); - if (nameWithExt.endsWith("." + ENV_EXT)) { //NOI18N - return MIME_TYPE; + if (EXCLUDED_EXTENSIONS.contains(ext)) { + return null; } - //Some application might use .env.example name format - int envPartPosition = 2; - String[] nameParts = nameWithExt.split("\\."); //NOI18N - - //check for previous name part - if (nameParts.length >= envPartPosition && nameParts[nameParts.length - envPartPosition].equals(ENV_EXT)) { + if (ext.equals(ENV_EXT) + || nameWithExt.equals(DOT_ENV) + //env files naming usually used in JS, PHP, Python frameworks + //.env.dist, .env.local, .env.local.demo ... + || nameWithExt.startsWith(DOT_ENV + ".")) { //NOI18N return MIME_TYPE; } diff --git a/ide/languages.env/src/org/netbeans/modules/languages/env/grammar/antlr4/coloring/EnvAntlrColoringLexer.g4 b/ide/languages.env/src/org/netbeans/modules/languages/env/grammar/antlr4/coloring/EnvAntlrColoringLexer.g4 index 4dedabdf2817..7d8db21decda 100644 --- a/ide/languages.env/src/org/netbeans/modules/languages/env/grammar/antlr4/coloring/EnvAntlrColoringLexer.g4 +++ b/ide/languages.env/src/org/netbeans/modules/languages/env/grammar/antlr4/coloring/EnvAntlrColoringLexer.g4 @@ -76,7 +76,7 @@ fragment BackTickQuote ; fragment SQuoteLiteral - : SQuote (Esc [btnfr"'\\] | ~ ['\\])* SQuote + : SQuote ( Esc ~[\r\n] | ~[\\'\r\n])* SQuote ; fragment NewLine diff --git a/ide/languages.env/src/org/netbeans/modules/languages/env/project/EnvFileImpl.java b/ide/languages.env/src/org/netbeans/modules/languages/env/project/EnvFileImpl.java index 8c1c6dc16fbf..43f50cb20ca0 100644 --- a/ide/languages.env/src/org/netbeans/modules/languages/env/project/EnvFileImpl.java +++ b/ide/languages.env/src/org/netbeans/modules/languages/env/project/EnvFileImpl.java @@ -18,25 +18,36 @@ */ package org.netbeans.modules.languages.env.project; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import javax.swing.event.ChangeListener; import org.netbeans.api.project.Project; +import org.netbeans.modules.languages.env.EnvFileResolver; import org.netbeans.modules.web.common.spi.ImportantFilesImplementation; import org.netbeans.modules.web.common.spi.ImportantFilesSupport; import org.netbeans.spi.project.LookupProvider; import org.netbeans.spi.project.ProjectServiceProvider; +import org.openide.filesystems.FileObject; @ProjectServiceProvider(service = ImportantFilesImplementation.class, projectTypes = { @LookupProvider.Registration.ProjectType(id = "org-netbeans-modules-web-clientproject"), @LookupProvider.Registration.ProjectType(id = "org-netbeans-modules-php-project"), }) public class EnvFileImpl implements ImportantFilesImplementation { - + private final ImportantFilesSupport support; public EnvFileImpl(Project project) { assert project != null; - support = ImportantFilesSupport.create(project.getProjectDirectory(), ".env"); // NOI18N + List envFiles = new ArrayList<>(); + + for (FileObject file : project.getProjectDirectory().getChildren()) { + if (!file.isFolder() && (file.getMIMEType().equals(EnvFileResolver.MIME_TYPE))) { + envFiles.add(file.getNameExt()); + } + } + support = ImportantFilesSupport.create(project.getProjectDirectory(), envFiles.toArray(String[]::new)); } @Override diff --git a/ide/languages.env/test/unit/data/testfiles/lexer/.env b/ide/languages.env/test/unit/data/testfiles/lexer/.env new file mode 100644 index 000000000000..4f11d7e8acba --- /dev/null +++ b/ide/languages.env/test/unit/data/testfiles/lexer/.env @@ -0,0 +1 @@ +APP_NAME='my file' diff --git a/ide/languages.env/test/unit/data/testfiles/lexer/.env.lexer b/ide/languages.env/test/unit/data/testfiles/lexer/.env.lexer new file mode 100644 index 000000000000..813fad7b5ce9 --- /dev/null +++ b/ide/languages.env/test/unit/data/testfiles/lexer/.env.lexer @@ -0,0 +1,4 @@ +Token #0 KEY [APP_NAME] +Token #1 OPERATOR [=] +Token #2 STRING ['my file'] +Token #3 WS [\n] diff --git a/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env b/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env new file mode 100644 index 000000000000..2f34e7d6243e --- /dev/null +++ b/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env @@ -0,0 +1,4 @@ +VALUE1='app\Kernel' +VALUE2='my\file' +INVALID_STRING='my\\'file' +NEXT_VALUE= \ No newline at end of file diff --git a/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env.lexer b/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env.lexer new file mode 100644 index 000000000000..31f7183757e6 --- /dev/null +++ b/ide/languages.env/test/unit/data/testfiles/lexer/single_quoted_value.env.lexer @@ -0,0 +1,15 @@ +Token #0 KEY [VALUE1] +Token #1 OPERATOR [=] +Token #2 STRING ['app\Kernel'] +Token #3 WS [\n] +Token #4 KEY [VALUE2] +Token #5 OPERATOR [=] +Token #6 STRING ['my\file'] +Token #7 WS [\n] +Token #8 KEY [INVALID_STRING] +Token #9 OPERATOR [=] +Token #10 STRING ['my\\'] +Token #11 VALUE [file'] +Token #12 WS [\n] +Token #13 KEY [NEXT_VALUE] +Token #14 OPERATOR [=] diff --git a/ide/languages.env/test/unit/src/org/netbeans/modules/languages/env/lexer/EnvLexerTest.java b/ide/languages.env/test/unit/src/org/netbeans/modules/languages/env/lexer/EnvLexerTest.java index 1ed6036b5b8e..d9230b11782e 100644 --- a/ide/languages.env/test/unit/src/org/netbeans/modules/languages/env/lexer/EnvLexerTest.java +++ b/ide/languages.env/test/unit/src/org/netbeans/modules/languages/env/lexer/EnvLexerTest.java @@ -44,7 +44,15 @@ public void setUp() throws Exception { public void testLexer_01() throws Exception { checkLexer("testfiles/lexer/env01.env"); } + + public void testSingleQuotedValue() throws Exception { + checkLexer("testfiles/lexer/single_quoted_value.env"); + } + public void testSmokeLexerDotEnvFile() throws Exception { + checkLexer("testfiles/lexer/.env"); + } + private void checkLexer(final String filePath) throws Exception { String fileContent = Files.readString(new File(getDataDir(), filePath).toPath(), StandardCharsets.UTF_8); EnvLanguage langSettings = new EnvLanguage();