下面列出了怎么用org.eclipse.lsp4j.LocationLink的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(
DefinitionParams params) {
return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> {
if (definitionLinkSupport) {
return Either.forRight(
getXMLLanguageService().findDefinition(xmlDocument, params.getPosition(), cancelChecker));
}
List<? extends Location> locations = getXMLLanguageService()
.findDefinition(xmlDocument, params.getPosition(), cancelChecker) //
.stream() //
.map(locationLink -> XMLPositionUtility.toLocation(locationLink)) //
.collect(Collectors.toList());
return Either.forLeft(locations);
});
}
@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> typeDefinition(
TypeDefinitionParams params) {
return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> {
if (typeDefinitionLinkSupport) {
return Either.forRight(
getXMLLanguageService().findTypeDefinition(xmlDocument, params.getPosition(), cancelChecker));
}
List<? extends Location> locations = getXMLLanguageService()
.findTypeDefinition(xmlDocument, params.getPosition(), cancelChecker) //
.stream() //
.map(locationLink -> XMLPositionUtility.toLocation(locationLink)) //
.collect(Collectors.toList());
return Either.forLeft(locations);
});
}
public List<? extends LocationLink> findDefinition(DOMDocument document, Position position,
CancelChecker cancelChecker) {
IDefinitionRequest request = null;
try {
request = new DefinitionRequest(document, position, extensionsRegistry);
} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Failed creating TypeDefinitionRequest", e);
return Collections.emptyList();
}
// Custom definition
List<LocationLink> locations = new ArrayList<>();
for (IDefinitionParticipant participant : extensionsRegistry.getDefinitionParticipants()) {
participant.findDefinition(request, locations, cancelChecker);
}
// Start end tag definition
findStartEndTagDefinition(request, locations);
return locations;
}
/**
* Find start end tag definition.
*
* @param request the definition request
* @param locations the locations
*/
private static void findStartEndTagDefinition(IDefinitionRequest request, List<LocationLink> locations) {
DOMNode node = request.getNode();
if (node != null && node.isElement()) {
// Node is a DOM element
DOMElement element = (DOMElement) node;
if (element.hasStartTag() && element.hasEndTag()) {
// The DOM element has end and start tag
DOMDocument document = element.getOwnerDocument();
Range startRange = XMLPositionUtility.selectStartTagName(element);
Range endRange = XMLPositionUtility.selectEndTagName(element);
int offset = request.getOffset();
if (element.isInStartTag(offset)) {
// Start tag was clicked, jump to the end tag
locations.add(new LocationLink(document.getDocumentURI(), endRange, endRange, startRange));
} else if (element.isInEndTag(offset)) {
// End tag was clicked, jump to the start tag
locations.add(new LocationLink(document.getDocumentURI(), startRange, startRange, endRange));
}
}
}
}
@Override
protected void doFindDefinition(IDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
DOMNode node = request.getNode();
int offset = request.getOffset();
// DTD definition is applicable only for <!ELEMENT and <!ATTLIST
if (!(node.isDTDElementDecl() || node.isDTDAttListDecl())) {
return;
}
// Get the parameter which defines the name which references an <!ELEMENT
// - <!ATTLIST elt -> we search the 'elt' in <!ELEMENT elt
// - <!ELEMENT elt (child1 -> we search the 'child1' in <!ELEMENT child1
DTDDeclParameter originName = ((DTDDeclNode) node).getReferencedElementNameAt(offset);
if (originName != null) {
DTDUtils.searchDTDTargetElementDecl(originName, true, targetElementName -> {
LocationLink location = XMLPositionUtility.createLocationLink((DOMRange) originName,
(DOMRange) targetElementName);
locations.add(location);
});
}
}
@Override
protected void doFindDefinition(IDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
DOMNode node = request.getNode();
if (!node.isText()) {
return;
}
// Definition is done in a text node, check if it's a entity reference
DOMDocument document = request.getXMLDocument();
int offset = request.getOffset();
EntityReferenceRange entityRange = XMLPositionUtility.selectEntityReference(offset, document);
if (entityRange != null) {
String entityName = entityRange.getName();
Range range = entityRange.getRange();
searchInLocalEntities(entityName, range, document, locations, cancelChecker);
searchInExternalEntities(entityName, range, document, locations, request, cancelChecker);
}
}
/**
* Search the given entity name in the local entities.
*
* @param document the DOM document.
* @param entityName the entity name.
* @param entityRange the entity range.
* @param locations the location links
* @param cancelChecker the cancel checker.
*/
private static void searchInLocalEntities(String entityName, Range entityRange, DOMDocument document,
List<LocationLink> locations, CancelChecker cancelChecker) {
DOMDocumentType docType = document.getDoctype();
if (docType == null) {
return;
}
cancelChecker.checkCanceled();
// Loop for entities declared in the DOCTYPE of the document
NamedNodeMap entities = docType.getEntities();
for (int i = 0; i < entities.getLength(); i++) {
cancelChecker.checkCanceled();
DTDEntityDecl entity = (DTDEntityDecl) entities.item(i);
fillEntityLocation(entity, entityName, entityRange, locations);
}
}
@Override
protected void doFindDefinition(IDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
// - xs:element/@type -> xs:complexType/@name
// - xs:extension/@base -> xs:complexType/@name
// - xs:element/@ref -> xs:complexType/@name
DOMNode node = request.getNode();
if (!node.isAttribute()) {
return;
}
DOMAttr attr = (DOMAttr) node;
BindingType bindingType = XSDUtils.getBindingType(attr);
if (bindingType != BindingType.NONE) {
XSDUtils.searchXSTargetAttributes(attr, bindingType, true, true, (targetNamespacePrefix, targetAttr) -> {
LocationLink location = XMLPositionUtility.createLocationLink(attr.getNodeAttrValue(),
targetAttr.getNodeAttrValue());
locations.add(location);
});
}
}
/**
* Returns the location of the local xs:element declared in the given XML Schema
* <code>targetSchema</code> which matches the given XML element
* <code>originElement</code> and null otherwise.
*
* @param originElement the XML element
* @param targetSchema the XML Schema
* @param enclosingType the enclosing type of the XS element declaration which
* matches the XML element
* @param grammar the Xerces grammar
* @return the location of the global xs:element declared in the given XML
* Schema <code>targetSchema</code> which matches the given XML element
* <code>originElement</code> and null otherwise.
*/
private static LocationLink findLocalXSElement(DOMElement originElement, DOMDocument targetSchema,
XSComplexTypeDefinition enclosingType, SchemaGrammar schemaGrammar) {
// In local xs:element case, xs:element is declared inside a complex type
// (enclosing type).
// Xerces stores in the SchemaGrammar the locator (offset) for each complex type
// (XSComplexTypeDecl)
// Here we get the offset of the local enclosing complex type xs:complexType.
// After that
// we just loop of children of local xs:complexType and return the
// location of
// xs:element/@name which matches the tag name of the origin XML element
// Get the location of the local xs:complexType
int complexTypeOffset = getComplexTypeOffset(enclosingType, schemaGrammar);
if (complexTypeOffset != -1) {
// location of xs:complexType is found, find the xs:element declared inside the
// xs:complexType
DOMNode node = targetSchema.findNodeAt(complexTypeOffset);
if (node != null && node.isElement() && node.hasChildNodes()) {
return findXSElement((DOMElement) originElement, node.getChildNodes(), true);
}
}
return null;
}
/**
* Returns the location of the xs:element declared in the given XML Schema
* <code>targetSchema</code> which matches the given XML element
* <code>originElement</code> and null otherwise.
*
* @param originElement the XML element
* @param children the children where xs:element must be searched
* @param inAnyLevel true if search must be done in any level and false
* otherwise.
* @return
*/
private static LocationLink findXSElement(DOMElement originElement, NodeList children, boolean inAnyLevel) {
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element elt = (Element) n;
LocationLink location = findXSElement(originElement, elt);
if (location != null) {
return location;
}
if (inAnyLevel && elt.hasChildNodes()) {
location = findXSElement(originElement, elt.getChildNodes(), inAnyLevel);
if (location != null) {
return location;
}
}
}
}
return null;
}
@Override
protected void doFindTypeDefinition(ITypeDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
ContentModelManager contentModelManager = request.getComponent(ContentModelManager.class);
DOMNode node = request.getNode();
if (node == null) {
return;
}
DOMElement element = null;
if (node.isElement()) {
element = (DOMElement) node;
} else if (node.isAttribute()) {
element = ((DOMAttr) node).getOwnerElement();
}
if (element != null) {
Collection<CMDocument> cmDocuments = contentModelManager.findCMDocument(element);
for (CMDocument cmDocument : cmDocuments) {
LocationLink location = cmDocument.findTypeLocation(node);
if (location != null) {
locations.add(location);
}
}
}
}
public static void testDefinitionFor(String value, String fileURI, LocationLink... expected)
throws BadLocationException {
int offset = value.indexOf('|');
value = value.substring(0, offset) + value.substring(offset + 1);
TextDocument document = new TextDocument(value, fileURI != null ? fileURI : "test://test/test.xml");
Position position = document.positionAt(offset);
XMLLanguageService xmlLanguageService = new XMLLanguageService();
ContentModelSettings settings = new ContentModelSettings();
settings.setUseCache(false);
xmlLanguageService.doSave(new SettingsSaveContext(settings));
DOMDocument xmlDocument = DOMParser.getInstance().parse(document,
xmlLanguageService.getResolverExtensionManager());
xmlLanguageService.setDocumentProvider((uri) -> xmlDocument);
List<? extends LocationLink> actual = xmlLanguageService.findDefinition(xmlDocument, position, () -> {
});
assertLocationLink(actual, expected);
}
@SuppressWarnings("squid:S1452")
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> getDefinitions(Position position) {
if (textDocumentItem.getUri().endsWith(".xml")) {
String camelComponentUri = parserXMLFileHelper.getCamelComponentUri(textDocumentItem, position);
if (camelComponentUri != null) {
CamelURIInstance camelURIInstance = parserXMLFileHelper.createCamelURIInstance(textDocumentItem, position, camelComponentUri);
if (camelURIInstance != null && "ref".equals(camelURIInstance.getComponentName())) {
Set<PathParamURIInstance> pathParams = camelURIInstance.getComponentAndPathUriElementInstance().getPathParams();
if(!pathParams.isEmpty()) {
String refId = pathParams.iterator().next().getValue();
return searchEndpointsWithId(refId);
}
}
}
}
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
/***/
@Test
public void testDefinition_04() throws Exception {
testWorkspaceManager.createTestProjectOnDisk(Collections.emptyMap());
startAndWaitForLspServer();
TextDocumentPositionParams textDocumentPositionParams = new TextDocumentPositionParams();
textDocumentPositionParams.setTextDocument(new TextDocumentIdentifier("n4scheme:/builtin_js.n4ts"));
// see position from test above
textDocumentPositionParams.setPosition(new Position(838, 15));
CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definitionsFuture = languageServer
.definition(textDocumentPositionParams);
Either<List<? extends Location>, List<? extends LocationLink>> definitions = definitionsFuture.get();
File root = getRoot();
String actualSignatureHelp = new StringLSP4J(root).toString4(definitions);
assertEquals("(n4scheme:/builtin_js.n4ts, [838:15 - 838:21])", actualSignatureHelp.trim());
}
@Override
protected void performTest(Project project, String moduleName, DefinitionTestConfiguration dtc)
throws InterruptedException, ExecutionException, URISyntaxException {
TextDocumentPositionParams textDocumentPositionParams = new TextDocumentPositionParams();
String completeFileUri = getFileURIFromModuleName(dtc.getFilePath()).toString();
textDocumentPositionParams.setTextDocument(new TextDocumentIdentifier(completeFileUri));
textDocumentPositionParams.setPosition(new Position(dtc.getLine(), dtc.getColumn()));
CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definitionsFuture = languageServer
.definition(textDocumentPositionParams);
Either<List<? extends Location>, List<? extends LocationLink>> definitions = definitionsFuture.get();
if (dtc.getAssertDefinitions() != null) {
dtc.getAssertDefinitions().apply(definitions.getLeft());
} else {
String actualSignatureHelp = getStringLSP4J().toString4(definitions);
assertEquals(dtc.getExpectedDefinitions().trim(), actualSignatureHelp.trim());
}
}
@Test
public void testDefinition() throws Exception {
URI fileURI = openFile("maven/salut4", "src/main/java/java/Foo.java");
TextDocumentIdentifier identifier = new TextDocumentIdentifier(fileURI.toString());
DefinitionParams params = new DefinitionParams(identifier, new Position(10, 22));
Either<List<? extends Location>, List<? extends LocationLink>> result = server.definition(params).join();
assertTrue(result.isLeft());
assertNotNull(result.getLeft());
assertEquals(1, result.getLeft().size());
String targetUri = result.getLeft().get(0).getUri();
URI targetURI = JDTUtils.toURI(targetUri);
assertNotNull(targetURI);
assertEquals("jdt", targetURI.getScheme());
assertTrue(targetURI.getPath().endsWith("PrintStream.class"));
assertEquals(JDTEnvironmentUtils.SYNTAX_SERVER_ID, targetURI.getFragment());
}
@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(
TextDocumentPositionParams params) {
URI uri = URI.create(params.getTextDocument().getUri());
recompileIfContextChanged(uri);
DefinitionProvider provider = new DefinitionProvider(astVisitor);
return provider.provideDefinition(params.getTextDocument(), params.getPosition());
}
@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> typeDefinition(
TextDocumentPositionParams params) {
URI uri = URI.create(params.getTextDocument().getUri());
recompileIfContextChanged(uri);
TypeDefinitionProvider provider = new TypeDefinitionProvider(astVisitor);
return provider.provideTypeDefinition(params.getTextDocument(), params.getPosition());
}
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> provideDefinition(
TextDocumentIdentifier textDocument, Position position) {
if (ast == null) {
//this shouldn't happen, but let's avoid an exception if something
//goes terribly wrong.
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
URI uri = URI.create(textDocument.getUri());
ASTNode offsetNode = ast.getNodeAtLineAndColumn(uri, position.getLine(), position.getCharacter());
if (offsetNode == null) {
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
ASTNode definitionNode = GroovyASTUtils.getDefinition(offsetNode, true, ast);
if (definitionNode == null || definitionNode.getLineNumber() == -1 || definitionNode.getColumnNumber() == -1) {
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
URI definitionURI = ast.getURI(definitionNode);
if (definitionURI == null) {
definitionURI = uri;
}
Location location = new Location(definitionURI.toString(),
GroovyLanguageServerUtils.astNodeToRange(definitionNode));
return CompletableFuture.completedFuture(Either.forLeft(Collections.singletonList(location)));
}
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> provideTypeDefinition(
TextDocumentIdentifier textDocument, Position position) {
if (ast == null) {
//this shouldn't happen, but let's avoid an exception if something
//goes terribly wrong.
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
URI uri = URI.create(textDocument.getUri());
ASTNode offsetNode = ast.getNodeAtLineAndColumn(uri, position.getLine(), position.getCharacter());
if (offsetNode == null) {
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
ASTNode definitionNode = GroovyASTUtils.getTypeDefinition(offsetNode, ast);
if (definitionNode == null || definitionNode.getLineNumber() == -1 || definitionNode.getColumnNumber() == -1) {
return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
}
URI definitionURI = ast.getURI(definitionNode);
if (definitionURI == null) {
definitionURI = uri;
}
Location location = new Location(definitionURI.toString(),
GroovyLanguageServerUtils.astNodeToRange(definitionNode));
return CompletableFuture.completedFuture(Either.forLeft(Collections.singletonList(location)));
}
/**
* Unify the definition result has a list of Location.
*
* @param definitions the definition result
* @return the list of locations
*/
private List<? extends Location> toLocation(Either<List<? extends Location>, List<? extends LocationLink>> definitions) {
if (definitions.isLeft()) {
return definitions.getLeft();
} else {
return definitions.getRight().stream().map(link -> new Location(link.getTargetUri(), link.getTargetRange())).collect(Collectors.toList());
}
}
/**
* Returns the location link for the given <code>origin</code> and
* <code>target</code> nodes.
*
* @param origin the origin node.
* @param target the target node.
* @return the location link for the given <code>origin</code> and
* <code>target</code> nodes.
*/
public static LocationLink createLocationLink(DOMRange origin, DOMRange target) {
Range originSelectionRange = null;
if (origin instanceof DOMElement) {
originSelectionRange = selectStartTagName((DOMElement) origin);
} else {
originSelectionRange = XMLPositionUtility.createRange(origin);
}
return createLocationLink(originSelectionRange, target);
}
@Override
public final void findDefinition(IDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
DOMDocument document = request.getXMLDocument();
if (!match(document)) {
return;
}
doFindDefinition(request, locations, cancelChecker);
}
@Override
public final void findTypeDefinition(ITypeDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
DOMDocument document = request.getXMLDocument();
if (!match(document)) {
return;
}
doFindTypeDefinition(request, locations, cancelChecker);
}
public List<? extends LocationLink> findTypeDefinition(DOMDocument document, Position position,
CancelChecker cancelChecker) {
ITypeDefinitionRequest request = null;
try {
request = new TypeDefinitionRequest(document, position, extensionsRegistry);
} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Failed creating TypeDefinitionRequest", e);
return Collections.emptyList();
}
List<LocationLink> locations = new ArrayList<>();
for (ITypeDefinitionParticipant participant : extensionsRegistry.getTypeDefinitionParticipants()) {
participant.findTypeDefinition(request, locations, cancelChecker);
}
return locations;
}
/**
* Search the given entity name in the external entities.
*
* @param document the DOM document.
* @param entityName the entity name.
* @param entityRange the entity range.
* @param locations the location links
* @param request the definition request.
* @param cancelChecker the cancel checker.
*/
private static void searchInExternalEntities(String entityName, Range entityRange, DOMDocument document,
List<LocationLink> locations, IDefinitionRequest request, CancelChecker cancelChecker) {
ContentModelManager contentModelManager = request.getComponent(ContentModelManager.class);
Collection<CMDocument> cmDocuments = contentModelManager.findCMDocument(document, null, false);
for (CMDocument cmDocument : cmDocuments) {
List<Entity> entities = cmDocument.getEntities();
for (Entity entity : entities) {
fillEntityLocation((DTDEntityDecl) entity, entityName, entityRange, locations);
}
}
}
private static void fillEntityLocation(DTDEntityDecl entity, String entityName, Range entityRange,
List<LocationLink> locations) {
if (entityName.equals(entity.getName())) {
TargetRange name = entity.getNameParameter();
locations.add(XMLPositionUtility.createLocationLink(entityRange, name));
}
}
private static LocationLink findXSElement(DOMElement originElement, Element elt) {
if (XSDUtils.isXSElement(elt)) {
if (originElement.getLocalName().equals(elt.getAttribute("name"))) {
DOMAttr targetAttr = (DOMAttr) elt.getAttributeNode("name");
LocationLink location = XMLPositionUtility.createLocationLink(originElement,
targetAttr.getNodeAttrValue());
return location;
}
}
return null;
}
private static LocationLink findLocalXSAttribute(DOMAttr originAttribute, DOMDocument targetSchema,
XSComplexTypeDefinition enclosingType, SchemaGrammar schemaGrammar) {
int complexTypeOffset = getComplexTypeOffset(enclosingType, schemaGrammar);
if (complexTypeOffset != -1) {
// location of xs:complexType is found, find the xs:attribute declared inside
// the
// xs:complexType
DOMNode node = targetSchema.findNodeAt(complexTypeOffset);
if (node != null && node.isElement() && node.hasChildNodes()) {
return findXSAttribute(originAttribute, node.getChildNodes(), true);
}
}
return null;
}
@Override
protected void doFindDefinition(IDefinitionRequest request, List<LocationLink> locations,
CancelChecker cancelChecker) {
DOMNode origin = request.getNode();
XMLReferencesManager.getInstance().collect(origin, target -> {
LocationLink location = XMLPositionUtility.createLocationLink(origin, target);
locations.add(location);
});
}