-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See redhat-developer/vscode-xml#395 Signed-off-by: azerr <azerr@redhat.com>
- Loading branch information
1 parent
bdfda9b
commit 769daea
Showing
16 changed files
with
503 additions
and
79 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
143 changes: 143 additions & 0 deletions
143
...in/java/org/eclipse/lemminx/extensions/contentmodel/commands/AssociateGrammarCommand.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,143 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2021 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 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.lemminx.extensions.contentmodel.commands; | ||
|
||
import static org.eclipse.lemminx.extensions.xsd.utils.XSDUtils.TARGET_NAMESPACE_ATTR; | ||
|
||
import java.net.URL; | ||
import java.nio.file.Path; | ||
|
||
import javax.xml.parsers.SAXParser; | ||
import javax.xml.parsers.SAXParserFactory; | ||
|
||
import org.eclipse.lemminx.dom.DOMDocument; | ||
import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.NoGrammarConstraintsCodeAction; | ||
import org.eclipse.lemminx.services.IXMLDocumentProvider; | ||
import org.eclipse.lemminx.services.extensions.commands.AbstractDOMDocumentCommandHandler; | ||
import org.eclipse.lemminx.services.extensions.commands.ArgumentsUtils; | ||
import org.eclipse.lemminx.settings.SharedSettings; | ||
import org.eclipse.lemminx.utils.FilesUtils; | ||
import org.eclipse.lemminx.utils.StringUtils; | ||
import org.eclipse.lsp4j.ExecuteCommandParams; | ||
import org.eclipse.lsp4j.jsonrpc.CancelChecker; | ||
import org.xml.sax.Attributes; | ||
import org.xml.sax.SAXException; | ||
import org.xml.sax.helpers.DefaultHandler; | ||
|
||
/** | ||
* Associate a grammar to a given XML command. | ||
* | ||
* @author Angelo ZERR | ||
* | ||
*/ | ||
public class AssociateGrammarCommand extends AbstractDOMDocumentCommandHandler { | ||
|
||
public static final String COMMAND_ID = "xml.associate.grammar.insert"; | ||
|
||
public AssociateGrammarCommand(IXMLDocumentProvider documentProvider) { | ||
super(documentProvider); | ||
} | ||
|
||
public enum GrammarBindingType { | ||
|
||
XSD("xsd"), // | ||
DTD("dtd"), // | ||
XML_MODEL("xml-model"); | ||
|
||
private String name; | ||
|
||
private GrammarBindingType(String name) { | ||
this.name = name != null ? name : name(); | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
} | ||
|
||
@Override | ||
protected Object executeCommand(DOMDocument document, ExecuteCommandParams params, SharedSettings sharedSettings, | ||
CancelChecker cancelChecker) throws Exception { | ||
String documentURI = document.getDocumentURI(); | ||
String fullPathGrammarURI = ArgumentsUtils.getArgAt(params, 1, String.class); | ||
String bindingType = ArgumentsUtils.getArgAt(params, 2, String.class); | ||
String grammarURI = getRelativeURI(fullPathGrammarURI, documentURI); | ||
|
||
if (GrammarBindingType.XSD.getName().equals(bindingType)) { | ||
// Check if XSD to bind declares a target namespace | ||
String targetNamespace = getTargetNamespace(fullPathGrammarURI); | ||
if (StringUtils.isEmpty(targetNamespace)) { | ||
// Insert inside <foo /> -> | ||
// xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance" | ||
// xsi:noNamespaceSchemaLocation=\"xsd/tag.xsd\" | ||
return NoGrammarConstraintsCodeAction.createXSINoNamespaceSchemaLocationEdit(grammarURI, document); | ||
} | ||
// Insert inside <foo /> -> | ||
// xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
// xsi:noNamespaceSchemaLocation="xsd/tag.xsd" | ||
return NoGrammarConstraintsCodeAction.createXSISchemaLocationEdit(grammarURI, targetNamespace, document); | ||
} else if (GrammarBindingType.DTD.getName().equals(bindingType)) { | ||
// Insert before <foo /> -> <!DOCTYPE foo SYSTEM "dtd/tag.dtd"> | ||
return NoGrammarConstraintsCodeAction.createDocTypeEdit(grammarURI, document, sharedSettings); | ||
} else if (GrammarBindingType.XML_MODEL.getName().equals(bindingType)) { | ||
// Insert before <foo /> -> <?xml-model href=\"dtd/tag.dtd\"?> | ||
return NoGrammarConstraintsCodeAction.createXmlModelEdit(grammarURI, document, sharedSettings); | ||
} | ||
return null; | ||
} | ||
|
||
private static String getRelativeURI(String fullPathGrammarURI, String documentURI) { | ||
try { | ||
Path grammarPath = FilesUtils.getPath(fullPathGrammarURI); | ||
Path documentPath = FilesUtils.getPath(documentURI); | ||
Path relativePath = documentPath.getParent().relativize(grammarPath); | ||
return relativePath.toString().replaceAll("[\\\\]", "/"); | ||
} catch (Exception e) { | ||
return fullPathGrammarURI; | ||
} | ||
} | ||
|
||
private static String getTargetNamespace(String xsdURI) { | ||
TargetNamespaceHandler handler = new TargetNamespaceHandler(); | ||
try { | ||
SAXParserFactory factory = SAXParserFactory.newInstance(); | ||
SAXParser saxParser = factory.newSAXParser(); | ||
saxParser.parse(new URL(xsdURI).openStream(), handler); | ||
} catch (Exception e) { | ||
|
||
} | ||
return handler.getTargetNamespace(); | ||
} | ||
|
||
/** | ||
* SAX handler which extract the targetNamespace attribute from the xs:schema | ||
* root tag element and null otherwise. | ||
* | ||
*/ | ||
private static class TargetNamespaceHandler extends DefaultHandler { | ||
|
||
private String targetNamespace; | ||
|
||
@Override | ||
public void startElement(String uri, String localName, String qName, Attributes attributes) | ||
throws SAXException { | ||
super.startElement(uri, localName, qName, attributes); | ||
this.targetNamespace = attributes.getValue(TARGET_NAMESPACE_ATTR); | ||
throw new SAXException(); | ||
} | ||
|
||
public String getTargetNamespace() { | ||
return targetNamespace; | ||
} | ||
} | ||
|
||
} |
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
74 changes: 74 additions & 0 deletions
74
...eclipse/lemminx/extensions/contentmodel/participants/ContentModelCodeLensParticipant.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,74 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2021 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 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
|
||
package org.eclipse.lemminx.extensions.contentmodel.participants; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import org.eclipse.lemminx.dom.DOMDocument; | ||
import org.eclipse.lemminx.dom.DOMElement; | ||
import org.eclipse.lemminx.extensions.contentmodel.commands.AssociateGrammarCommand; | ||
import org.eclipse.lemminx.extensions.contentmodel.commands.AssociateGrammarCommand.GrammarBindingType; | ||
import org.eclipse.lemminx.services.extensions.codelens.ICodeLensParticipant; | ||
import org.eclipse.lemminx.services.extensions.codelens.ICodeLensRequest; | ||
import org.eclipse.lemminx.utils.XMLPositionUtility; | ||
import org.eclipse.lsp4j.CodeLens; | ||
import org.eclipse.lsp4j.Command; | ||
import org.eclipse.lsp4j.Range; | ||
import org.eclipse.lsp4j.jsonrpc.CancelChecker; | ||
|
||
/** | ||
* When XML file is not associated to a grammar (XSD, DTD), this class generates | ||
* several CodeLenses on the root of the DOM Document: | ||
* | ||
* <ul> | ||
* <li>[Bind with XSD] : click on this Codelens open a folder dialog to select | ||
* the XSD to bind.</li> | ||
* <li>[Bind with DTD] : click on this Codelens open a folder dialog to select | ||
* the DTD to bind.</li> | ||
* <li>[Bind with xml-model] : click on this Codelens open a folder dialog to | ||
* select the XSD, DTD to bind.</li> | ||
* </ul> | ||
* | ||
* <p> | ||
* Once the LSP client select the DTD, XSD, it should call the | ||
* {@link AssociateGrammarCommand} to generate the proper syntax for binding. | ||
* </p> | ||
* | ||
*/ | ||
public class ContentModelCodeLensParticipant implements ICodeLensParticipant { | ||
|
||
private static final String COMMAND_ID = "xml.associate.grammar.selectFile"; | ||
|
||
@Override | ||
public void doCodeLens(ICodeLensRequest request, List<CodeLens> lenses, CancelChecker cancelChecker) { | ||
DOMDocument document = request.getDocument(); | ||
DOMElement documentElement = document.getDocumentElement(); | ||
if (documentElement == null || document.hasGrammar()) { | ||
return; | ||
} | ||
String documentURI = document.getDocumentURI(); | ||
Range range = XMLPositionUtility.selectRootStartTag(document); | ||
|
||
lenses.add(createAssociateLens(documentURI, "Bind with XSD", GrammarBindingType.XSD.getName(), range)); | ||
lenses.add(createAssociateLens(documentURI, "Bind with DTD", GrammarBindingType.DTD.getName(), range)); | ||
lenses.add( | ||
createAssociateLens(documentURI, "Bind with xml-model", GrammarBindingType.XML_MODEL.getName(), range)); | ||
} | ||
|
||
private static CodeLens createAssociateLens(String documentURI, String title, String bindingType, Range range) { | ||
Command command = new Command(title, COMMAND_ID, Arrays.asList(documentURI, bindingType)); | ||
return new CodeLens(range, command, 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.