-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Model and completion for property expressions
In many MicroProfile implementations, `${other.property}` can be used to refer to the value of an already defined property when defining the value of another property. This PR modifies the property file model to allow representing these property expressions. It also adds completion for defined properties when completion is opened after typing `${` as a part of a property value. This PR was migrated from [quarkus-ls](redhat-developer/quarkus-ls#340). Signed-off-by: David Thompson <davthomp@redhat.com>
- Loading branch information
1 parent
7901de7
commit 8512c09
Showing
18 changed files
with
982 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
...rofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/model/PropertyGraph.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
|
||
package org.eclipse.lsp4mp.model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import com.google.common.graph.EndpointPair; | ||
import com.google.common.graph.Graph; | ||
import com.google.common.graph.GraphBuilder; | ||
import com.google.common.graph.MutableGraph; | ||
import com.google.common.graph.Traverser; | ||
|
||
import org.eclipse.lsp4mp.model.Node.NodeType; | ||
|
||
/** | ||
* Represents the graph of dependencies between properties defined in a | ||
* MicroProfile properties file. | ||
*/ | ||
public class PropertyGraph { | ||
|
||
private Graph<String> graph; | ||
|
||
/** | ||
* Build a PropertyGraph for the given properties model | ||
* | ||
* @param model the properties model to build the graph for | ||
*/ | ||
public PropertyGraph(PropertiesModel model) { | ||
MutableGraph<String> graph = GraphBuilder.directed().allowsSelfLoops(true).build(); | ||
// Add nodes | ||
for (Node modelChild : model.getChildren()) { | ||
if (modelChild.getNodeType() == NodeType.PROPERTY) { | ||
Property property = (Property) modelChild; | ||
String propertyName = property.getPropertyName(); | ||
if (!(propertyName.isEmpty() || graph.nodes().contains(propertyName))) { | ||
graph.addNode(propertyName); | ||
} | ||
} | ||
} | ||
// Add edges | ||
for (Node modelChild : model.getChildren()) { | ||
if (modelChild.getNodeType() == NodeType.PROPERTY) { | ||
Property property = (Property) modelChild; | ||
if (property.getValue() != null) { | ||
for (Node valueNode : property.getValue().getChildren()) { | ||
if (valueNode.getNodeType() == NodeType.PROPERTY_VALUE_EXPRESSION) { | ||
PropertyValueExpression propExpr = (PropertyValueExpression) valueNode; | ||
String propName = property.getPropertyName(); | ||
String refPropName = propExpr.getReferencedPropertyName(); | ||
if (graph.nodes().containsAll(Arrays.asList(propName, refPropName))) { | ||
graph.putEdge(propName, refPropName); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
this.graph = graph; | ||
} | ||
|
||
/** | ||
* Returns true if the given property is in the PropertyGraph, and false | ||
* otherwise | ||
* | ||
* @param property the property that is being checked | ||
* @return true if the given property is in the PropertyGraph, and false | ||
* otherwise | ||
*/ | ||
public boolean hasNode(String property) { | ||
return this.graph.nodes().contains(property); | ||
} | ||
|
||
/** | ||
* Gets a list of properties that do not depend on <code>property</code>. | ||
* | ||
* These are the properties that, if a dependency of <code>property</code> on | ||
* them were introduced, wouldn't introduce a circular dependency. | ||
* | ||
* @param property The property the find the independent properties of. | ||
* @return A list of all the properties whose value do not depend on this | ||
* property. | ||
*/ | ||
public List<String> getIndependentProperties(String property) { | ||
Graph<String> reversed = getReversed(); | ||
Set<String> reachable = new HashSet<>(); | ||
List<String> unreachable = new ArrayList<>(graph.nodes().size()); | ||
for (String reached : Traverser.forGraph(reversed).breadthFirst(property)) { | ||
reachable.add(reached); | ||
} | ||
for (String node : graph.nodes()) { | ||
if (!reachable.contains(node)) { | ||
unreachable.add(node); | ||
} | ||
} | ||
return unreachable; | ||
} | ||
|
||
/** | ||
* Get a copy of this property graph with all the edges reversed. | ||
* | ||
* @return a copy of this property graph with all the edges reversed. | ||
*/ | ||
private Graph<String> getReversed() { | ||
MutableGraph<String> mutableReversed = GraphBuilder.directed().allowsSelfLoops(true).build(); | ||
for (String node : graph.nodes()) { | ||
mutableReversed.addNode(node); | ||
} | ||
for (EndpointPair<String> edge : graph.edges()) { | ||
mutableReversed.putEdge(edge.nodeV(), edge.nodeU()); | ||
} | ||
return mutableReversed; | ||
} | ||
|
||
} |
73 changes: 73 additions & 0 deletions
73
...org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/model/PropertyValueExpression.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.lsp4mp.model; | ||
|
||
/** | ||
* Represents a portion of the property value that refers to the value of | ||
* another property. | ||
* | ||
* When properties file is processed, the reference is replaced with the value | ||
* of the other property. In the properties file, it has the form: | ||
* <code>${other.property.name}</code> | ||
*/ | ||
public class PropertyValueExpression extends Node { | ||
|
||
@Override | ||
public NodeType getNodeType() { | ||
return NodeType.PROPERTY_VALUE_EXPRESSION; | ||
} | ||
|
||
/** | ||
* Returns the text that this Node contains. | ||
* | ||
* Removes backslashes, and newlines. Doesn't not resolve the reference to | ||
* another property. | ||
*/ | ||
public String getValue() { | ||
String text = getText(true); | ||
return text != null ? text.trim() : null; | ||
} | ||
|
||
/** | ||
* Get the name of the referenced property, or null if the opening bracket is | ||
* missing in the property expression. | ||
* | ||
* Does not check if the referenced property exists. | ||
* | ||
* @return the name of the referenced property, or null if brackets were missing | ||
* in the property expression. | ||
*/ | ||
public String getReferencedPropertyName() { | ||
String value = getValue(); | ||
if (value.length() < 2 || !"${".equals(value.substring(0, 2))) { | ||
return null; | ||
} | ||
int end = value.indexOf("}"); | ||
end = end == -1 ? value.length() : end; | ||
return value.substring(2, end); | ||
} | ||
|
||
/** | ||
* Returns true if the last character in this node is a '}', and false | ||
* otherwise. | ||
* | ||
* @return true if the last character in this node is a '}', and false | ||
* otherwise. | ||
*/ | ||
public boolean isClosed() { | ||
String text = getText(); | ||
return text.charAt(text.length() - 1) == '}'; | ||
} | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
...ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/model/PropertyValueLiteral.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.lsp4mp.model; | ||
|
||
/** | ||
* Represents text in a property value that should be interpreted literally. | ||
*/ | ||
public class PropertyValueLiteral extends Node { | ||
|
||
@Override | ||
public NodeType getNodeType() { | ||
return NodeType.PROPERTY_VALUE_LITERAL; | ||
} | ||
|
||
/** | ||
* Returns the text this node contains and null otherwise. | ||
* | ||
* If this node covers more than one line, the backslashes and newlines are | ||
* removed. | ||
* | ||
* @return the text this node contains and null otherwise | ||
*/ | ||
public String getValue() { | ||
String text = getText(true); | ||
return text != null ? text.trim() : null; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.