From 9f0b5fdd023bf07764b091288894684637db0e64 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 24 Jul 2019 22:44:38 +0200 Subject: [PATCH] Add support for `textDocument/documentHighlight` for DTD Fixes #545 Signed-off-by: azerr --- .../eclipse/lsp4xml/dom/DTDElementDecl.java | 82 ++++++++++++- .../lsp4xml/extensions/dtd/DTDPlugin.java | 8 ++ .../DTDHighlightingParticipant.java | 98 +++++++++++++++ .../extensions/dtd/utils/DTDUtils.java | 112 +++++++++++++++++- 4 files changed, 295 insertions(+), 5 deletions(-) create mode 100644 org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/participants/DTDHighlightingParticipant.java diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java index 27244e8c48..54c27ba635 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java @@ -10,6 +10,8 @@ */ package org.eclipse.lsp4xml.dom; +import java.util.function.BiConsumer; + /** * DTD Element Declaration collector) { + DTDDeclParameter name = getNameParameter(); + if (name == null) { + return; + } + int start = name.getEnd(); + int end = getEnd(); + + String text = getOwnerDocument().getText(); + text.length(); + int wordStart = -1; + int wordEnd = -1; + // Loop for content after from offset to the * to offse and -1 if no word. @@ -164,9 +219,30 @@ private static boolean isValidChar(char c) { return Character.isJavaIdentifierPart(c) || c == '-'; } - @Override - public DTDDeclParameter getReferencedElementNameAt(int offset) { - return getParameterAt(offset); + /** + * Returns true if the word in the given text which starts at + * wordStart offset and ends at wordEnd matches the + * given searchWord + * + * @param searchWord the word to search + * @param text the text + * @param wordStart the word start offset + * @param wordEnd the word end offset + * @return true if the word in the given text which starts at + * wordStart offset and ends at wordEnd + * matches the given searchName + */ + private static boolean isMatchName(String searchWord, String text, int wordStart, int wordEnd) { + int length = wordEnd - wordStart; + if (searchWord.length() != length) { + return false; + } + for (int j = 0; j < length; j++) { + if ((searchWord.charAt(j) != text.charAt(wordStart + j))) { + return false; + } + } + return true; } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/DTDPlugin.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/DTDPlugin.java index fc95c94dd1..5416e7d20a 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/DTDPlugin.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/DTDPlugin.java @@ -15,8 +15,10 @@ import org.eclipse.lsp4xml.extensions.contentmodel.model.ContentModelProvider; import org.eclipse.lsp4xml.extensions.dtd.contentmodel.CMDTDContentModelProvider; import org.eclipse.lsp4xml.extensions.dtd.participants.DTDDefinitionParticipant; +import org.eclipse.lsp4xml.extensions.dtd.participants.DTDHighlightingParticipant; import org.eclipse.lsp4xml.extensions.dtd.participants.diagnostics.DTDDiagnosticsParticipant; import org.eclipse.lsp4xml.services.extensions.IDefinitionParticipant; +import org.eclipse.lsp4xml.services.extensions.IHighlightingParticipant; import org.eclipse.lsp4xml.services.extensions.IXMLExtension; import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; import org.eclipse.lsp4xml.services.extensions.diagnostics.IDiagnosticsParticipant; @@ -29,10 +31,12 @@ public class DTDPlugin implements IXMLExtension { private final IDiagnosticsParticipant diagnosticsParticipant; private final IDefinitionParticipant definitionParticipant; + private IHighlightingParticipant highlightingParticipant; public DTDPlugin() { diagnosticsParticipant = new DTDDiagnosticsParticipant(); definitionParticipant = new DTDDefinitionParticipant(); + highlightingParticipant = new DTDHighlightingParticipant(); } @Override @@ -50,6 +54,8 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) { registry.registerDiagnosticsParticipant(diagnosticsParticipant); // register definition participant registry.registerDefinitionParticipant(definitionParticipant); + // register highlighting participant + registry.registerHighlightingParticipant(highlightingParticipant); } @Override @@ -58,5 +64,7 @@ public void stop(XMLExtensionsRegistry registry) { registry.unregisterDiagnosticsParticipant(diagnosticsParticipant); // unregister definition participant registry.unregisterDefinitionParticipant(definitionParticipant); + // unregister highlighting participant + registry.unregisterHighlightingParticipant(highlightingParticipant); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/participants/DTDHighlightingParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/participants/DTDHighlightingParticipant.java new file mode 100644 index 0000000000..59cbfd87e0 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/participants/DTDHighlightingParticipant.java @@ -0,0 +1,98 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4xml.extensions.dtd.participants; + +import java.util.List; + +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentHighlightKind; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4xml.dom.DOMNode; +import org.eclipse.lsp4xml.dom.DTDAttlistDecl; +import org.eclipse.lsp4xml.dom.DTDDeclParameter; +import org.eclipse.lsp4xml.dom.DTDElementDecl; +import org.eclipse.lsp4xml.extensions.dtd.utils.DTDUtils; +import org.eclipse.lsp4xml.services.extensions.IHighlightingParticipant; +import org.eclipse.lsp4xml.utils.XMLPositionUtility; + +/** + * DTD highlight participant + * + * @author Angelo ZERR + * + */ + +public class DTDHighlightingParticipant implements IHighlightingParticipant { + + @Override + public void findDocumentHighlights(DOMNode node, Position position, int offset, List highlights, + CancelChecker cancelChecker) { + boolean findReferences = false; + DTDDeclParameter parameter = null; + DTDElementDecl elementDecl = null; + + if (node.isDTDElementDecl()) { + elementDecl = (DTDElementDecl) node; + if (elementDecl.isInNameParameter(offset)) { + // here cursor is in the name of here cursor is in the child element + // we must find only the here cusror is in the name of { + highlights + .add(new DocumentHighlight(XMLPositionUtility.createRange(origin), DocumentHighlightKind.Read)); + }, cancelChecker); + } else { + // case with + // - { + highlights.add( + new DocumentHighlight(XMLPositionUtility.createRange(targetName), DocumentHighlightKind.Write)); + }); + } + } + +} diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/utils/DTDUtils.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/utils/DTDUtils.java index eafaf92470..23dfeebb1c 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/utils/DTDUtils.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/utils/DTDUtils.java @@ -9,10 +9,16 @@ *******************************************************************************/ package org.eclipse.lsp4xml.extensions.dtd.utils; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Consumer; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4xml.dom.DOMDocumentType; import org.eclipse.lsp4xml.dom.DOMNode; +import org.eclipse.lsp4xml.dom.DTDAttlistDecl; +import org.eclipse.lsp4xml.dom.DTDDeclNode; import org.eclipse.lsp4xml.dom.DTDDeclParameter; import org.eclipse.lsp4xml.dom.DTDElementDecl; import org.w3c.dom.Node; @@ -31,8 +37,8 @@ public class DTDUtils { * node. * * @param originNameNode the origin name node ( collector, CancelChecker cancelChecker) { + // Collect all potential target DTD nodes (all targetNodes = getTargetNodes(targetNode); + if (targetNodes.isEmpty()) { + // None referenced nodes, stop the search of references + return; + } + + // Loop for each --> here target node is 'from' + // --> here origin node is 'note' + // --> here 'note' has a 'from' as child and it should be collected + DTDElementDecl originElement = (DTDElementDecl) origin; + originElement.collectParameters(targetElement.getNameParameter(), collector); + break; + case DOMNode.DTD_ATT_LIST_NODE: + String name = targetElement.getName(); + // check if the current here target node is 'note' + // here origin node is 'note' + // --> here getTargetNodes(DTDDeclNode referencedNode) { + List referencedNodes = new ArrayList<>(); + switch (referencedNode.getNodeType()) { + case DOMNode.DTD_ELEMENT_DECL_NODE: + addTargetNode(referencedNode, referencedNodes); + break; + case Node.DOCUMENT_TYPE_NODE: + DOMDocumentType docType = (DOMDocumentType) referencedNode; + if (docType.hasChildNodes()) { + // Loop for element referencedNodes) { + if (referencedNode.isDTDElementDecl()) { + // Add only