Deal better with anchors and references in outline
See: https://github.com/spring-projects/sts4/issues/483 Signed-off-by: Kris De Volder <kdevolder@pivotal.io>
This commit is contained in:
@@ -359,4 +359,8 @@ public class DocumentRegion implements CharSequence, IRegion {
|
||||
return charBefore.equals("\n"); //This should work on windows too because windows uses "\r\n" but that still ends with "\n".
|
||||
}
|
||||
|
||||
public boolean contains(DocumentRegion inner) {
|
||||
return start<=inner.start && inner.end <= end;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,9 @@ package org.springframework.ide.vscode.commons.yaml.path;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeMergeSupport;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
@@ -29,6 +31,8 @@ public class NodeCursor extends ASTCursor {
|
||||
|
||||
private final Node currentNode;
|
||||
|
||||
private NodeMergeSupport nodeMerger = new NodeMergeSupport(IProblemCollector.NULL);
|
||||
|
||||
public NodeCursor(Node node) {
|
||||
Assert.isNotNull(node);
|
||||
this.currentNode = node;
|
||||
@@ -41,7 +45,7 @@ public class NodeCursor extends ASTCursor {
|
||||
switch (s.getType()) {
|
||||
case KEY_AT_KEY: {
|
||||
String key = s.toPropString();
|
||||
MappingNode mappingNode = NodeUtil.asMapping(getNode());
|
||||
MappingNode mappingNode = asMapping(getNode());
|
||||
if (mappingNode!=null) {
|
||||
return mappingNode.getValue().stream()
|
||||
.filter((c) -> key.equals(NodeUtil.asScalar(c.getKeyNode())))
|
||||
@@ -51,7 +55,7 @@ public class NodeCursor extends ASTCursor {
|
||||
return Stream.empty();
|
||||
}
|
||||
case ANY_CHILD: {
|
||||
MappingNode mappingNode = NodeUtil.asMapping(getNode());
|
||||
MappingNode mappingNode = asMapping(getNode());
|
||||
if (mappingNode!=null) {
|
||||
return mappingNode.getValue().stream()
|
||||
.map((c) -> new NodeCursor(c.getValueNode()));
|
||||
@@ -72,7 +76,7 @@ public class NodeCursor extends ASTCursor {
|
||||
return Stream.empty();
|
||||
}
|
||||
case VAL_AT_KEY: {
|
||||
MappingNode mappingNode = NodeUtil.asMapping(getNode());
|
||||
MappingNode mappingNode = asMapping(getNode());
|
||||
if (mappingNode!=null) {
|
||||
String key = s.toPropString();
|
||||
return mappingNode.getValue().stream()
|
||||
@@ -87,6 +91,16 @@ public class NodeCursor extends ASTCursor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private MappingNode asMapping(Node node) {
|
||||
MappingNode mapping = NodeUtil.asMapping(node);
|
||||
if (mapping!=null) {
|
||||
nodeMerger.flattenMapping(mapping);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return currentNode;
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HierarchicalDocumentSymbolHandler;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
|
||||
@@ -76,9 +77,16 @@ public class TypeBasedYamlHierarchicalSymbolHandler implements HierarchicalDocum
|
||||
if (namePath!=null) {
|
||||
Node nameNode = namePath.traverseNode(node);
|
||||
if (nameNode!=null) {
|
||||
DocumentRegion nodeRegion = NodeUtil.region(doc, node);
|
||||
DocumentRegion nameRegion = NodeUtil.region(doc, nameNode);
|
||||
if (!nodeRegion.contains(nameRegion)) {
|
||||
//This violates the expectation that most clients have.
|
||||
//vscode, for example drops the entire symbols hierarchy as 'invalid' if this happens
|
||||
nodeRegion = nameRegion;
|
||||
}
|
||||
return new DocumentSymbol(NodeUtil.asScalar(nameNode), kind,
|
||||
NodeUtil.region(doc, node).asRange(),
|
||||
NodeUtil.region(doc, nameNode).asRange(),
|
||||
nodeRegion.asRange(),
|
||||
nameRegion.asRange(),
|
||||
detail
|
||||
);
|
||||
}
|
||||
@@ -151,7 +159,9 @@ public class TypeBasedYamlHierarchicalSymbolHandler implements HierarchicalDocum
|
||||
|
||||
@Override
|
||||
public List<? extends DocumentSymbol> handleHierarchic(DocumentSymbolParams params) {
|
||||
return outlineByUri.get(params.getTextDocument().getUri());
|
||||
List<DocumentSymbol> symbols = outlineByUri.get(params.getTextDocument().getUri());
|
||||
log.info("hierarchical symbols: {}", symbols);
|
||||
return symbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,10 +178,12 @@ public class TypeBasedYamlHierarchicalSymbolHandler implements HierarchicalDocum
|
||||
if (def!=null) {
|
||||
Item parent = findParent(path);
|
||||
DocumentSymbol sym = def.createSymbol(currentAst, node, type, path);
|
||||
if (parent!=null) {
|
||||
parent.addChild(sym);
|
||||
} else {
|
||||
rootSymbols.add(sym);
|
||||
if (sym!=null) {
|
||||
if (parent!=null) {
|
||||
parent.addChild(sym);
|
||||
} else {
|
||||
rootSymbols.add(sym);
|
||||
}
|
||||
}
|
||||
stack.push(new Item(path, sym));
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.junit.Assert;
|
||||
import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -991,12 +992,36 @@ public class Editor {
|
||||
symbolDump.append(s.getDetail());
|
||||
symbolDump.append("\n");
|
||||
assertEquals(s.getName(), getText(s.getSelectionRange()));
|
||||
|
||||
assertNestedRange("Invalid selection range for "+s.getName(), s.getRange(), s.getSelectionRange());
|
||||
List<DocumentSymbol> children = s.getChildren();
|
||||
if (children!=null) {
|
||||
dumpSymbols(children, indent+1, symbolDump);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNestedRange(String msg, Range outerRange, Range innerRange) {
|
||||
boolean startOk = compare(outerRange.getStart(), innerRange.getStart()) <= 0;
|
||||
boolean endOk = compare(outerRange.getEnd(), innerRange.getEnd()) >= 0;
|
||||
if (startOk && endOk) {
|
||||
//it's fine!
|
||||
} else {
|
||||
fail(msg + "\n" +
|
||||
"outer: '"+this.getText(outerRange)+"'\n" +
|
||||
"does not contain\n" +
|
||||
"inner: '"+this.getText(innerRange)+"'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static int compare(Position p1, Position p2) {
|
||||
if (p1.getLine()==p2.getLine()) {
|
||||
return p1.getCharacter() - p2.getCharacter();
|
||||
} else {
|
||||
return p1.getLine() - p2.getLine();
|
||||
}
|
||||
}
|
||||
|
||||
private List<? extends DocumentSymbol> getHierarchicalDocumentSymbols() throws Exception {
|
||||
return harness.getHierarchicalDocumentSymbols(this.doc);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.stream.Collectors;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.eclipse.lsp4j.DocumentSymbol;
|
||||
import org.eclipse.lsp4j.InsertTextFormat;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
@@ -240,6 +241,31 @@ public class ConcourseEditorTest {
|
||||
InputStream stream = ConcourseEditorTest.class.getClassLoader().getResourceAsStream(resourceName);
|
||||
return IOUtil.toString(stream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outlineWithAnchors() throws Exception {
|
||||
harness.enableHierarchicalDocumentSymbols(true);
|
||||
//See: https://github.com/spring-projects/sts4/issues/483
|
||||
Editor editor = harness.newEditor(
|
||||
"def: &stuff\n" +
|
||||
" name: git\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: \n" +
|
||||
"resources:\n" +
|
||||
"- <<: *stuff\n" +
|
||||
"- name: git2\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: git@github.com:kdvolder/7zip.git"
|
||||
);
|
||||
|
||||
editor.assertHierarchicalDocumentSymbols(
|
||||
"resources::Resources\n" +
|
||||
" git::Resource\n" +
|
||||
" git2::Resource\n"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reconcileStructuralProblems() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user