diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java index db3ef172f..b0a7b9ece 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.references; +import static org.springframework.ide.vscode.commons.yaml.ast.NodeUtil.asScalar; + import java.io.File; import java.net.URI; import java.nio.file.Files; @@ -34,10 +36,18 @@ import org.eclipse.lsp4j.Range; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.text.TextDocument; +import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; +import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST; +import org.springframework.ide.vscode.commons.yaml.ast.YamlParser; import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser; import org.springframework.ide.vscode.java.properties.parser.ParseResults; import org.springframework.ide.vscode.java.properties.parser.Parser; import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeId; +import org.yaml.snakeyaml.nodes.NodeTuple; /** * @author Martin Lippert @@ -137,8 +147,72 @@ public class ValuePropertyReferencesProvider { private List findReferencesInYMLFile(String filePath, String propertyKey) { List foundLocations = new ArrayList<>(); + + try { + String fileContent = FileUtils.readFileToString(new File(filePath)); + + Yaml yaml = new Yaml(); + YamlASTProvider parser = new YamlParser(yaml); + + URI docURI = Paths.get(filePath).toUri(); + TextDocument doc = new TextDocument(docURI.toString(), null); + doc.setText(fileContent); + YamlFileAST ast = parser.getAST(doc); + + List nodes = ast.getNodes(); + if (nodes != null && !nodes.isEmpty()) { + for (Node node : nodes) { + Node foundNode = findNode(node, "", propertyKey); + if (foundNode != null) { + + Position start = new Position(); + start.setLine(foundNode.getStartMark().getLine()); + start.setCharacter(foundNode.getStartMark().getColumn()); + + Position end = new Position(); + end.setLine(foundNode.getEndMark().getLine()); + end.setCharacter(foundNode.getEndMark().getColumn()); + + Range range = new Range(); + range.setStart(start); + range.setEnd(end); + + Location location = new Location(docURI.toString(), range); + foundLocations.add(location); + } + } + } + + } + catch (Exception e) { + e.printStackTrace(); + } + return foundLocations; } + + protected Node findNode(Node node, String prefix, String propertyKey) { + if (node.getNodeId().equals(NodeId.mapping)) { + for (NodeTuple entry : ((MappingNode)node).getValue()) { + Node keyNode = entry.getKeyNode(); + String key = asScalar(keyNode); + + String combinedKey = prefix.length() > 0 ? prefix + "." + key : key; + + if (combinedKey != null && combinedKey.equals(propertyKey)) { + return keyNode; + } + else { + Node recursive = findNode(entry.getValueNode(), combinedKey, propertyKey); + if (recursive != null) { + return recursive; + } + } + } + } + + return null; + } private List findReferencesInPropertiesFile(String filePath, String propertyKey) { List foundLocations = new ArrayList<>(); diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java index 5df4c925b..119675af5 100644 --- a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java @@ -30,7 +30,7 @@ import org.springframework.ide.vscode.project.harness.ProjectsHarness; public class PropertyReferenceFinderTest { @Test - public void testFindReferenceAtBeginning() throws Exception { + public void testFindReferenceAtBeginningPropFile() throws Exception { ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-case/").toURI()); @@ -49,6 +49,26 @@ public class PropertyReferenceFinderTest { assertEquals(13, location.getRange().getEnd().getCharacter()); } + @Test + public void testFindReferenceAtBeginningYMLFile() throws Exception { + ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); + + Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-yml/").toURI()); + CompletableFuture> resultFuture = provider.findReferencesFromPropertyFiles(root, "test.property"); + + assertNotNull(resultFuture); + List locations = resultFuture.get(); + assertEquals(1, locations.size()); + Location location = locations.get(0); + + URI docURI = Paths.get(root.toString(), "application.yml").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(3, location.getRange().getStart().getLine()); + assertEquals(2, location.getRange().getStart().getCharacter()); + assertEquals(3, location.getRange().getEnd().getLine()); + assertEquals(10, location.getRange().getEnd().getCharacter()); + } + @Test public void testFindReferenceWithinTheDocument() throws Exception { ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); @@ -105,4 +125,31 @@ public class PropertyReferenceFinderTest { assertEquals(10, location.getRange().getEnd().getCharacter()); } + @Test + public void testFindReferenceWithinMultipleMixedFiles() throws Exception { + ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); + + Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/mixed-multiple-files/").toURI()); + CompletableFuture> resultFuture = provider.findReferencesFromPropertyFiles(root, "appl1.prop"); + + assertNotNull(resultFuture); + List locations = resultFuture.get(); + assertEquals(2, locations.size()); + + Location location = locations.get(0); + URI docURI = Paths.get(root.toString(), "application-dev.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(1, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(1, location.getRange().getEnd().getLine()); + assertEquals(10, location.getRange().getEnd().getCharacter()); + + location = locations.get(1); + docURI = Paths.get(root.toString(), "application.yml").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(3, location.getRange().getStart().getLine()); + assertEquals(2, location.getRange().getStart().getCharacter()); + assertEquals(3, location.getRange().getEnd().getLine()); + assertEquals(6, location.getRange().getEnd().getCharacter()); + } } diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application-dev.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application-dev.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application-dev.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application.yml b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application.yml new file mode 100644 index 000000000..3e6894b1e --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/application.yml @@ -0,0 +1,4 @@ +something: + else: true +appl1: + prop: test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/no-props.yml b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/no-props.yml new file mode 100644 index 000000000..3e6894b1e --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/no-props.yml @@ -0,0 +1,4 @@ +something: + else: true +appl1: + prop: test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/non-app-props.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/non-app-props.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/mixed-multiple-files/non-app-props.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-yml/application.yml b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-yml/application.yml new file mode 100644 index 000000000..1f066e9b3 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-yml/application.yml @@ -0,0 +1,4 @@ +server: + port: 8080 +test: + property: mytestproperty