diff --git a/collab.channel.chat.xml/manifest.mf b/collab.channel.chat.xml/manifest.mf --- a/collab.channel.chat.xml/manifest.mf +++ b/collab.channel.chat.xml/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.collab.channel.chat.xml/1 -OpenIDE-Module-Specification-Version: 1.3 +OpenIDE-Module-Specification-Version: 1.4 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/collab/channel/chat/xml/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/collab/channel/chat/xml/layer.xml AutoUpdate-Show-In-Client: false diff --git a/collab.channel.chat.xml/nbproject/project.xml b/collab.channel.chat.xml/nbproject/project.xml --- a/collab.channel.chat.xml/nbproject/project.xml +++ b/collab.channel.chat.xml/nbproject/project.xml @@ -63,7 +63,7 @@ org.netbeans.modules.xml.text 2 - 1.16 + 1.60 diff --git a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java b/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java --- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java +++ b/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java @@ -638,7 +638,10 @@ public void run() { List> seqs = TokenHierarchy.get(doc).embeddedTokenSequences(offset, true); TokenSequence seq; - + if (seqs.size() == 1) { + // get the mime path from the document/kit + return; + } if (seqs.isEmpty()) { seq = TokenHierarchy.get(doc).tokenSequence(); } else { diff --git a/editor.kit/manifest.mf b/editor.kit/manifest.mf --- a/editor.kit/manifest.mf +++ b/editor.kit/manifest.mf @@ -2,5 +2,5 @@ AutoUpdate-Show-In-Client: false OpenIDE-Module: org.netbeans.modules.editor.kit OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/kit/Bundle.properties -OpenIDE-Module-Specification-Version: 1.33 +OpenIDE-Module-Specification-Version: 1.34 diff --git a/editor.kit/nbproject/project.xml b/editor.kit/nbproject/project.xml --- a/editor.kit/nbproject/project.xml +++ b/editor.kit/nbproject/project.xml @@ -155,7 +155,7 @@ org.netbeans.modules.xml.text 2 - 1.16 + 1.60 diff --git a/editor.structure/nbproject/project.xml b/editor.structure/nbproject/project.xml --- a/editor.structure/nbproject/project.xml +++ b/editor.structure/nbproject/project.xml @@ -176,6 +176,7 @@ org.netbeans.modules.mobility.svgcore org.netbeans.modules.xml.text + org.netbeans.modules.xml.text.obsolete90 org.netbeans.modules.editor.structure.api org.netbeans.modules.editor.structure.formatting org.netbeans.modules.editor.structure.spi diff --git a/hibernate/nbproject/project.properties b/hibernate/nbproject/project.properties --- a/hibernate/nbproject/project.properties +++ b/hibernate/nbproject/project.properties @@ -40,11 +40,11 @@ build.compiler.deprecation=false javac.compilerargs=-Xlint -Xlint:-serial -javac.source=1.7 +javac.source=1.8 hibernate.test.dir=${nb_all}/contrib/hibernate/test -spec.version.base=1.34.0 +spec.version.base=1.35.0 test.unit.cp.extra=\ ${nb_all}/libs.junit4/external/junit-4.12.jar:\ diff --git a/hibernate/nbproject/project.xml b/hibernate/nbproject/project.xml --- a/hibernate/nbproject/project.xml +++ b/hibernate/nbproject/project.xml @@ -162,6 +162,14 @@ + org.netbeans.modules.editor.document + + + + 1.0 + + + org.netbeans.modules.editor.lib @@ -180,14 +188,6 @@ - org.netbeans.modules.editor.document - - - - 1.0 - - - org.netbeans.modules.hibernate4lib @@ -250,7 +250,7 @@ 1 1.62 - + org.netbeans.modules.java.source.base @@ -269,6 +269,15 @@ + org.netbeans.modules.lexer + + + + 2 + 1.64 + + + org.netbeans.modules.parsing.api @@ -366,6 +375,14 @@ + org.netbeans.modules.xml.lexer + + + + 1.30 + + + org.netbeans.modules.xml.multiview @@ -380,7 +397,7 @@ 2 - 1.16 + 1.60 @@ -448,14 +465,6 @@ - org.openide.util.ui - - - - 9.3 - - - org.openide.util @@ -472,6 +481,14 @@ + org.openide.util.ui + + + + 9.3 + + + org.openide.windows diff --git a/hibernate/src/org/netbeans/modules/hibernate/completion/CompletionContext.java b/hibernate/src/org/netbeans/modules/hibernate/completion/CompletionContext.java --- a/hibernate/src/org/netbeans/modules/hibernate/completion/CompletionContext.java +++ b/hibernate/src/org/netbeans/modules/hibernate/completion/CompletionContext.java @@ -47,19 +47,18 @@ import org.netbeans.modules.hibernate.editor.EditorContextFactory; import org.netbeans.modules.hibernate.editor.DocumentContext; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.openide.util.Exceptions; import org.w3c.dom.Node; import org.w3c.dom.Text; @@ -69,7 +68,7 @@ * @author Rohan Ranade (Rohan.Ranade@Sun.COM) */ public class CompletionContext { - private ArrayList existingAttributes; + private List existingAttributes = Collections.emptyList(); public static enum CompletionType { TAG, @@ -93,49 +92,60 @@ this.caretOffset = caretOffset; try { - this.support = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport(); + this.support = XMLSyntaxSupport.getSyntaxSupport(doc); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.support = new XMLSyntaxSupport(((BaseDocument)doc)); + this.support = XMLSyntaxSupport.createSyntaxSupport(doc); } this.documentContext = EditorContextFactory.getDocumentContext(doc, caretOffset); this.lastTypedChar = support.lastTypedChar(); - initContext(); + try { + initContext(); + } catch (BadLocationException ex) { + // ignore + } } - private void initContext() { - TokenItem token = documentContext.getCurrentToken(); + private void initContext() throws BadLocationException { + Token token = documentContext.getCurrentToken(); if(token == null) return; - boolean tokenBoundary = (token.getOffset() == caretOffset) - || ((token.getOffset() + token.getImage().length()) == caretOffset); + boolean tokenBoundary = (documentContext.getCurrentTokenOffset() == caretOffset) + || ((documentContext.getCurrentTokenOffset() + token.length()) == caretOffset); - int id = token.getTokenID().getNumericID(); + XMLTokenId id = token.id(); SyntaxElement element = documentContext.getCurrentElement(); + String chars = token.text().toString().trim(); + int tOffset = documentContext.getCurrentTokenOffset(); switch (id) { //user enters < character - case XMLDefaultTokenContext.TEXT_ID: - String chars = token.getImage().trim(); + case TEXT: + Token previousTokenItem = support.getPreviousToken(tOffset); + if (previousTokenItem == null) { + completionType = CompletionType.NONE; + break; + } + String text = previousTokenItem.text().toString().trim(); if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals("/>")) { // NOI18N + text.equals("/>")) { // NOI18N completionType = CompletionType.NONE; break; } if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.VALUE; break; } if (chars != null && !chars.startsWith("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.VALUE; typedChars = ""; break; } if (chars != null && !chars.equals("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.NONE; break; } @@ -146,54 +156,54 @@ break; //start tag of an element - case XMLDefaultTokenContext.TAG_ID: - if (element instanceof EndTag) { + case TAG: + String tagName = element.getNode().getNodeName(); + if (support.isEndTag(element)) { completionType = CompletionType.NONE; break; } - if (element instanceof EmptyTag) { + if (support.isEmptyTag(element)) { if (token != null && - token.getImage().trim().equals("/>")) { + chars.equals("/>")) { completionType = CompletionType.NONE; break; } - EmptyTag tag = (EmptyTag) element; if (element.getElementOffset() + 1 == this.caretOffset) { completionType = CompletionType.TAG; break; } if (caretOffset > element.getElementOffset() + 1 && - caretOffset <= element.getElementOffset() + 1 + tag.getTagName().length()) { + caretOffset <= element.getElementOffset() + 1 +tagName.length()) { completionType = CompletionType.TAG; - typedChars = tag.getTagName(); + typedChars = tagName; break; } completionType = CompletionType.ATTRIBUTE; break; } - if (element instanceof StartTag) { + if (support.isStartTag(element)) { if (token != null && - token.getImage().trim().equals(">")) { + chars.equals(">")) { completionType = CompletionType.NONE; break; } if (token != null && - token.getImage().trim().startsWith(" previous = support.getPreviousToken(tOffset); + typedChars = previous.text().toString().trim(); completionType = CompletionType.VALUE; break; } @@ -207,41 +217,40 @@ break; //user enters an attribute name - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: completionType = CompletionType.ATTRIBUTE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset());; + typedChars = chars.substring(0, caretOffset - tOffset); break; //some random character - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: //user enters = character, we should ignore all other operators - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: completionType = CompletionType.NONE; break; //user enters either ' or " - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: if(!tokenBoundary) { completionType = CompletionType.ATTRIBUTE_VALUE; - typedChars = token.getImage().substring(1, caretOffset - token.getOffset()); + typedChars = chars.substring(1, caretOffset - tOffset); } else { completionType = CompletionType.NONE; } break; //user enters white-space character - case XMLDefaultTokenContext.WS_ID: + case WS: completionType = CompletionType.NONE; - TokenItem prev = token.getPrevious(); - while (prev != null && - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID)) { - prev = prev.getPrevious(); + Token prev = support.skip(tOffset, false, XMLTokenId.WS); + if (prev == null) { + completionType = CompletionType.NONE; + break; } - - if(prev.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { - typedChars = prev.getImage(); + if(prev.id() == XMLTokenId.ARGUMENT) { + typedChars = prev.text().toString(); completionType = CompletionType.ATTRIBUTE; - } else if ((prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) || - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID)) { + } else if ((prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG)) { completionType = CompletionType.ATTRIBUTE; } break; @@ -274,28 +283,44 @@ public Node getTag() { SyntaxElement element = documentContext.getCurrentElement(); - return (element instanceof Tag) ? (Node) element : null; + return element.getType() == Node.ELEMENT_NODE ? element.getNode() : null; } - public TokenItem getCurrentToken() { + public Token getCurrentToken() { return documentContext.getCurrentToken(); } - public List getExistingAttributes() { - if(existingAttributes != null) - return existingAttributes; - existingAttributes = new ArrayList(); - TokenItem item = documentContext.getCurrentToken().getPrevious(); - while(item != null) { - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.TAG_ID) + public int getCurrentTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } + + private List getExistingAttributesLocked(TokenSequence ts) { + List existingAttributes = new ArrayList(); + while (ts.movePrevious()) { + Token item = ts.token(); + XMLTokenId tokenId = item.id(); + if (tokenId == XMLTokenId.TAG) { break; - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.ARGUMENT_ID) { - existingAttributes.add(item.getImage()); } - item = item.getPrevious(); + if (tokenId == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } } return existingAttributes; } + + public List getExistingAttributes() { + if (existingAttributes == null) { + try { + existingAttributes = (List)support.runWithSequence( + documentContext.getCurrentTokenOffset(), + this::getExistingAttributesLocked + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } + return existingAttributes; + } + } diff --git a/hibernate/src/org/netbeans/modules/hibernate/completion/Completor.java b/hibernate/src/org/netbeans/modules/hibernate/completion/Completor.java --- a/hibernate/src/org/netbeans/modules/hibernate/completion/Completor.java +++ b/hibernate/src/org/netbeans/modules/hibernate/completion/Completor.java @@ -118,7 +118,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -156,7 +156,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -184,9 +184,9 @@ } if (typedChars.contains(".") || typedChars.equals("")) { // Switch to normal completion - doNormalJavaCompletion(js, results, typedChars, context.getCurrentToken().getOffset() + 1); + doNormalJavaCompletion(js, results, typedChars, context.getCurrentTokenOffset() + 1); } else { // Switch to smart class path completion - doSmartJavaCompletion(js, results, typedChars, context.getCurrentToken().getOffset() + 1); + doSmartJavaCompletion(js, results, typedChars, context.getCurrentTokenOffset() + 1); } } catch (IOException ex) { Exceptions.printStackTrace(ex); @@ -325,7 +325,7 @@ Exceptions.printStackTrace(ex); } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } @@ -355,7 +355,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } @@ -402,7 +402,7 @@ results.add(item); } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } @@ -446,7 +446,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -475,7 +475,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } diff --git a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateCfgCompletionManager.java b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateCfgCompletionManager.java --- a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateCfgCompletionManager.java +++ b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateCfgCompletionManager.java @@ -49,15 +49,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.swing.text.BadLocationException; import org.hibernate.cfg.Environment; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.hibernate.cfg.HibernateCfgProperties; import org.netbeans.modules.hibernate.cfg.HibernateCfgXmlConstants; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; import org.openide.util.NbBundle; -import org.w3c.dom.Text; +import org.w3c.dom.Node; /** * This class figures out the completion items for various attributes @@ -179,8 +181,8 @@ return anchorOffset; String tagName = context.getTag().getNodeName(); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; Completor completor = locateCompletor(tagName, attribName); if (completor != null) { @@ -198,21 +200,23 @@ DocumentContext docContext = context.getDocumentContext(); SyntaxElement curElem = docContext.getCurrentElement(); SyntaxElement prevElem = docContext.getCurrentElement().getPrevious(); - Tag propTag = null; + TagElement propTag = null; // If current element is a start tag and its tag is // or the current element is text and its prev is a start tag, // then do the code completion - if ((curElem instanceof StartTag) && ((StartTag) curElem).getTagName().equalsIgnoreCase(HibernateCfgXmlConstants.PROPERTY_TAG)) { - propTag = (StartTag) curElem; - } else if ((curElem instanceof Text) && (prevElem instanceof StartTag) && - ((StartTag) prevElem).getTagName().equalsIgnoreCase(HibernateCfgXmlConstants.PROPERTY_TAG)) { - propTag = (StartTag) prevElem; + if (curElem.getType() == Node.ELEMENT_NODE && + ((TagElement)curElem).isStart() && HibernateCfgXmlConstants.PROPERTY_TAG.equalsIgnoreCase(curElem.getNode().getNodeName())) { + propTag = (TagElement) curElem; + } else if (curElem.getType() == Node.TEXT_NODE && + (prevElem.getType() == Node.ELEMENT_NODE && ((TagElement)prevElem).isStart() && + HibernateCfgXmlConstants.PROPERTY_TAG.equalsIgnoreCase(prevElem.getNode().getNodeName()))) { + propTag = (TagElement) prevElem; } else { return anchorOffset; } - String propName = HibernateEditorUtil.getHbPropertyName(propTag); + String propName = HibernateEditorUtil.getHbPropertyName(propTag.getNode()); int caretOffset = context.getCaretOffset(); String typedChars = context.getTypedPrefix(); @@ -231,8 +235,17 @@ valueItems.add(item); } } - - anchorOffset = context.getCurrentToken().getPrevious().getOffset() + 1; + try { + anchorOffset = context.getDocumentContext(). + runWithSequence((TokenSequence s) -> { + if (!s.movePrevious()) { + return -1; + } + return s.offset(); + }); + } catch (BadLocationException ex) { + anchorOffset = -1; + } } return anchorOffset; diff --git a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateMappingCompletionManager.java b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateMappingCompletionManager.java --- a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateMappingCompletionManager.java +++ b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateMappingCompletionManager.java @@ -47,9 +47,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.hibernate.mapping.HibernateMappingXmlConstants; -import org.netbeans.spi.editor.completion.CompletionResultSet; import org.openide.util.NbBundle; /** @@ -240,8 +240,8 @@ return anchorOffset; String tagName = context.getTag().getNodeName(); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; Completor completor = locateCompletor(tagName, attribName); if (completor != null) { diff --git a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateRevengCompletionManager.java b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateRevengCompletionManager.java --- a/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateRevengCompletionManager.java +++ b/hibernate/src/org/netbeans/modules/hibernate/completion/HibernateRevengCompletionManager.java @@ -47,7 +47,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.hibernate.reveng.HibernateRevengXmlConstants; import org.openide.util.NbBundle; @@ -160,8 +161,8 @@ return anchorOffset; String tagName = context.getTag().getNodeName(); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; Completor completor = locateCompletor(tagName, attribName); if (completor != null) { diff --git a/hibernate/src/org/netbeans/modules/hibernate/editor/ContextUtilities.java b/hibernate/src/org/netbeans/modules/hibernate/editor/ContextUtilities.java --- a/hibernate/src/org/netbeans/modules/hibernate/editor/ContextUtilities.java +++ b/hibernate/src/org/netbeans/modules/hibernate/editor/ContextUtilities.java @@ -44,13 +44,16 @@ package org.netbeans.modules.hibernate.editor; +import javax.swing.text.BadLocationException; import javax.xml.XMLConstants; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; + +import static org.netbeans.api.xml.lexer.XMLTokenId.*; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.w3c.dom.Node; /** * @@ -61,9 +64,9 @@ private ContextUtilities() { } - public static boolean isValueToken(TokenItem currentToken) { + public static boolean isValueToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) { + if (currentToken.id() == VALUE) { return true; } } @@ -71,9 +74,9 @@ return false; } - public static boolean isTagToken(TokenItem currentToken) { + public static boolean isTagToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) { + if (currentToken.id() == TAG) { return true; } } @@ -81,9 +84,9 @@ return false; } - public static boolean isAttributeToken(TokenItem currentToken) { + public static boolean isAttributeToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { + if (currentToken.id() == ARGUMENT) { return true; } } @@ -91,88 +94,44 @@ return false; } - public static TokenItem getAttributeToken(TokenItem currentToken) { - if(currentToken == null ) - return null; - - if(isValueToken(currentToken)) { - TokenItem equalsToken = currentToken.getPrevious(); - if(equalsToken == null) - return null; - - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; - } - - return null; - } - - public static Tag getCurrentTagElement(DocumentContext context) { - SyntaxElement element = context.getCurrentElement(); - if(element instanceof StartTag) { - return (StartTag) element; - } else if(element instanceof EmptyTag) { - return (EmptyTag) element; - } - - return null; - } - - public static TokenItem getAttributeToken(DocumentContext context) { + public static Token getAttributeToken(DocumentContext context) { if(context.getCurrentToken() == null ) return null; - - if(isValueToken(context.getCurrentToken())) { - TokenItem equalsToken = context.getCurrentToken().getPrevious(); - if(equalsToken == null) - return null; - - //getTokenId() should not return null by JavaDoc. But in reality, it does reutrn null sometimes - // see issue 67661 - if(equalsToken.getTokenID() == null) { - return null; - } - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; + try { + return context.>runWithSequence((TokenSequence ts) -> { + if(!isValueToken(context.getCurrentToken())) { + return null; + } + Token equalsToken = null; + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == OPERATOR) { + equalsToken = t; + break; + } + } + if(equalsToken == null) { + return null; + } + Token argumentToken = null; + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == ARGUMENT) { + argumentToken = t; + break; + } + } + return argumentToken; + }); + } catch (BadLocationException ex) { } - return null; } public static String getAttributeTokenImage(DocumentContext context) { - TokenItem tok = getAttributeToken(context); + Token tok = getAttributeToken(context); if(tok != null) { - return tok.getImage(); + return tok.text().toString(); } return null; @@ -221,11 +180,12 @@ return nodeName.substring(0, colonIndex); } - public static StartTag getRoot(SyntaxElement se) { - StartTag root = null; + public static SyntaxElement getRoot(SyntaxElement se) { + SyntaxElement root = null; while( se != null) { - if(se instanceof StartTag) { - root = (StartTag)se; + if(se.getType() == Node.ELEMENT_NODE && + ((TagElement)se).isStart()) { + root = se; } se = se.getPrevious(); } diff --git a/hibernate/src/org/netbeans/modules/hibernate/editor/DocumentContext.java b/hibernate/src/org/netbeans/modules/hibernate/editor/DocumentContext.java --- a/hibernate/src/org/netbeans/modules/hibernate/editor/DocumentContext.java +++ b/hibernate/src/org/netbeans/modules/hibernate/editor/DocumentContext.java @@ -44,25 +44,17 @@ package org.netbeans.modules.hibernate.editor; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map.Entry; -import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Attr; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -83,9 +75,10 @@ private XMLSyntaxSupport syntaxSupport; private int caretOffset = -1; private SyntaxElement element; - private TokenItem token; + private Token token; + private int tokenOffset; private boolean valid = false; - private StartTag docRoot; + private SyntaxElement docRoot; private String defaultNamespace; private HashMap declaredNamespaces = new HashMap(); @@ -95,10 +88,10 @@ DocumentContext(Document document) { this.document = document; try { - this.syntaxSupport = (XMLSyntaxSupport) ((BaseDocument)document).getSyntaxSupport(); + this.syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.syntaxSupport = new XMLSyntaxSupport(((BaseDocument)document)); + this.syntaxSupport = XMLSyntaxSupport.createSyntaxSupport(document); } } @@ -108,13 +101,19 @@ } private void initialize() { - valid = true; declaredNamespaces.clear(); + if (syntaxSupport == null) { + valid = false; + return; + } try { element = syntaxSupport.getElementChain(caretOffset); - token = syntaxSupport.getTokenChain(caretOffset, Math.min(document.getLength(), caretOffset+1)); + int[] off = new int[2]; + token = syntaxSupport.getTokenAtPosition(caretOffset, off); + tokenOffset = off[0]; this.docRoot = ContextUtilities.getRoot(element); populateNamespaces(); + valid = true; } catch (BadLocationException ex) { // No context support available in this case valid = false; @@ -125,6 +124,7 @@ return this.valid; } + /* public int getCurrentTokenId() { if (isValid()) { return token.getTokenID().getNumericID(); @@ -132,8 +132,9 @@ return -1; } } + */ - public TokenItem getCurrentToken() { + public Token getCurrentToken() { if (isValid()) { return token; } else { @@ -143,64 +144,19 @@ public String getCurrentTokenImage() { if (isValid()) { - return token.getImage(); + return token.text().toString(); } else { return null; } } + + public int getCurrentTokenOffset() { + return tokenOffset; + } public SyntaxElement getCurrentElement() { return this.element; } - - public List getPathFromRoot() { - if (isValid()) { - SyntaxElement elementRef = this.element; - Stack stack = new Stack(); - - while (elementRef != null) { - if ((elementRef instanceof EndTag) || - (elementRef instanceof EmptyTag && stack.isEmpty()) || - (elementRef instanceof StartTag && stack.isEmpty())) { - stack.push(elementRef); - elementRef = elementRef.getPrevious(); - continue; - } - if (elementRef instanceof StartTag) { - StartTag start = (StartTag) elementRef; - if (stack.peek() instanceof EndTag) { - EndTag end = (EndTag) stack.peek(); - if (end.getTagName().equals(start.getTagName())) { - stack.pop(); - } - } else { - SyntaxElement e = (SyntaxElement) stack.peek(); - String tagAtTop = (e instanceof StartTag) ? ((StartTag) e).getTagName() : ((EmptyTag) e).getTagName(); - stack.push(elementRef); - } - } - elementRef = elementRef.getPrevious(); - } - - return createPath(stack); - } - - return Collections.emptyList(); - } - - private List createPath(Stack stack) { - ArrayList pathList = new ArrayList(); - while (!stack.isEmpty()) { - SyntaxElement top = stack.pop(); - String tagName = (top instanceof StartTag) ? ((StartTag) top).getTagName() : ((EmptyTag) top).getTagName(); - if (tagName != null) { - pathList.add(tagName); - } - } - - return Collections.unmodifiableList(pathList); - } - public Document getDocument() { return this.document; } @@ -223,7 +179,7 @@ return declaredNamespaces.values(); } - public StartTag getDocRoot() { + public SyntaxElement getDocRoot() { return docRoot; } @@ -234,7 +190,7 @@ private void populateNamespaces() { // Find the a start or empty tag just before the current syntax element. SyntaxElement element = this.element; - while (element != null && !(element instanceof StartTag) && !(element instanceof EmptyTag)) { + while (element != null && !syntaxSupport.isStartTag(element) && !syntaxSupport.isEmptyTag(element)) { element = element.getPrevious(); } if (element == null) { @@ -244,9 +200,9 @@ // To find all namespace declarations active at the caret offset, we // need to look at xmlns attributes of the current element and its ancestors. Node node = (Node)element; - while (node != null) { - if (node instanceof StartTag || node instanceof EmptyTag) { - NamedNodeMap attributes = ((Tag)node).getAttributes(); + while (node != null && element != null) { + if (syntaxSupport.isStartTag(element) || syntaxSupport.isEmptyTag(element)) { + NamedNodeMap attributes = node.getAttributes(); for (int index = 0; index < attributes.getLength(); index++) { Attr attr = (Attr) attributes.item(index); String attrName = attr.getName(); @@ -265,6 +221,7 @@ } } node = node.getParentNode(); + element = syntaxSupport.getSyntaxElement(node); } } @@ -297,4 +254,8 @@ hash = 61 * hash + (this.document != null ? this.document.hashCode() : 0); return hash; } + + public T runWithSequence(XMLSyntaxSupport.SequenceCallable callable) throws BadLocationException { + return syntaxSupport.runWithSequence(caretOffset, callable); + } } diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateCfgHyperlinkProvider.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateCfgHyperlinkProvider.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateCfgHyperlinkProvider.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateCfgHyperlinkProvider.java @@ -50,7 +50,7 @@ import org.netbeans.editor.BaseDocument; import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider; import org.netbeans.modules.hibernate.cfg.HibernateCfgXmlConstants; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; /** * Provides hyperlinking functionality for HibernateConfiguration files @@ -86,12 +86,7 @@ } public boolean isHyperlinkPoint(Document document, int offset) { - if (!(document instanceof BaseDocument)) { - return false; - } - - BaseDocument doc = (BaseDocument) document; - if (!(doc.getSyntaxSupport() instanceof XMLSyntaxSupport)) { + if (XMLSyntaxSupport.getSyntaxSupport(document) == null) { return false; } diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateMappingHyperlinkProvider.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateMappingHyperlinkProvider.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateMappingHyperlinkProvider.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HibernateMappingHyperlinkProvider.java @@ -50,7 +50,7 @@ import org.netbeans.editor.BaseDocument; import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider; import org.netbeans.modules.hibernate.mapping.HibernateMappingXmlConstants; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; /** * Provides hyperlinking functionality for Hibernate mapping files @@ -112,12 +112,7 @@ } public boolean isHyperlinkPoint(Document document, int offset) { - if (!(document instanceof BaseDocument)) { - return false; - } - - BaseDocument doc = (BaseDocument) document; - if (!(doc.getSyntaxSupport() instanceof XMLSyntaxSupport)) { + if (XMLSyntaxSupport.getSyntaxSupport(document) == null) { return false; } diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkEnv.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkEnv.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkEnv.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkEnv.java @@ -44,14 +44,15 @@ package org.netbeans.modules.hibernate.hyperlink; import javax.swing.text.Document; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.modules.hibernate.editor.ContextUtilities; import org.netbeans.modules.hibernate.editor.DocumentContext; import org.netbeans.modules.hibernate.editor.EditorContextFactory; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; import org.openide.filesystems.FileObject; +import org.w3c.dom.Node; /** * @@ -64,7 +65,7 @@ private String attribName; private String valueString; private int offset; - private TokenItem token; + private Token token; private DocumentContext documentContext; public static enum Type { @@ -99,13 +100,13 @@ currentTag = documentContext.getCurrentElement(); attribName = ContextUtilities.getAttributeTokenImage(documentContext); token = documentContext.getCurrentToken(); - valueString = token.getImage(); + valueString = token.text().toString(); valueString = valueString.substring(1, valueString.length() - 1); // Strip quotes } else if (ContextUtilities.isAttributeToken(documentContext.getCurrentToken())) { type = Type.ATTRIB; currentTag = documentContext.getCurrentElement(); token = documentContext.getCurrentToken(); - attribName = token.getImage(); + attribName = token.text().toString(); } } } @@ -114,8 +115,12 @@ return attribName; } - public Tag getCurrentTag() { - return currentTag instanceof Tag ? (Tag) currentTag : null; + public SyntaxElement getCurrentTag() { + if (currentTag.getType() == Node.ELEMENT_NODE) { + return currentTag; + } else { + return null; + } } public Document getDocument() { @@ -123,7 +128,7 @@ } public String getTagName() { - return getCurrentTag() != null ? getCurrentTag().getTagName() : null; + return getCurrentTag() != null ? getCurrentTag().getNode().getNodeName(): null; } public String getValueString() { @@ -134,9 +139,13 @@ return type; } - public TokenItem getToken() { + public Token getToken() { return token; } + + public int getTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } public int getOffset() { return offset; diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkProcessor.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkProcessor.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkProcessor.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/HyperlinkProcessor.java @@ -44,7 +44,8 @@ package org.netbeans.modules.hibernate.hyperlink; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; /** * @@ -54,7 +55,7 @@ public abstract void process(HyperlinkEnv env); public int[] getSpan(HyperlinkEnv env) { - TokenItem item = env.getToken(); - return new int[] { item.getOffset() + 1, item.getOffset() + item.getImage().length() - 1 }; + Token item = env.getToken(); + return new int[] { env.getTokenOffset() + 1, env.getTokenOffset() + item.text().length() - 1 }; } } diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/JavaClassHyperlinkProcessor.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/JavaClassHyperlinkProcessor.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/JavaClassHyperlinkProcessor.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/JavaClassHyperlinkProcessor.java @@ -45,6 +45,7 @@ import org.netbeans.modules.hibernate.editor.HibernateEditorUtil; import org.netbeans.modules.hibernate.mapping.HibernateMappingXmlConstants; +import org.w3c.dom.Node; /** * @@ -58,7 +59,9 @@ @Override public void process(HyperlinkEnv env) { String className = env.getValueString(); - String pack = env.getDocumentContext().getDocRoot().getAttribute(HibernateMappingXmlConstants.PACKAGE_ATTRIB);//NOI18N + Node n = env.getDocumentContext().getDocRoot().getNode().getAttributes(). + getNamedItem(HibernateMappingXmlConstants.PACKAGE_ATTRIB);//NOI18N + String pack = n == null ? null : n.getNodeValue(); if(pack!=null && pack.length()>0){ if(!className.contains(".")){ className = pack + "." +className; diff --git a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/PropertyHyperlinkProcessor.java b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/PropertyHyperlinkProcessor.java --- a/hibernate/src/org/netbeans/modules/hibernate/hyperlink/PropertyHyperlinkProcessor.java +++ b/hibernate/src/org/netbeans/modules/hibernate/hyperlink/PropertyHyperlinkProcessor.java @@ -55,6 +55,7 @@ import org.netbeans.modules.hibernate.editor.HibernateEditorUtil; import org.netbeans.modules.hibernate.mapping.HibernateMappingXmlConstants; import org.openide.util.Exceptions; +import org.w3c.dom.Node; /** * @@ -68,11 +69,13 @@ @Override public void process(HyperlinkEnv env) { try { - String className0 = HibernateEditorUtil.getClassName(env.getCurrentTag()); + String className0 = HibernateEditorUtil.getClassName(env.getCurrentTag().getNode()); if (className0 == null) { return; } - String pack = env.getDocumentContext().getDocRoot().getAttribute(HibernateMappingXmlConstants.PACKAGE_ATTRIB);//NOI18N + Node n = env.getDocumentContext().getDocRoot().getNode().getAttributes(). + getNamedItem(HibernateMappingXmlConstants.PACKAGE_ATTRIB);//NOI18N + String pack = n == null ? null : n.getNodeValue(); if(pack!=null && pack.length()>0){ if(!className0.contains(".")){ className0 = pack + "." +className0; diff --git a/hibernate/src/org/netbeans/modules/hibernate/refactoring/HibernateRefactoringUtil.java b/hibernate/src/org/netbeans/modules/hibernate/refactoring/HibernateRefactoringUtil.java --- a/hibernate/src/org/netbeans/modules/hibernate/refactoring/HibernateRefactoringUtil.java +++ b/hibernate/src/org/netbeans/modules/hibernate/refactoring/HibernateRefactoringUtil.java @@ -62,6 +62,7 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import javax.swing.text.Position.Bias; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.source.CompilationController; @@ -70,20 +71,18 @@ import org.netbeans.api.java.source.JavaSource.Phase; import org.netbeans.api.java.source.Task; import org.netbeans.api.java.source.TreePathHandle; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.project.Project; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenID; -import org.netbeans.editor.TokenItem; import org.netbeans.modules.hibernate.cfg.HibernateCfgXmlConstants; import org.netbeans.modules.hibernate.editor.HibernateEditorUtil; import org.netbeans.modules.hibernate.mapping.HibernateMappingXmlConstants; import org.netbeans.modules.hibernate.service.api.HibernateEnvironment; import org.netbeans.modules.refactoring.api.Problem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.ErrorManager; import org.openide.cookies.EditorCookie; import org.openide.filesystems.FileObject; @@ -297,153 +296,164 @@ // Get the document for this file DataObject dataObject = DataObject.find(mappingFile); EditorCookie result = dataObject.getCookie(EditorCookie.class); - String mappingPackage = null; if (result == null) { throw new IllegalStateException("File " + mappingFile + " does not have an EditorCookie."); } CloneableEditorSupport editor = (CloneableEditorSupport) result; - BaseDocument document = (BaseDocument) editor.openDocument(); - XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport) document.getSyntaxSupport(); + Document document = editor.openDocument(); + XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); + if (syntaxSupport == null) { + return foundPlaces; + } + return syntaxSupport.runWithSequence(0, + (TokenSequence ts) -> { + int start = document.getStartPosition().getOffset(); + return getOccurPlacesLocked(syntaxSupport, start, + editor, ts, searchingForName, searchingPackageName); + }); + } catch (BadLocationException | IOException ex) { + ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); + } + return foundPlaces; + } + + private static List getOccurPlacesLocked( + XMLSyntaxSupport sup, + int start, + CloneableEditorSupport editor, + TokenSequence seq, + String searchingForName, boolean searchingPackageName) throws BadLocationException { + List foundPlaces = new ArrayList(); + String mappingPackage = null; + seq.move(start); + while (seq.moveNext()) { + Token item = seq.token(); + XMLTokenId tokenId = item.id(); - int start = document.getStartPosition().getOffset(); - TokenItem item = syntaxSupport.getTokenChain(start, Math.min(start + 1, document.getLength())); - if (item == null) { - return null; - } + if (tokenId == XMLTokenId.TAG) { - while (item != null) { - TokenID tokenId = item.getTokenID(); + SyntaxElement element = sup.getElementChain(seq.offset() + 1); + String[] attributeValues = null; // Multiple attributes can have class name as values + boolean pkgValue = false; // To indicate the attributeValues are Java package, not full class name + if (sup.isStartTag(element) || sup.isEmptyTag(element)) { - if (tokenId == XMLDefaultTokenContext.TAG) { - - SyntaxElement element = syntaxSupport.getElementChain(item.getOffset() + 1); - String[] attributeValues = null; // Multiple attributes can have class name as values - boolean pkgValue = false; // To indicate the attributeValues are Java package, not full class name - if (element instanceof StartTag || element instanceof EmptyTag) { - - Node theNode = (Node) element; - String nodeName = theNode.getNodeName(); - String itemImage = item.getImage(); - - if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MAPPING_TAG) && - itemImage.contains(HibernateMappingXmlConstants.MAPPING_TAG)) { - if(searchingPackageName) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.PACKAGE_ATTRIB); - pkgValue = true; - } else { - mappingPackage = getAttributeValue(theNode, HibernateMappingXmlConstants.PACKAGE_ATTRIB); - } - } // Search the element/attrubutes that take class names - else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.CLASS_TAG) && - itemImage.contains(HibernateMappingXmlConstants.CLASS_TAG)) { + Node theNode = (Node) element; + String nodeName = theNode.getNodeName(); + String itemImage = item.text().toString(); + int itemOffset = seq.offset(); + + if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MAPPING_TAG) && + itemImage.contains(HibernateMappingXmlConstants.MAPPING_TAG)) { + if(searchingPackageName) { // element attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_MANY_TAG) && - itemImage.contains(HibernateMappingXmlConstants.ONE_TO_MANY_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPOSITE_ID_TAG) && - itemImage.contains(HibernateMappingXmlConstants.COMPOSITE_ID_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.MANY_TO_ONE_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.ONE_TO_ONE_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPONENT_TAG) && - itemImage.contains(HibernateMappingXmlConstants.COMPONENT_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.SUBCLASS_TAG) && - itemImage.contains(HibernateMappingXmlConstants.SUBCLASS_TAG)) { - // element - attributeValues = new String[2]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); - attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.JOINED_SUBCLASS_TAG) && - itemImage.contains(HibernateMappingXmlConstants.JOINED_SUBCLASS_TAG)) { - // element - attributeValues = new String[3]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); - attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); - attributeValues[2] = getAttributeValue(theNode, HibernateMappingXmlConstants.PERSISTER_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.UNION_SUBCLASS_TAG) && - itemImage.contains(HibernateMappingXmlConstants.UNION_SUBCLASS_TAG)) { - // element - attributeValues = new String[3]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); - attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); - attributeValues[2] = getAttributeValue(theNode, HibernateMappingXmlConstants.PERSISTER_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.IMPORT_TAG) && - itemImage.contains(HibernateMappingXmlConstants.IMPORT_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_MANY_TAG) && - itemImage.contains(HibernateMappingXmlConstants.MANY_TO_MANY_TAG)) { - // element - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); - } else if(nodeName.equalsIgnoreCase("property") &&//NOI18N - itemImage.contains("property")) {//NOI18N - attributeValues = new String[1]; - attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.TYPE_ATTRIB); + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.PACKAGE_ATTRIB); + pkgValue = true; + } else { + mappingPackage = getAttributeValue(theNode, HibernateMappingXmlConstants.PACKAGE_ATTRIB); } - if (attributeValues != null) { - for (int i = 0; i < attributeValues.length; i++) { + } // Search the element/attrubutes that take class names + else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.CLASS_TAG) && + itemImage.contains(HibernateMappingXmlConstants.CLASS_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_MANY_TAG) && + itemImage.contains(HibernateMappingXmlConstants.ONE_TO_MANY_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPOSITE_ID_TAG) && + itemImage.contains(HibernateMappingXmlConstants.COMPOSITE_ID_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.MANY_TO_ONE_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.ONE_TO_ONE_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPONENT_TAG) && + itemImage.contains(HibernateMappingXmlConstants.COMPONENT_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.SUBCLASS_TAG) && + itemImage.contains(HibernateMappingXmlConstants.SUBCLASS_TAG)) { + // element + attributeValues = new String[2]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); + attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.JOINED_SUBCLASS_TAG) && + itemImage.contains(HibernateMappingXmlConstants.JOINED_SUBCLASS_TAG)) { + // element + attributeValues = new String[3]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); + attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); + attributeValues[2] = getAttributeValue(theNode, HibernateMappingXmlConstants.PERSISTER_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.UNION_SUBCLASS_TAG) && + itemImage.contains(HibernateMappingXmlConstants.UNION_SUBCLASS_TAG)) { + // element + attributeValues = new String[3]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); + attributeValues[1] = getAttributeValue(theNode, HibernateMappingXmlConstants.EXTENDS_ATTRIB); + attributeValues[2] = getAttributeValue(theNode, HibernateMappingXmlConstants.PERSISTER_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.IMPORT_TAG) && + itemImage.contains(HibernateMappingXmlConstants.IMPORT_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_MANY_TAG) && + itemImage.contains(HibernateMappingXmlConstants.MANY_TO_MANY_TAG)) { + // element + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.CLASS_ATTRIB); + } else if(nodeName.equalsIgnoreCase("property") &&//NOI18N + itemImage.contains("property")) {//NOI18N + attributeValues = new String[1]; + attributeValues[0] = getAttributeValue(theNode, HibernateMappingXmlConstants.TYPE_ATTRIB); + } + if (attributeValues != null) { + for (int i = 0; i < attributeValues.length; i++) { - String text = document.getText(item.getOffset(), element.getElementLength()); + String text = sup.getDocument().getText(itemOffset, element.getElementLength()); - String value = attributeValues[i]; - if (searchingPackageName && !pkgValue) { - value = getPackageName(value); - } + String value = attributeValues[i]; + if (searchingPackageName && !pkgValue) { + value = getPackageName(value); + } - if (value != null && (value.equals(searchingForName) || (mappingPackage!=null && mappingPackage.length()>0 && value.indexOf('.')==-1 && (mappingPackage + "." + value).equals(searchingForName)))) { + if (value != null && (value.equals(searchingForName) || (mappingPackage!=null && mappingPackage.length()>0 && value.indexOf('.')==-1 && (mappingPackage + "." + value).equals(searchingForName)))) { - // TODO: can not just do indexof. It does not work correctly if there are multiple - // attributes have the same class searchingForName. Though, it does not make sense to have such case. + // TODO: can not just do indexof. It does not work correctly if there are multiple + // attributes have the same class searchingForName. Though, it does not make sense to have such case. - if (text.indexOf(value) != -1) { - int startOffset = item.getOffset() + text.indexOf(value); - int endOffset = startOffset + value.length(); + if (text.indexOf(value) != -1) { + int startOffset = itemOffset + text.indexOf(value); + int endOffset = startOffset + value.length(); - PositionBounds loc = new PositionBounds(editor.createPositionRef(startOffset, Bias.Forward), - editor.createPositionRef(endOffset, Bias.Forward)); + PositionBounds loc = new PositionBounds(editor.createPositionRef(startOffset, Bias.Forward), + editor.createPositionRef(endOffset, Bias.Forward)); - foundPlaces.add(new OccurrenceItem(loc, text, value)); - } + foundPlaces.add(new OccurrenceItem(loc, text, value)); } } } } } - item = item.getNext(); } - } catch (IOException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); - } catch (BadLocationException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); } - return foundPlaces; } @@ -458,88 +468,96 @@ } CloneableEditorSupport editor = (CloneableEditorSupport) result; - BaseDocument document = (BaseDocument) editor.openDocument(); - XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport) document.getSyntaxSupport(); + Document document = editor.openDocument(); + XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); + if (syntaxSupport == null) { + return foundPlaces; + } + foundPlaces = syntaxSupport.runWithSequence(0, + (TokenSequence ts) -> { + int start = document.getStartPosition().getOffset(); + return getJavaFieldOccurPlacesLocked(syntaxSupport, ts, start, editor, className, fieldName); + }); + } catch (IOException | BadLocationException ex) { + ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); + } + return foundPlaces; + } - int start = document.getStartPosition().getOffset(); - TokenItem item = syntaxSupport.getTokenChain(start, Math.min(start + 1, document.getLength())); - if (item == null) { - return null; - } - String text = null; - while (item != null) { - TokenID tokenId = item.getTokenID(); + private static List getJavaFieldOccurPlacesLocked( + XMLSyntaxSupport sup, TokenSequence seq, int start, + CloneableEditorSupport editor, String className, String fieldName) throws BadLocationException { + List foundPlaces = new ArrayList(); + seq.move(start); + String text = null; + while (seq.moveNext()) { + Token item = seq.token(); + XMLTokenId tokenId = item.id(); - if (tokenId == XMLDefaultTokenContext.TAG) { - // Did we find the element + if (tokenId == XMLTokenId.TAG) { + // Did we find the element - SyntaxElement element = syntaxSupport.getElementChain(item.getOffset() + 1); - String nameAttribValue = null; - if (element instanceof StartTag || element instanceof EmptyTag) { + SyntaxElement element = sup.getElementChain(seq.offset() + 1); + String nameAttribValue = null; + if (sup.isStartTag(element) || sup.isEmptyTag(element)) { - Node theNode = (Node) element; - String nodeName = theNode.getNodeName(); - String itemImage = item.getImage(); + Node theNode = (Node) element; + String nodeName = theNode.getNodeName(); + String itemImage = item.text().toString(); - if ((nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.PROPERTY_TAG) && - itemImage.contains(HibernateMappingXmlConstants.PROPERTY_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ID_TAG) && - itemImage.contains(HibernateMappingXmlConstants.ID_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.SET_TAG) && - itemImage.contains(HibernateMappingXmlConstants.SET_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPOSITE_ID_TAG) && - itemImage.contains(HibernateMappingXmlConstants.COMPOSITE_ID_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_PROPERTY_TAG) && - itemImage.contains(HibernateMappingXmlConstants.KEY_PROPERTY_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.VERSION_TAG) && - itemImage.contains(HibernateMappingXmlConstants.VERSION_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.TIMESTAMP_TAG) && - itemImage.contains(HibernateMappingXmlConstants.TIMESTAMP_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.MANY_TO_ONE_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_ONE_TAG) && - itemImage.contains(HibernateMappingXmlConstants.ONE_TO_ONE_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPONENT_TAG) && - itemImage.contains(HibernateMappingXmlConstants.COMPONENT_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ANY_TAG) && - itemImage.contains(HibernateMappingXmlConstants.ANY_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MAP_TAG) && - itemImage.contains(HibernateMappingXmlConstants.MAP_TAG)) || - (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.LIST_TAG) && - itemImage.contains(HibernateMappingXmlConstants.LIST_TAG))) { + if ((nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.PROPERTY_TAG) && + itemImage.contains(HibernateMappingXmlConstants.PROPERTY_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ID_TAG) && + itemImage.contains(HibernateMappingXmlConstants.ID_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.SET_TAG) && + itemImage.contains(HibernateMappingXmlConstants.SET_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPOSITE_ID_TAG) && + itemImage.contains(HibernateMappingXmlConstants.COMPOSITE_ID_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_PROPERTY_TAG) && + itemImage.contains(HibernateMappingXmlConstants.KEY_PROPERTY_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.KEY_MANY_TO_ONE_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.VERSION_TAG) && + itemImage.contains(HibernateMappingXmlConstants.VERSION_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.TIMESTAMP_TAG) && + itemImage.contains(HibernateMappingXmlConstants.TIMESTAMP_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MANY_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.MANY_TO_ONE_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ONE_TO_ONE_TAG) && + itemImage.contains(HibernateMappingXmlConstants.ONE_TO_ONE_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.COMPONENT_TAG) && + itemImage.contains(HibernateMappingXmlConstants.COMPONENT_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.ANY_TAG) && + itemImage.contains(HibernateMappingXmlConstants.ANY_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.MAP_TAG) && + itemImage.contains(HibernateMappingXmlConstants.MAP_TAG)) || + (nodeName.equalsIgnoreCase(HibernateMappingXmlConstants.LIST_TAG) && + itemImage.contains(HibernateMappingXmlConstants.LIST_TAG))) { - nameAttribValue = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); + nameAttribValue = getAttributeValue(theNode, HibernateMappingXmlConstants.NAME_ATTRIB); - if (nameAttribValue != null && nameAttribValue.equals(fieldName)) { + if (nameAttribValue != null && nameAttribValue.equals(fieldName)) { - // Check class name - if (HibernateEditorUtil.getClassName(theNode).equals(className)) { - text = document.getText(item.getOffset(), element.getElementLength()); + // Check class name + if (HibernateEditorUtil.getClassName(theNode).equals(className)) { + text = sup.getDocument().getText(seq.offset(), element.getElementLength()); - // find the offset for the field name - int index = text.indexOf(fieldName); - int startOffset = item.getOffset() + index; - int endOffset = startOffset + fieldName.length(); - PositionBounds loc = new PositionBounds(editor.createPositionRef(startOffset, Bias.Forward), - editor.createPositionRef(endOffset, Bias.Forward)); + // find the offset for the field name + int index = text.indexOf(fieldName); + int startOffset = seq.offset() + index; + int endOffset = startOffset + fieldName.length(); + PositionBounds loc = new PositionBounds( + editor.createPositionRef(startOffset, Bias.Forward), + editor.createPositionRef(endOffset, Bias.Forward)); - foundPlaces.add(new OccurrenceItem(loc, text, fieldName)); - } + foundPlaces.add(new OccurrenceItem(loc, text, fieldName)); } } } } - item = item.getNext(); } - } catch (IOException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); - } catch (BadLocationException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); } - return foundPlaces; } @@ -563,65 +581,71 @@ CloneableEditorSupport editor = (CloneableEditorSupport) result; BaseDocument document = (BaseDocument) editor.openDocument(); - XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport) document.getSyntaxSupport(); + XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); + if (syntaxSupport == null) { + return foundPlaces; + } + return syntaxSupport.runWithSequence(0, + (TokenSequence ts) -> { + int start = document.getStartPosition().getOffset(); + return getMappingResourceOccurPlacesLocked(syntaxSupport, ts, start, editor, resourceName, searchingPathOnly); + }); + } catch (IOException | BadLocationException ex) { + ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); + } + return foundPlaces; + } - int start = document.getStartPosition().getOffset(); - TokenItem item = syntaxSupport.getTokenChain(start, Math.min(start + 1, document.getLength())); - if (item == null) { - return null; - } + private static List getMappingResourceOccurPlacesLocked( + XMLSyntaxSupport sup, TokenSequence seq, int start, CloneableEditorSupport editor, + String resourceName, boolean searchingPathOnly) throws BadLocationException { + List foundPlaces = new ArrayList(); + seq.move(start); + String text = null; + while (seq.moveNext()) { + Token item = seq.token(); + XMLTokenId tokenId = item.id(); - String text = null; - while (item != null) { - TokenID tokenId = item.getTokenID(); + if (tokenId == XMLTokenId.TAG) { + // Did we find the element - if (tokenId == XMLDefaultTokenContext.TAG) { - // Did we find the element + SyntaxElement element = sup.getElementChain(seq.offset() + 1); + String mappingResourceAttribValue = null; + if (sup.isStartTag(element) || sup.isEmptyTag(element)) { - SyntaxElement element = syntaxSupport.getElementChain(item.getOffset() + 1); - String mappingResourceAttribValue = null; - if (element instanceof StartTag || element instanceof EmptyTag) { + Node theNode = (Node) element; + String nodeName = theNode.getNodeName(); + String itemImage = item.text().toString(); - Node theNode = (Node) element; - String nodeName = theNode.getNodeName(); - String itemImage = item.getImage(); + if(nodeName.equalsIgnoreCase(HibernateCfgXmlConstants.MAPPING_TAG) && + itemImage.contains(HibernateCfgXmlConstants.MAPPING_TAG)){ - if(nodeName.equalsIgnoreCase(HibernateCfgXmlConstants.MAPPING_TAG) && - itemImage.contains(HibernateCfgXmlConstants.MAPPING_TAG)){ + mappingResourceAttribValue = getAttributeValue(theNode, HibernateCfgXmlConstants.RESOURCE_ATTRIB); + if(mappingResourceAttribValue != null) { + if(searchingPathOnly) { + int lastIndex = mappingResourceAttribValue.lastIndexOf('/'); + if (lastIndex > -1) { + mappingResourceAttribValue = mappingResourceAttribValue.substring(0, lastIndex); + } else { + mappingResourceAttribValue = ""; + } + } + if (mappingResourceAttribValue.equals(resourceName)) { + text = sup.getDocument().getText(seq.offset(), element.getElementLength()); - mappingResourceAttribValue = getAttributeValue(theNode, HibernateCfgXmlConstants.RESOURCE_ATTRIB); - if(mappingResourceAttribValue != null) { - if(searchingPathOnly) { - int lastIndex = mappingResourceAttribValue.lastIndexOf('/'); - if (lastIndex > -1) { - mappingResourceAttribValue = mappingResourceAttribValue.substring(0, lastIndex); - } else { - mappingResourceAttribValue = ""; - } - } - if (mappingResourceAttribValue.equals(resourceName)) { - text = document.getText(item.getOffset(), element.getElementLength()); - - // find the offset for the field name - int index = text.indexOf(resourceName); - int startOffset = item.getOffset() + index; - int endOffset = startOffset + resourceName.length(); - PositionBounds loc = new PositionBounds(editor.createPositionRef(startOffset, Bias.Forward), - editor.createPositionRef(endOffset, Bias.Forward)); - foundPlaces.add(new OccurrenceItem(loc, text, resourceName)); - } + // find the offset for the field name + int index = text.indexOf(resourceName); + int startOffset = seq.offset() + index; + int endOffset = startOffset + resourceName.length(); + PositionBounds loc = new PositionBounds(editor.createPositionRef(startOffset, Bias.Forward), + editor.createPositionRef(endOffset, Bias.Forward)); + foundPlaces.add(new OccurrenceItem(loc, text, resourceName)); } } } } - item = item.getNext(); } - } catch (IOException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); - } catch (BadLocationException ex) { - ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex); } - return foundPlaces; } diff --git a/j2ee.persistence/nbproject/project.properties b/j2ee.persistence/nbproject/project.properties --- a/j2ee.persistence/nbproject/project.properties +++ b/j2ee.persistence/nbproject/project.properties @@ -40,8 +40,8 @@ # Version 2 license, then the option applies only if the new code is # made subject to such option by the copyright holder. -javac.source=1.7 -spec.version.base=1.52.0 +javac.source=1.8 +spec.version.base=1.53.0 test.unit.run.cp.extra=${j2eeserver.dir}/modules/ext/jsr88javax.jar:${j2ee.persistence.dir}/modules/ext/eclipselink/eclipselink.jar:${j2ee.persistence.dir}/modules/ext/eclipselink/javax.persistence_2.1.0.v201304241213.jar:${masterfs.dir}/modules/org-netbeans-modules-masterfs.jar diff --git a/j2ee.persistence/nbproject/project.xml b/j2ee.persistence/nbproject/project.xml --- a/j2ee.persistence/nbproject/project.xml +++ b/j2ee.persistence/nbproject/project.xml @@ -463,7 +463,7 @@ 2 - 1.30 + 1.60 diff --git a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/CompletionContext.java b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/CompletionContext.java --- a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/CompletionContext.java +++ b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/CompletionContext.java @@ -48,16 +48,13 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Node; import org.w3c.dom.Text; @@ -65,7 +62,7 @@ * Tracks context information for a code completion scenario */ public class CompletionContext { - private ArrayList existingAttributes; + private List existingAttributes; public static enum CompletionType { TAG, @@ -89,49 +86,61 @@ this.caretOffset = caretOffset; try { - this.support = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport(); + this.support = XMLSyntaxSupport.getSyntaxSupport(doc); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.support = new XMLSyntaxSupport(((BaseDocument)doc)); + this.support = XMLSyntaxSupport.createSyntaxSupport(doc); } this.documentContext = EditorContextFactory.getDocumentContext(doc, caretOffset); this.lastTypedChar = support.lastTypedChar(); - initContext(); + try { + initContext(); + } catch (BadLocationException ex) { + throw new IllegalStateException(ex); + } } - private void initContext() { - TokenItem token = documentContext.getCurrentToken(); + private void initContext() throws BadLocationException { + Token token = documentContext.getCurrentToken(); if(token == null) return; - boolean tokenBoundary = (token.getOffset() == caretOffset) - || ((token.getOffset() + token.getImage().length()) == caretOffset); + boolean tokenBoundary = (documentContext.getCurrentTokenOffset() == caretOffset) + || ((documentContext.getCurrentTokenOffset() + token.length()) == caretOffset); - int id = token.getTokenID().getNumericID(); + XMLTokenId id = token.id(); SyntaxElement element = documentContext.getCurrentElement(); + int tOffset = documentContext.getCurrentTokenOffset(); + switch (id) { // - case XMLDefaultTokenContext.TEXT_ID: - String chars = token.getImage().trim(); + case TEXT: + String chars = token.text().toString().trim(); + Token previousTokenItem = support.getPreviousToken(tOffset); + if (previousTokenItem == null) { + completionType = CompletionType.NONE; + break; + } + String previousTokenText = previousTokenItem.text().toString().trim(); if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals("/>")) { // NOI18N + previousTokenText.equals("/>")) { // NOI18N completionType = CompletionType.NONE; break; } if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + previousTokenText.equals(">")) { // NOI18N completionType = CompletionType.VALUE; break; } if (chars != null && !chars.startsWith("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + previousTokenText.equals(">")) { // NOI18N completionType = CompletionType.VALUE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset()); + typedChars = token.text().subSequence(0, caretOffset - tOffset).toString(); break; } if (chars != null && !chars.equals("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + previousTokenText.equals(">")) { // NOI18N completionType = CompletionType.NONE; break; } @@ -142,54 +151,57 @@ break; //start tag of an element - case XMLDefaultTokenContext.TAG_ID: - if (element instanceof EndTag) { + case TAG: + if (support.isEndTag(element)) { completionType = CompletionType.NONE; break; } - if (element instanceof EmptyTag) { + if (support.isEmptyTag(element)) { if (token != null && - token.getImage().trim().equals("/>")) { + token.text().toString().trim().equals("/>")) { completionType = CompletionType.NONE; break; } - EmptyTag tag = (EmptyTag) element; if (element.getElementOffset() + 1 == this.caretOffset) { completionType = CompletionType.TAG; break; } if (caretOffset > element.getElementOffset() + 1 && - caretOffset <= element.getElementOffset() + 1 + tag.getTagName().length()) { + caretOffset <= element.getElementOffset() + 1 +element.getNode().getNodeName().length()) { completionType = CompletionType.TAG; - typedChars = tag.getTagName(); + typedChars = element.getNode().getNodeName(); break; } completionType = CompletionType.ATTRIBUTE; break; } - if (element instanceof StartTag) { + if (support.isStartTag(element)) { if (token != null && - token.getImage().trim().equals(">")) { + token.text().toString().trim().equals(">")) { completionType = CompletionType.NONE; break; } if (token != null && - token.getImage().trim().startsWith(" prevToken = support.getPreviousToken(tOffset); + if (prevToken == null) { + completionType = CompletionType.NONE; + break; + } + typedChars = prevToken.text().toString().trim(); completionType = CompletionType.VALUE; break; } @@ -203,41 +215,60 @@ break; //user enters an attribute name - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: completionType = CompletionType.ATTRIBUTE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset());; + typedChars = token.text().toString().substring(0, caretOffset - tOffset);; break; //some random character - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: //user enters = character, we should ignore all other operators - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: completionType = CompletionType.NONE; break; //user enters either ' or " - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: if(!tokenBoundary) { completionType = CompletionType.ATTRIBUTE_VALUE; - typedChars = token.getImage().substring(1, caretOffset - token.getOffset()); + typedChars = token.text().subSequence(1, caretOffset - tOffset).toString(); } else { completionType = CompletionType.NONE; } break; //user enters white-space character - case XMLDefaultTokenContext.WS_ID: + case WS: completionType = CompletionType.NONE; - TokenItem prev = token.getPrevious(); - while (prev != null && - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID)) { - prev = prev.getPrevious(); + int[] offset = new int[1]; + Token prev = support.runWithSequence(tOffset, + (TokenSequence ts) -> { + Token t = null; + boolean ok; + while ((ok = ts.movePrevious())) { + t = ts.token(); + if (t.id() != XMLTokenId.WS) { + break; + } + } + if (ok) { + offset[0] = ts.offset(); + return t; + } else { + return null; + } + } + ); + if (prev == null) { + completionType = CompletionType.NONE; + break; } - - if(prev.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { - typedChars = prev.getImage(); + int prevOffset = offset[0]; + + if(prev.id() == XMLTokenId.ARGUMENT) { + typedChars = prev.text().toString(); completionType = CompletionType.ATTRIBUTE; - } else if ((prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) || - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID)) { + } else if ((prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG)) { completionType = CompletionType.ATTRIBUTE; } break; @@ -270,27 +301,41 @@ public Node getTag() { SyntaxElement element = documentContext.getCurrentElement(); - return (element instanceof Tag) ? (Node) element : null; + return element.getType() == Node.ELEMENT_NODE ? (Node) element : null; } - public TokenItem getCurrentToken() { + public Token getCurrentToken() { return documentContext.getCurrentToken(); } + public int getCurrentTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } + + private List getExistingAttributesLocked(TokenSequence ts) { + List existingAttributes = new ArrayList(); + while (ts.movePrevious()) { + Token item = ts.token(); + XMLTokenId tokenId = item.id(); + if (tokenId == XMLTokenId.TAG) { + break; + } + if (tokenId == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } + } + return existingAttributes; + } + public List getExistingAttributes() { - if(existingAttributes != null) - return existingAttributes; - existingAttributes = new ArrayList(); - TokenItem item = documentContext.getCurrentToken().getPrevious(); - while(item != null) { - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.TAG_ID) - break; - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.ARGUMENT_ID) { - existingAttributes.add(item.getImage()); + if (existingAttributes == null) { + try { + existingAttributes = (List)support.runWithSequence( + documentContext.getCurrentTokenOffset(), + this::getExistingAttributesLocked + ); + } catch (BadLocationException ex) { } - item = item.getPrevious(); } return existingAttributes; } diff --git a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/ContextUtilities.java b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/ContextUtilities.java --- a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/ContextUtilities.java +++ b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/ContextUtilities.java @@ -44,13 +44,16 @@ package org.netbeans.modules.j2ee.persistence.editor; +import javax.swing.text.BadLocationException; import javax.xml.XMLConstants; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import static org.netbeans.api.xml.lexer.XMLTokenId.*; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.w3c.dom.Node; /** * @@ -61,9 +64,9 @@ private ContextUtilities() { } - public static boolean isValueToken(TokenItem currentToken) { + public static boolean isValueToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) { + if (currentToken.id() == VALUE) { return true; } } @@ -71,9 +74,9 @@ return false; } - public static boolean isTagToken(TokenItem currentToken) { + public static boolean isTagToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) { + if (currentToken.id() == TAG) { return true; } } @@ -81,9 +84,9 @@ return false; } - public static boolean isAttributeToken(TokenItem currentToken) { + public static boolean isAttributeToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { + if (currentToken.id() == ARGUMENT) { return true; } } @@ -91,88 +94,44 @@ return false; } - public static TokenItem getAttributeToken(TokenItem currentToken) { - if(currentToken == null ) - return null; - - if(isValueToken(currentToken)) { - TokenItem equalsToken = currentToken.getPrevious(); - if(equalsToken == null) - return null; - - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; - } - - return null; - } - - public static Tag getCurrentTagElement(DocumentContext context) { - SyntaxElement element = context.getCurrentElement(); - if(element instanceof StartTag) { - return (StartTag) element; - } else if(element instanceof EmptyTag) { - return (EmptyTag) element; - } - - return null; - } - - public static TokenItem getAttributeToken(DocumentContext context) { + public static Token getAttributeToken(DocumentContext context) { if(context.getCurrentToken() == null ) return null; - - if(isValueToken(context.getCurrentToken())) { - TokenItem equalsToken = context.getCurrentToken().getPrevious(); - if(equalsToken == null) - return null; - - //getTokenId() should not return null by JavaDoc. But in reality, it does reutrn null sometimes - // see issue 67661 - if(equalsToken.getTokenID() == null) { - return null; - } - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; + try { + return context.>runWithSequence((TokenSequence ts) -> { + if(!isValueToken(context.getCurrentToken())) { + return null; + } + Token equalsToken = null; + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == OPERATOR) { + equalsToken = t; + break; + } + } + if(equalsToken == null) { + return null; + } + Token argumentToken = null; + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == ARGUMENT) { + argumentToken = t; + break; + } + } + return argumentToken; + }); + } catch (BadLocationException ex) { } - return null; } public static String getAttributeTokenImage(DocumentContext context) { - TokenItem tok = getAttributeToken(context); + Token tok = getAttributeToken(context); if(tok != null) { - return tok.getImage(); + return tok.text().toString(); } return null; @@ -221,11 +180,12 @@ return nodeName.substring(0, colonIndex); } - public static StartTag getRoot(SyntaxElement se) { - StartTag root = null; + public static SyntaxElement getRoot(SyntaxElement se) { + SyntaxElement root = null; while( se != null) { - if(se instanceof StartTag) { - root = (StartTag)se; + if(se.getType() == Node.ELEMENT_NODE && + ((TagElement)se).isStart()) { + root = se; } se = se.getPrevious(); } diff --git a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/DocumentContext.java b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/DocumentContext.java --- a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/DocumentContext.java +++ b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/DocumentContext.java @@ -55,14 +55,10 @@ import java.util.logging.Logger; import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Attr; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -79,9 +75,10 @@ private XMLSyntaxSupport syntaxSupport; private int caretOffset = -1; private SyntaxElement element; - private TokenItem token; + private Token token; + private int tokenOffset; private boolean valid = false; - private StartTag docRoot; + private SyntaxElement docRoot; private String defaultNamespace; private HashMap declaredNamespaces = new HashMap(); @@ -93,10 +90,10 @@ DocumentContext(Document document) { this.document = document; try { - this.syntaxSupport = (XMLSyntaxSupport) ((BaseDocument)document).getSyntaxSupport(); + this.syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.syntaxSupport = new XMLSyntaxSupport(((BaseDocument)document)); + this.syntaxSupport = XMLSyntaxSupport.createSyntaxSupport(document); } } @@ -110,7 +107,9 @@ declaredNamespaces.clear(); try { element = syntaxSupport.getElementChain(caretOffset); - token = syntaxSupport.getTokenChain(caretOffset, Math.min(document.getLength(), caretOffset+1)); + int[] off = new int[2]; + token = syntaxSupport.getNextToken(caretOffset, off); + tokenOffset = off[0]; this.docRoot = ContextUtilities.getRoot(element); populateNamespaces(); } catch (BadLocationException ex) { @@ -123,25 +122,21 @@ return this.valid; } - public int getCurrentTokenId() { - if (isValid()) { - return token.getTokenID().getNumericID(); - } else { - return -1; - } - } - - public TokenItem getCurrentToken() { + public Token getCurrentToken() { if (isValid()) { return token; } else { return null; } } + + public int getCurrentTokenOffset() { + return tokenOffset; + } public String getCurrentTokenImage() { if (isValid()) { - return token.getImage(); + return token.text().toString(); } else { return null; } @@ -151,54 +146,6 @@ return this.element; } - public List getPathFromRoot() { - if (isValid()) { - SyntaxElement elementRef = this.element; - Stack stack = new Stack(); - - while (elementRef != null) { - if ((elementRef instanceof EndTag) || - (elementRef instanceof EmptyTag && stack.isEmpty()) || - (elementRef instanceof StartTag && stack.isEmpty())) { - stack.push(elementRef); - elementRef = elementRef.getPrevious(); - continue; - } - if (elementRef instanceof StartTag) { - StartTag start = (StartTag) elementRef; - if (stack.peek() instanceof EndTag) { - EndTag end = (EndTag) stack.peek(); - if (end.getTagName().equals(start.getTagName())) { - stack.pop(); - } - } else { - SyntaxElement e = (SyntaxElement) stack.peek(); - String tagAtTop = (e instanceof StartTag) ? ((StartTag) e).getTagName() : ((EmptyTag) e).getTagName(); - stack.push(elementRef); - } - } - elementRef = elementRef.getPrevious(); - } - - return createPath(stack); - } - - return Collections.emptyList(); - } - - private List createPath(Stack stack) { - ArrayList pathList = new ArrayList(); - while (!stack.isEmpty()) { - SyntaxElement top = stack.pop(); - String tagName = (top instanceof StartTag) ? ((StartTag) top).getTagName() : ((EmptyTag) top).getTagName(); - if (tagName != null) { - pathList.add(tagName); - } - } - - return Collections.unmodifiableList(pathList); - } - public Document getDocument() { return this.document; } @@ -225,7 +172,7 @@ return declaredNamespaces.values(); } - public StartTag getDocRoot() { + public SyntaxElement getDocRoot() { return docRoot; } @@ -236,7 +183,7 @@ private void populateNamespaces() { // Find the a start or empty tag just before the current syntax element. SyntaxElement element = this.element; - while (element != null && !(element instanceof StartTag) && !(element instanceof EmptyTag)) { + while (element != null && !syntaxSupport.isStartTag(element) && !syntaxSupport.isEmptyTag(element)) { element = element.getPrevious(); } if (element == null) { @@ -246,9 +193,9 @@ // To find all namespace declarations active at the caret offset, we // need to look at xmlns attributes of the current element and its ancestors. Node node = (Node)element; - while (node != null) { - if (node instanceof StartTag || node instanceof EmptyTag) { - NamedNodeMap attributes = ((Tag)node).getAttributes(); + while (node != null && element != null) { + if (syntaxSupport.isStartTag(element) || syntaxSupport.isEmptyTag(element)) { + NamedNodeMap attributes = node.getAttributes(); for (int index = 0; index < attributes.getLength(); index++) { Attr attr = (Attr) attributes.item(index); String attrName = attr.getName(); @@ -271,6 +218,7 @@ } } node = node.getParentNode(); + element = syntaxSupport.getSyntaxElement(node); } } @@ -303,4 +251,8 @@ hash = 61 * hash + (this.document != null ? this.document.hashCode() : 0); return hash; } + + public T runWithSequence(XMLSyntaxSupport.SequenceCallable callable) throws BadLocationException { + return syntaxSupport.runWithSequence(caretOffset, callable); + } } diff --git a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletionManager.java b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletionManager.java --- a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletionManager.java +++ b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletionManager.java @@ -48,13 +48,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.netbeans.editor.TokenItem; +import javax.swing.text.BadLocationException; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.j2ee.persistence.editor.*; import org.netbeans.modules.j2ee.persistence.unit.PersistenceCfgProperties; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; -import org.w3c.dom.Text; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.w3c.dom.Node; /** * This class figures out the completion items for various attributes @@ -109,8 +111,8 @@ } String tagName = context.getTag().getNodeName(); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; PUCompletor completor = locateCompletor(tagName, attribName); if (completor != null) { @@ -128,9 +130,17 @@ DocumentContext docContext = context.getDocumentContext(); SyntaxElement curElem = docContext.getCurrentElement(); SyntaxElement prevElem = docContext.getCurrentElement().getPrevious(); - Tag propTag; + TagElement propTag; - String tagName = (curElem instanceof StartTag) ? ((StartTag) curElem).getTagName() : ((prevElem instanceof StartTag) ? ((StartTag) prevElem).getTagName() : null); + String tagName; + + if (curElem.getType() == Node.ELEMENT_NODE && ((TagElement)curElem).isStart()) { + tagName = curElem.getNode().getNodeName(); + } else if (prevElem.getType() == Node.ELEMENT_NODE && ((TagElement)prevElem).isStart()) { + tagName = prevElem.getNode().getNodeName(); + } else { + tagName = null; + } PUCompletor completor = locateCompletor(tagName, null); if (completor != null) { valueItems.addAll(completor.doCompletion(context)); @@ -142,16 +152,17 @@ // If current element is a start tag and its tag is // or the current element is text and its prev is a start tag, // then do the code completion - if ((curElem instanceof StartTag) && ((StartTag) curElem).getTagName().equalsIgnoreCase(PersistenceCfgXmlConstants.PROPERTY_TAG)) { - propTag = (StartTag) curElem; - } else if ((curElem instanceof Text) && (prevElem instanceof StartTag) && - ((StartTag) prevElem).getTagName().equalsIgnoreCase(PersistenceCfgXmlConstants.PROPERTY_TAG)) { - propTag = (StartTag) prevElem; + if (curElem.getType() == Node.ELEMENT_NODE && ((TagElement)curElem).isStart() && + PersistenceCfgXmlConstants.PROPERTY_TAG.equalsIgnoreCase(curElem.getNode().getNodeName())) { + propTag = (TagElement)curElem; + } else if (curElem.getType() == Node.TEXT_NODE && (prevElem.getType() == Node.ELEMENT_NODE && ((TagElement)prevElem).isStart()) && + PersistenceCfgXmlConstants.PROPERTY_TAG.equalsIgnoreCase(prevElem.getNode().getNodeName())) { + propTag = (TagElement)prevElem; } else { return anchorOffset; } - String propName = JPAEditorUtil.getPersistencePropertyName(propTag); + String propName = JPAEditorUtil.getPersistencePropertyName(propTag.getNode()); int caretOffset = context.getCaretOffset(); String typedChars = context.getTypedPrefix(); @@ -171,7 +182,17 @@ } } - anchorOffset = context.getCurrentToken().getPrevious().getOffset() + 1; + try { + anchorOffset = context.getDocumentContext(). + runWithSequence((TokenSequence s) -> { + if (!s.movePrevious()) { + return -1; + } + return s.offset(); + }); + } catch (BadLocationException ex) { + anchorOffset = -1; + } } } return anchorOffset; diff --git a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletor.java b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletor.java --- a/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletor.java +++ b/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/PUCompletor.java @@ -103,7 +103,7 @@ } } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -131,7 +131,7 @@ results.add(item); } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -151,7 +151,7 @@ results.add(item); } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -199,7 +199,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -221,7 +221,7 @@ return Collections.emptyList(); } FileObject fo = NbEditorUtilities.getFileObject(context.getDocument()); - doJavaCompletion(fo, js, results, typedChars, context.getCurrentToken().getOffset()); + doJavaCompletion(fo, js, results, typedChars, context.getCurrentTokenOffset()); } catch (IOException ex) { Exceptions.printStackTrace(ex); } @@ -318,7 +318,7 @@ Exceptions.printStackTrace(ex); } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } @@ -364,7 +364,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -425,7 +425,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } } @@ -455,7 +455,7 @@ } } - setAnchorOffset(context.getCurrentToken().getOffset() + 1); + setAnchorOffset(context.getCurrentTokenOffset() + 1); return results; } diff --git a/j2ee.websphere6/nbproject/project.xml b/j2ee.websphere6/nbproject/project.xml --- a/j2ee.websphere6/nbproject/project.xml +++ b/j2ee.websphere6/nbproject/project.xml @@ -190,7 +190,7 @@ org.netbeans.modules.xml.text 2 - 1.16 + 1.60 diff --git a/javafx2.editor/nbproject/project.xml b/javafx2.editor/nbproject/project.xml --- a/javafx2.editor/nbproject/project.xml +++ b/javafx2.editor/nbproject/project.xml @@ -277,7 +277,7 @@ 2 - 1.34 + 1.60 diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -556,6 +556,7 @@ xml.schema.model,\ xml.tax,\ xml.text,\ + xml.text.obsolete90,\ xml.tools,\ xml.wsdl.model,\ xml.xam,\ diff --git a/nbbuild/javadoctools/links.xml b/nbbuild/javadoctools/links.xml --- a/nbbuild/javadoctools/links.xml +++ b/nbbuild/javadoctools/links.xml @@ -250,3 +250,4 @@ + diff --git a/nbbuild/javadoctools/properties.xml b/nbbuild/javadoctools/properties.xml --- a/nbbuild/javadoctools/properties.xml +++ b/nbbuild/javadoctools/properties.xml @@ -248,3 +248,4 @@ + diff --git a/nbbuild/javadoctools/replaces.xml b/nbbuild/javadoctools/replaces.xml --- a/nbbuild/javadoctools/replaces.xml +++ b/nbbuild/javadoctools/replaces.xml @@ -248,3 +248,4 @@ + diff --git a/spring.beans/nbproject/project.properties b/spring.beans/nbproject/project.properties --- a/spring.beans/nbproject/project.properties +++ b/spring.beans/nbproject/project.properties @@ -40,10 +40,10 @@ # Version 2 license, then the option applies only if the new code is # made subject to such option by the copyright holder. -javac.source=1.7 +javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial -spec.version.base=1.40.0 +spec.version.base=1.41.0 test.config.stableBTD.includes=**/*Test.class test.config.stableBTD.excludes=\ diff --git a/spring.beans/nbproject/project.xml b/spring.beans/nbproject/project.xml --- a/spring.beans/nbproject/project.xml +++ b/spring.beans/nbproject/project.xml @@ -145,6 +145,14 @@ + org.netbeans.modules.editor.document + + + + 1.0 + + + org.netbeans.modules.editor.indent @@ -172,14 +180,6 @@ - org.netbeans.modules.editor.document - - - - 1.0 - - - org.netbeans.modules.editor.mimelookup @@ -372,6 +372,14 @@ + org.netbeans.modules.xml.lexer + + + + 1.30 + + + org.netbeans.modules.xml.retriever @@ -403,7 +411,7 @@ 2 - 1.16 + 1.60 @@ -480,14 +488,6 @@ - org.openide.util.ui - - - - 9.3 - - - org.openide.util @@ -504,6 +504,14 @@ + org.openide.util.ui + + + + 9.3 + + + org.openide.windows @@ -582,6 +590,9 @@ org.openide.text + org.netbeans.modules.lexer.nbbridge + + org.openide.util.ui @@ -591,6 +602,11 @@ + + org.netbeans.modules.editor.mimelookup + + + diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletionContext.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletionContext.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletionContext.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletionContext.java @@ -48,20 +48,15 @@ import java.util.List; import javax.swing.text.BadLocationException; import javax.swing.text.Document; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenContextPath; -import org.netbeans.editor.TokenID; -import org.netbeans.editor.TokenItem; import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.modules.spring.beans.editor.DocumentContext; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.modules.xml.text.syntax.XMLKit; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; import org.netbeans.spi.editor.completion.CompletionProvider; import org.openide.filesystems.FileObject; import org.openide.util.Exceptions; @@ -73,7 +68,7 @@ * @author Rohan Ranade (Rohan.Ranade@Sun.COM) */ public class CompletionContext { - private ArrayList existingAttributes; + private List existingAttributes; public static enum CompletionType { TAG, @@ -97,10 +92,14 @@ this.caretOffset = caretOffset; this.fileObject = NbEditorUtilities.getFileObject(doc); this.queryType = queryType; - initContext((BaseDocument) doc); + try { + initContext((BaseDocument) doc); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } } - private void initContext(BaseDocument bDoc) { + private void initContext(BaseDocument bDoc) throws BadLocationException { boolean copyResult = copyDocument(bDoc, internalDoc); if(!copyResult) { return; @@ -108,57 +107,64 @@ Object sdp = bDoc.getProperty(Document.StreamDescriptionProperty); internalDoc.putProperty(Document.StreamDescriptionProperty, sdp); - this.support = (XMLSyntaxSupport) internalDoc.getSyntaxSupport(); + this.support = (XMLSyntaxSupport)XMLSyntaxSupport.getSyntaxSupport(internalDoc); this.documentContext = DocumentContext.create(internalDoc, caretOffset); // get last inserted character from the actual document - this.lastTypedChar = ((XMLSyntaxSupport) bDoc.getSyntaxSupport()).lastTypedChar(); + this.lastTypedChar = support.lastTypedChar(); if(documentContext == null) { return; } - TokenItem token = documentContext.getCurrentToken(); + Token token = documentContext.getCurrentToken(); if(token == null) { return; } + int tOffset = documentContext.getCurrentTokenOffset(); + String tokenText = token.text().toString(); + XMLTokenId id = token.id(); + int tlen = token.length(); + // see issue #191651 // ExtSyntaxSupport returns token on base of caretoffset and caretoffset+1 which // returns ERROR token at line ending (just "/" means error). In that cases // is fake WS token created with position between previous and current error // token for purposes of CC. Possibly will be extended about more characters. - if (token.getTokenID().getNumericID() == XMLDefaultTokenContext.ERROR_ID - && token.getImage().equals("/")) { - token = new WsToken(caretOffset, token); + if (token.id() == XMLTokenId.ERROR + && token.text().toString().equals("/")) { + tokenText = " "; + id = XMLTokenId.WS; + tlen = 1; + tOffset = caretOffset; } + boolean tokenBoundary = (tOffset == caretOffset) + || ((tOffset + tlen) == caretOffset); - boolean tokenBoundary = (token.getOffset() == caretOffset) - || ((token.getOffset() + token.getImage().length()) == caretOffset); - - int id = token.getTokenID().getNumericID(); SyntaxElement element = documentContext.getCurrentElement(); switch (id) { //user enters < character - case XMLDefaultTokenContext.TEXT_ID: - String chars = token.getImage().trim(); - TokenItem previousTokenItem = token.getPrevious(); + case TEXT: + String chars = tokenText.trim(); + Token previousTokenItem = support.getPreviousToken(tOffset); if (previousTokenItem == null) { completionType = CompletionType.NONE; break; } + String text = previousTokenItem.text().toString().trim(); if (chars != null && chars.equals("") && - previousTokenItem.getImage().trim().equals("/>")) { // NOI18N + text.equals("/>")) { // NOI18N completionType = CompletionType.NONE; break; } if (chars != null && chars.equals("") && - previousTokenItem.getImage().trim().equals(">")) { // NOI18N + text.trim().equals(">")) { // NOI18N completionType = CompletionType.VALUE; break; } if (chars != null && !chars.equals("<") && - previousTokenItem.getImage().trim().equals(">")) { // NOI18N + text.trim().equals(">")) { // NOI18N completionType = CompletionType.NONE; break; } @@ -169,44 +175,42 @@ break; //start tag of an element - case XMLDefaultTokenContext.TAG_ID: - if (element instanceof EndTag) { + case TAG: + if (support.isEndTag(element)) { completionType = CompletionType.NONE; break; } - if (element instanceof EmptyTag) { - if (token != null && - token.getImage().trim().equals("/>")) { // NOI18N - TokenItem prevToken = token.getPrevious(); - if(prevToken != null && prevToken.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID - && caretOffset == token.getOffset()) { + if (support.isEmptyTag(element)) { + if (tokenText.trim().equals("/>")) { // NOI18N + Token prevToken = support.getPreviousToken(tOffset); + if(prevToken != null && prevToken.id() == XMLTokenId.WS + && caretOffset == tOffset) { completionType = CompletionType.ATTRIBUTE; } else { completionType = CompletionType.NONE; } break; } - EmptyTag tag = (EmptyTag) element; if (element.getElementOffset() + 1 == this.caretOffset) { completionType = CompletionType.TAG; break; } + String tagName = element.getNode().getNodeName(); if (caretOffset > element.getElementOffset() + 1 && - caretOffset <= element.getElementOffset() + 1 + tag.getTagName().length()) { + caretOffset <= element.getElementOffset() + 1 + tagName.length()) { completionType = CompletionType.TAG; - typedChars = tag.getTagName(); + typedChars = tagName; break; } completionType = CompletionType.ATTRIBUTE; break; } - if (element instanceof StartTag) { - if (token != null && - token.getImage().trim().equals(">")) { // NOI18N - TokenItem prevToken = token.getPrevious(); - if(prevToken != null && prevToken.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID - && caretOffset == token.getOffset()) { + if (support.isStartTag(element)) { + if (tokenText.toString().trim().equals(">")) { // NOI18N + Token prevToken = support.getPreviousToken(tOffset); + if(prevToken != null && prevToken.id() == XMLTokenId.WS + && caretOffset == tOffset) { completionType = CompletionType.ATTRIBUTE; } else { completionType = CompletionType.NONE; @@ -214,8 +218,7 @@ break; } if (element.getElementOffset() + 1 != this.caretOffset) { - StartTag tag = (StartTag) element; - typedChars = tag.getTagName(); + typedChars = element.getNode().getNodeName(); } } if (lastTypedChar == '>') { @@ -226,43 +229,60 @@ break; //user enters an attribute name - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: completionType = CompletionType.ATTRIBUTE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset());; + typedChars = tokenText.substring(0, caretOffset - tOffset); break; //some random character - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: //user enters = character, we should ignore all other operators - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: completionType = CompletionType.NONE; break; //user enters either ' or " - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: if(!tokenBoundary) { completionType = CompletionType.ATTRIBUTE_VALUE; - typedChars = token.getImage().substring(1, caretOffset - token.getOffset()); + typedChars = tokenText.subSequence(1, caretOffset - tOffset).toString(); } else { completionType = CompletionType.NONE; } break; //user enters white-space character - case XMLDefaultTokenContext.WS_ID: + case WS: completionType = CompletionType.NONE; - - TokenItem prev = token.getPrevious(); - while (prev != null && - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID)) { - prev = prev.getPrevious(); + int[] offset = new int[1]; + Token prev = support.runWithSequence(tOffset, + (TokenSequence ts) -> { + Token t = null; + boolean ok; + while ((ok = ts.movePrevious())) { + t = ts.token(); + if (t.id() != XMLTokenId.WS) { + break; + } + } + if (ok) { + offset[0] = ts.offset(); + return t; + } else { + return null; + } + } + ); + if (prev == null) { + completionType = CompletionType.NONE; + break; } - - if(prev.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID - && prev.getOffset() + prev.getImage().length() == caretOffset) { - typedChars = prev.getImage(); + int prevOffset = offset[0]; + if(prev.id() == XMLTokenId.ARGUMENT + && prevOffset + prev.length() == caretOffset) { + typedChars = prev.text().toString(); completionType = CompletionType.ATTRIBUTE; - } else if (((prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) || - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID)) + } else if (((prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG)) && !tokenBoundary) { completionType = CompletionType.ATTRIBUTE; } @@ -286,6 +306,7 @@ try { String docText = src.getText(0, src.getLength()); dest.insertString(0, docText, null); +// dest.putProperty(Language.class, src.getProperty(Language.class)); } catch(BadLocationException ble) { Exceptions.printStackTrace(ble); retVal[0] = false; @@ -321,29 +342,43 @@ public Node getTag() { SyntaxElement element = documentContext.getCurrentElement(); - return (element instanceof Tag) ? (Node) element : null; + return element.getType() == Node.ELEMENT_NODE ? element.getNode() : null; } - public TokenItem getCurrentToken() { + public Token getCurrentToken() { return documentContext.getCurrentToken(); } + + public int getCurrentTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } + + private List getExistingAttributesLocked(TokenSequence ts) { + List existingAttributes = new ArrayList(); + while (ts.movePrevious()) { + Token item = ts.token(); + XMLTokenId tokenId = item.id(); + if (tokenId == XMLTokenId.TAG) { + break; + } + if (tokenId == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } + } + return existingAttributes; + } public List getExistingAttributes() { if (existingAttributes == null) { - existingAttributes = new ArrayList(); - TokenItem item = documentContext.getCurrentToken().getPrevious(); - while (item != null) { - int tokenId = item.getTokenID().getNumericID(); - if (tokenId == XMLDefaultTokenContext.TAG_ID) { - break; - } - if (tokenId == XMLDefaultTokenContext.ARGUMENT_ID) { - existingAttributes.add(item.getImage()); - } - item = item.getPrevious(); + try { + existingAttributes = (List)support.runWithSequence( + documentContext.getCurrentTokenOffset(), + this::getExistingAttributesLocked + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); } } - return existingAttributes; } @@ -362,45 +397,4 @@ public Document getDocument() { return internalDoc; } - - private class WsToken implements TokenItem { - - private final int caretOffset; - private final TokenItem currentToken; - - public WsToken(int caretOffset, TokenItem currentToken) { - this.caretOffset = caretOffset; - this.currentToken = currentToken; - } - - @Override - public TokenID getTokenID() { - return XMLDefaultTokenContext.WS; - } - - @Override - public TokenContextPath getTokenContextPath() { - return currentToken.getTokenContextPath(); - } - - @Override - public int getOffset() { - return caretOffset; - } - - @Override - public String getImage() { - return " "; - } - - @Override - public TokenItem getNext() { - return currentToken; - } - - @Override - public TokenItem getPrevious() { - return currentToken.getPrevious(); - } - } } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletorRegistry.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletorRegistry.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletorRegistry.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/CompletorRegistry.java @@ -55,7 +55,8 @@ import org.netbeans.modules.spring.beans.completion.completors.AttributeValueCompletorFactory; import java.util.HashMap; import java.util.Map; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.spring.beans.BeansAttributes; import org.netbeans.modules.spring.beans.BeansElements; import org.netbeans.modules.spring.beans.completion.completors.BeanDependsOnCompletor; @@ -177,8 +178,8 @@ private Completor getAttributeValueCompletor(CompletionContext context) { String tagName = extractVanilaTagName(context.getTag().getNodeName()); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; CompletorFactory completorFactory = locateCompletorFactory(tagName, attribName); if (completorFactory != null) { Completor completor = completorFactory.createCompletor(context.getCaretOffset()); diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/SpringXMLConfigCompletionProvider.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/SpringXMLConfigCompletionProvider.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/SpringXMLConfigCompletionProvider.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/SpringXMLConfigCompletionProvider.java @@ -55,9 +55,9 @@ import org.netbeans.modules.spring.beans.completion.CompletionContext.CompletionType; import org.netbeans.modules.spring.beans.editor.DocumentContext; import org.netbeans.modules.spring.beans.index.SpringIndex; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionResultSet; import org.netbeans.spi.editor.completion.CompletionTask; @@ -66,6 +66,8 @@ import org.openide.filesystems.FileObject; import org.openide.util.Exceptions; import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; /** * @@ -224,7 +226,7 @@ void updateSchemaLocation(Document doc, final int offset, final String namespace, final String schemaLocation) { BaseDocument baseDoc = (BaseDocument) doc; - final XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport) baseDoc.getSyntaxSupport(); + final XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(doc); baseDoc.runAtomic(new Runnable() { @@ -232,11 +234,13 @@ public void run() { try { SyntaxElement element = syntaxSupport.getElementChain(offset); - if (element instanceof StartTag) { - Attr attr = ((StartTag) element).getAttributeNode("xsi:schemaLocation"); //NOI18N + if (element.getType() == Node.ELEMENT_NODE && + ((TagElement)element).isStart()) { + NamedNodeMap nnm = element.getNode().getAttributes(); + Attr attr = (Attr)nnm.getNamedItem("xsi:schemaLocation"); //NOI18N if (attr != null) { String val = attr.getValue(); - if (val.indexOf(namespace) == -1) { + if (!val.contains(namespace)) { attr.setValue(val + "\n " + namespace + " " + schemaLocation); //NOI18N } } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/AttributeValueCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/AttributeValueCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/AttributeValueCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/AttributeValueCompletor.java @@ -67,7 +67,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - return context.getCurrentToken().getOffset() + 1; + return context.getCurrentTokenOffset() + 1; } @Override diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanDependsOnCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanDependsOnCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanDependsOnCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanDependsOnCompletor.java @@ -65,7 +65,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - int index = context.getCurrentToken().getOffset() + 1; + int index = context.getCurrentTokenOffset() + 1; String prefix = context.getTypedPrefix(); if (StringUtils.hasText(prefix)) { int sepOffset = Math.max(Math.max(prefix.lastIndexOf(','), prefix.lastIndexOf(';')), prefix.lastIndexOf(' ')); // NOI18N @@ -97,7 +97,7 @@ return Collections.emptySet(); } - int startIdx = context.getCurrentToken().getOffset() + 1; + int startIdx = context.getCurrentTokenOffset() + 1; int length = getAnchorOffset() - startIdx; if(length <= 0) { diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanIdCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanIdCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanIdCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeanIdCompletor.java @@ -84,7 +84,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - return context.getCurrentToken().getOffset() + 1; + return context.getCurrentTokenOffset() + 1; } @Override diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeansRefCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeansRefCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeansRefCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/BeansRefCompletor.java @@ -77,7 +77,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - return context.getCurrentToken().getOffset() + 1; + return context.getCurrentTokenOffset() + 1; } @Override diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaClassCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaClassCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaClassCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaClassCompletor.java @@ -86,7 +86,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - int idx = context.getCurrentToken().getOffset() + 1; + int idx = context.getCurrentTokenOffset() + 1; String typedChars = context.getTypedPrefix(); if(typedChars.contains(".") || typedChars.equals("")) { int dotIndex = typedChars.lastIndexOf("."); @@ -106,9 +106,9 @@ } if (typedChars.contains(".") || typedChars.equals("")) { // Switch to normal completion - doNormalJavaCompletion(js, typedChars, context.getCurrentToken().getOffset() + 1); + doNormalJavaCompletion(js, typedChars, context.getCurrentTokenOffset() + 1); } else { // Switch to smart class path completion - doSmartJavaCompletion(js, typedChars, context.getCurrentToken().getOffset() + 1, context.getQueryType()); + doSmartJavaCompletion(js, typedChars, context.getCurrentTokenOffset() + 1, context.getQueryType()); } } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaMethodCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaMethodCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaMethodCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaMethodCompletor.java @@ -74,7 +74,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - return context.getCurrentToken().getOffset() + 1; + return context.getCurrentTokenOffset() + 1; } @Override diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaPackageCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaPackageCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaPackageCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/JavaPackageCompletor.java @@ -71,7 +71,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - int idx = context.getCurrentToken().getOffset() + 1; + int idx = context.getCurrentTokenOffset() + 1; String typedChars = context.getTypedPrefix(); if (typedChars.contains(".") || typedChars.equals("")) { int dotIndex = typedChars.lastIndexOf("."); @@ -89,7 +89,7 @@ return; } - doPackageCompletion(js, typedChars, context.getCurrentToken().getOffset() + 1); + doPackageCompletion(js, typedChars, context.getCurrentTokenOffset() + 1); } private void doPackageCompletion(JavaSource js, final String typedPrefix, final int substitutionOffset) throws IOException { diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PNamespaceBeanRefCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PNamespaceBeanRefCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PNamespaceBeanRefCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PNamespaceBeanRefCompletor.java @@ -43,7 +43,8 @@ import java.io.IOException; import java.util.List; -import org.netbeans.editor.TokenItem; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.spring.beans.completion.CompletionContext; import org.netbeans.modules.spring.beans.completion.Completor; import org.netbeans.modules.spring.beans.completion.CompletorUtils; @@ -63,17 +64,17 @@ @Override protected int initAnchorOffset(CompletionContext context) { - return context.getCurrentToken().getOffset() + 1; + return context.getCurrentTokenOffset() + 1; } @Override protected void compute(CompletionContext context) throws IOException { - TokenItem attribToken = ContextUtilities.getAttributeToken(context.getCurrentToken()); + Token attribToken = ContextUtilities.getAttributeToken(context.getDocumentContext()); if (attribToken == null) { return; } - String attribName = attribToken.getImage(); + String attribName = attribToken.text().toString(); if (!ContextUtilities.isPNamespaceName(context.getDocumentContext(), attribName)) { return; } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PropertyCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PropertyCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PropertyCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/PropertyCompletor.java @@ -63,7 +63,7 @@ import org.netbeans.modules.spring.java.Property; import org.netbeans.modules.spring.java.PropertyFinder; import org.netbeans.modules.spring.java.PropertyType; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.w3c.dom.Node; /** * @@ -77,7 +77,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - int idx = context.getCurrentToken().getOffset() + 1; + int idx = context.getCurrentTokenOffset() + 1; String typedPrefix = context.getTypedPrefix(); int offset = typedPrefix.lastIndexOf('.'); // NOI18N return idx + offset + 1; @@ -97,7 +97,7 @@ js.runUserActionTask(new Task() { public void run(CompilationController cc) throws Exception { - Tag beanTag = (Tag) SpringXMLConfigEditorUtils.getBean(context.getTag()); + Node beanTag = SpringXMLConfigEditorUtils.getBean(context.getTag()); if (beanTag == null) { return; } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/ResourceCompletor.java b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/ResourceCompletor.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/ResourceCompletor.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/completion/completors/ResourceCompletor.java @@ -63,7 +63,7 @@ @Override protected int initAnchorOffset(CompletionContext context) { - int idx = context.getCurrentToken().getOffset() + 1; + int idx = context.getCurrentTokenOffset() + 1; String typedChars = context.getTypedPrefix(); int lastSlashIndex = typedChars.lastIndexOf("/"); // NOI18N return idx + lastSlashIndex + 1; diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/editor/ContextUtilities.java b/spring.beans/src/org/netbeans/modules/spring/beans/editor/ContextUtilities.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/editor/ContextUtilities.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/editor/ContextUtilities.java @@ -44,13 +44,15 @@ package org.netbeans.modules.spring.beans.editor; +import javax.swing.text.BadLocationException; import javax.xml.XMLConstants; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.openide.util.Exceptions; +import org.w3c.dom.Node; /** * @@ -74,9 +76,9 @@ return false; } - public static boolean isValueToken(TokenItem currentToken) { + public static boolean isValueToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) { + if (currentToken.id() == XMLTokenId.VALUE) { return true; } } @@ -84,9 +86,9 @@ return false; } - public static boolean isTagToken(TokenItem currentToken) { + public static boolean isTagToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) { + if (currentToken.id() == XMLTokenId.TAG) { return true; } } @@ -94,9 +96,9 @@ return false; } - public static boolean isAttributeToken(TokenItem currentToken) { + public static boolean isAttributeToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { + if (currentToken.id() == XMLTokenId.ARGUMENT) { return true; } } @@ -104,57 +106,14 @@ return false; } - public static TokenItem getAttributeToken(TokenItem currentToken) { - if(isValueToken(currentToken)) { - TokenItem equalsToken = currentToken.getPrevious(); - while(equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - TokenItem argumentToken = equalsToken.getPrevious(); - while(argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; - } - - return null; - } - - public static Tag getCurrentTagElement(DocumentContext context) { - SyntaxElement element = context.getCurrentElement(); - if(element instanceof StartTag) { - return (StartTag) element; - } else if(element instanceof EmptyTag) { - return (EmptyTag) element; - } - - return null; - } - - public static TokenItem getAttributeToken(DocumentContext context) { - if(isValueToken(context.getCurrentToken())) { - TokenItem equalsToken = context.getCurrentToken().getPrevious(); - while(equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - TokenItem argumentToken = equalsToken.getPrevious(); - while(argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; - } - - return null; + public static Token getAttributeToken(DocumentContext context) { + return context.getSyntaxSupport().getAttributeToken(context.getCurrentTokenOffset()); } public static String getAttributeTokenImage(DocumentContext context) { - TokenItem tok = getAttributeToken(context); + Token tok = getAttributeToken(context); if(tok != null) { - return tok.getImage(); + return tok.text().toString(); } return null; @@ -203,11 +162,12 @@ return nodeName.substring(0, colonIndex); } - public static StartTag getRoot(SyntaxElement se) { - StartTag root = null; + public static SyntaxElement getRoot(SyntaxElement se) { + SyntaxElement root = null; while( se != null) { - if(se instanceof StartTag) { - root = (StartTag)se; + if(se.getType() == Node.ELEMENT_NODE && + ((TagElement)se).isStart()) { + root = se; } se = se.getPrevious(); } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/editor/DocumentContext.java b/spring.beans/src/org/netbeans/modules/spring/beans/editor/DocumentContext.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/editor/DocumentContext.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/editor/DocumentContext.java @@ -50,13 +50,11 @@ import java.util.Map.Entry; import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Attr; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -72,7 +70,8 @@ private XMLSyntaxSupport syntaxSupport; private int caretOffset = -1; private SyntaxElement element; - private TokenItem token; + private Token token; + private int tokenOffset; private HashMap declaredNamespaces = new HashMap(); @@ -86,27 +85,41 @@ private DocumentContext(Document document, int caretOffset) throws BadLocationException { this.document = document; - this.syntaxSupport = (XMLSyntaxSupport) ((BaseDocument) document).getSyntaxSupport(); + this.syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); this.caretOffset = caretOffset; initialize(); } private void initialize() throws BadLocationException { element = syntaxSupport.getElementChain(caretOffset); - token = syntaxSupport.getTokenChain(caretOffset, Math.min(document.getLength(), caretOffset + 1)); + syntaxSupport.runWithSequence(caretOffset, + (TokenSequence ts) -> { + token = syntaxSupport.getNextToken(caretOffset); + tokenOffset = ts.offset(); + return null; + } + ); populateNamespaces(); } - - public int getCurrentTokenId() { - return token.getTokenID().getNumericID(); + + public XMLSyntaxSupport getSyntaxSupport() { + return syntaxSupport; + } + + public T runWithTokenSequence(int offset, XMLSyntaxSupport.SequenceCallable callable) throws BadLocationException { + return syntaxSupport.runWithSequence(offset, callable); } - public TokenItem getCurrentToken() { + public int getCurrentTokenOffset() { + return tokenOffset; + } + + public Token getCurrentToken() { return token; } public String getCurrentTokenImage() { - return token.getImage(); + return token.text().toString(); } public SyntaxElement getCurrentElement() { @@ -142,7 +155,7 @@ private void populateNamespaces() { // Find the a start or empty tag just before the current syntax element. SyntaxElement element = this.element; - while (element != null && !(element instanceof StartTag) && !(element instanceof EmptyTag)) { + while (element != null && !(syntaxSupport.isStartTag(element)) && !(syntaxSupport.isEmptyTag(element))) { element = element.getPrevious(); } if (element == null) { @@ -151,10 +164,10 @@ // To find all namespace declarations active at the caret offset, we // need to look at xmlns attributes of the current element and its ancestors. - Node node = (Node)element; - while (node != null) { - if (node instanceof StartTag || node instanceof EmptyTag) { - NamedNodeMap attributes = ((Tag)node).getAttributes(); + while (element != null) { + Node node = element.getNode(); + if (syntaxSupport.isStartTag(element) || syntaxSupport.isEmptyTag(element)) { + NamedNodeMap attributes = node.getAttributes(); for (int index = 0; index < attributes.getLength(); index++) { Attr attr = (Attr) attributes.item(index); String attrName = attr.getName(); @@ -172,7 +185,15 @@ } } } - node = node.getParentNode(); + element = element.getParentElement(); } } + + public int getNodeOffset(Node n) { + return syntaxSupport.getNodeOffset(n); + } + + public boolean isTag(SyntaxElement e) { + return syntaxSupport.isStartTag(e) || syntaxSupport.isEmptyTag(e) || syntaxSupport.isEndTag(e); + } } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/editor/SpringXMLConfigEditorUtils.java b/spring.beans/src/org/netbeans/modules/spring/beans/editor/SpringXMLConfigEditorUtils.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/editor/SpringXMLConfigEditorUtils.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/editor/SpringXMLConfigEditorUtils.java @@ -56,9 +56,9 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.StyledDocument; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.editor.ext.ExtSyntaxSupport; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.spring.api.Action; import org.netbeans.modules.spring.api.beans.model.Location; import org.netbeans.modules.spring.api.beans.model.SpringBean; @@ -68,11 +68,9 @@ import org.netbeans.modules.spring.beans.BeansAttributes; import org.netbeans.modules.spring.beans.BeansElements; import org.netbeans.modules.spring.beans.utils.StringUtils; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.cookies.EditorCookie; import org.openide.cookies.LineCookie; import org.openide.cookies.OpenCookie; @@ -133,7 +131,7 @@ return "set" + String.valueOf(buffer); // NOI18N } - public static String getBeanFactoryMethod(Tag tag) { + public static String getBeanFactoryMethod(Node tag) { Node bean = getBean(tag); if (bean != null) { NamedNodeMap attribs = bean.getAttributes(); @@ -184,32 +182,40 @@ return null; } - public static final Tag getDocumentRoot(Document doc) { - Tag retTag = null; + public static final Node getDocumentRoot(Document doc) { + Node retTag = null; // Temporary fix for IZ#155008 until Lexer migration XMLSyntaxSupport syntaxSupport = null; try { - syntaxSupport = (XMLSyntaxSupport) ((BaseDocument) doc).getSyntaxSupport(); + syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(doc); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - syntaxSupport = new XMLSyntaxSupport(((BaseDocument)doc)); + syntaxSupport = XMLSyntaxSupport.createSyntaxSupport(doc); } if (syntaxSupport == null) return retTag; try { - TokenItem tok = syntaxSupport.getTokenChain(0,1); + Token tok = syntaxSupport.getNextToken(1); if(tok != null) { - TokenItem prevTok = null; - while((!ContextUtilities.isTagToken(tok)) && (tok != prevTok) ) { - prevTok = tok; - if (tok.getNext() != null) { - tok = tok.getNext(); + int off = syntaxSupport.runWithSequence(0, (TokenSequence s) -> { + s.move(0); + while (s.moveNext()) { + Token t = s.token(); + if (ContextUtilities.isTagToken(t)) { + return s.offset() + t.length(); + } } + return -1; + }); + if (off == -1) { + return null; } - SyntaxElement element = syntaxSupport.getElementChain(tok.getOffset()+tok.getImage().length()); - if(element instanceof StartTag || element instanceof EmptyTag) { - Tag tag = (Tag) element; - if(tag.getParentNode() instanceof org.w3c.dom.Document) { - return tag; + SyntaxElement element = syntaxSupport.getElementChain(off); + if (element != null && element.getType() == Node.ELEMENT_NODE) { + TagElement te = (TagElement)element; + if (te.isStart() || te.isSelfClosing()) { + if(te.getNode().getParentNode() instanceof org.w3c.dom.Document) { + return te.getNode(); + } } } } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/HyperlinkEnv.java b/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/HyperlinkEnv.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/HyperlinkEnv.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/HyperlinkEnv.java @@ -47,14 +47,14 @@ import java.util.HashMap; import java.util.Map; import javax.swing.text.Document; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.modules.spring.beans.editor.ContextUtilities; import org.netbeans.modules.spring.beans.editor.DocumentContext; import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; import org.openide.filesystems.FileObject; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -110,7 +110,7 @@ } private void initialize() { - Tag currentTag = null; + SyntaxElement currentTag = null; DocumentContext documentContext = DocumentContext.create(baseDocument, offset); if (documentContext == null) { return; @@ -118,43 +118,43 @@ declaredNamespaces = documentContext.getDeclaredNamespacesMap(); - TokenItem token = documentContext.getCurrentToken(); + Token token = documentContext.getCurrentToken(); if (token == null) { return; } - tokenStartOffset = token.getOffset(); - tokenEndOffset = tokenStartOffset + token.getImage().length(); - tokenImage = token.getImage(); + tokenStartOffset = documentContext.getCurrentTokenOffset(); + tokenEndOffset = tokenStartOffset + token.length(); + tokenImage = token.text().toString(); if (ContextUtilities.isValueToken(token) || ContextUtilities.isAttributeToken(documentContext.getCurrentToken())) { SyntaxElement element = documentContext.getCurrentElement(); - if (element instanceof Tag) { - currentTag = (Tag) element; + if (documentContext.isTag(element)) { + currentTag = element; } else { return; } - Tag beanTag = (Tag) SpringXMLConfigEditorUtils.getBean(currentTag); + Node beanTag = SpringXMLConfigEditorUtils.getBean(currentTag.getNode()); if (beanTag != null) { - beanTagOffset = beanTag.getElementOffset(); + beanTagOffset = documentContext.getNodeOffset(beanTag); beanAttribs = collectAttributes(beanTag); } - tagName = currentTag.getNodeName(); + tagName = currentTag.getNode().getNodeName(); } if (ContextUtilities.isValueToken(token)) { type = Type.ATTRIB_VALUE; attribName = ContextUtilities.getAttributeTokenImage(documentContext); - valueString = token.getImage(); + valueString = token.text().toString(); valueString = valueString.substring(1, valueString.length() - 1); // Strip quotes } else if (ContextUtilities.isAttributeToken(documentContext.getCurrentToken())) { type = Type.ATTRIB; - attribName = token.getImage(); + attribName = token.text().toString(); } } - private Map collectAttributes(Tag currentTag) { + private Map collectAttributes(Node currentTag) { Map attribsMap = new HashMap(); NamedNodeMap attribsNodeMap = currentTag.getAttributes(); for(int i = 0; i < attribsNodeMap.getLength(); i++) { diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/SpringXMLConfigHyperlinkProvider.java b/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/SpringXMLConfigHyperlinkProvider.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/SpringXMLConfigHyperlinkProvider.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/hyperlink/SpringXMLConfigHyperlinkProvider.java @@ -55,7 +55,7 @@ import org.netbeans.modules.spring.beans.utils.StringUtils; import org.netbeans.modules.spring.java.Public; import org.netbeans.modules.spring.java.Static; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; /** * Provides hyperlinking functionality for Spring XML Configuration files @@ -124,9 +124,7 @@ if (!(document instanceof BaseDocument)) { return false; } - - BaseDocument doc = (BaseDocument) document; - if (!(doc.getSyntaxSupport() instanceof XMLSyntaxSupport)) { + if (XMLSyntaxSupport.getSyntaxSupport(document) == null) { return false; } diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/model/impl/ConfigFileSpringBeanSource.java b/spring.beans/src/org/netbeans/modules/spring/beans/model/impl/ConfigFileSpringBeanSource.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/model/impl/ConfigFileSpringBeanSource.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/model/impl/ConfigFileSpringBeanSource.java @@ -67,7 +67,7 @@ import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils; import org.netbeans.modules.spring.beans.model.SpringBeanSource; import org.netbeans.modules.spring.beans.utils.StringUtils; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.w3c.dom.NamedNodeMap; @@ -145,6 +145,8 @@ private static final String REF_SUFFIX = "-ref"; // NOI18N private static final String NULL_PREFIX = "null_prefix"; + + private XMLSyntaxSupport support; public DocumentParser(File file, Document document) { this.file = file; @@ -160,6 +162,7 @@ if (rootNode == null) { return; } + support = XMLSyntaxSupport.getSyntaxSupport(document); NodeList childNodes = rootNode.getChildNodes(); // prefixesMap caches the prefixes for tag nemes @@ -198,8 +201,8 @@ String parent = getTrimmedAttr(node, BeansAttributes.PARENT); String factoryBean = getTrimmedAttr(node, BeansAttributes.FACTORY_BEAN); String factoryMethod = getTrimmedAttr(node, BeansAttributes.FACTORY_METHOD); - Tag tag = (Tag)node; - Location location = new ConfigFileLocation(FileUtil.toFileObject(file), tag.getElementOffset()); + Location location = new ConfigFileLocation(FileUtil.toFileObject(file), + support.getNodeOffset(node)); Set properties = parseBeanProperties(node, prefixesMap); ConfigFileSpringBean bean = new ConfigFileSpringBean(id, names, clazz, parent, factoryBean, factoryMethod, properties, location); if (id != null) { @@ -227,10 +230,11 @@ } // P Namespace items - String tagName = ((Tag)node).getTagName(); + String tagName = node.getNodeName(); String prefix = prefixesMap.get(tagName); if (prefix == null) { - prefix = SpringXMLConfigEditorUtils.getPNamespacePrefix(document, ((Tag)node).getElementOffset()); + prefix = SpringXMLConfigEditorUtils.getPNamespacePrefix(document, + support.getNodeOffset(node)); if (prefix == null) { // this is caching the case when prefix declaration is missing prefixesMap.put(tagName, NULL_PREFIX); diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeFinder.java b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeFinder.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeFinder.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeFinder.java @@ -42,11 +42,10 @@ package org.netbeans.modules.spring.beans.refactoring; import javax.swing.text.BadLocationException; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenID; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; /** * @@ -65,27 +64,27 @@ public boolean find(String attrName) throws BadLocationException { foundOffset = -1; - BaseDocument doc = syntaxSupport.getDocument(); - TokenItem item = syntaxSupport.getTokenChain(start, Math.min(start + 1, doc.getLength())); - if (item == null || item.getTokenID() != XMLDefaultTokenContext.TAG) { + Token item = syntaxSupport.getNextToken(start); + if (item == null || item.id() != XMLTokenId.TAG) { return false; } - item = item.getNext(); - String currentAttrName = null; - while (item != null) { - TokenID id = item.getTokenID(); - if (id == XMLDefaultTokenContext.ARGUMENT) { - currentAttrName = item.getImage(); - if (currentAttrName != null && currentAttrName.equals(attrName)) { - foundOffset = item.getOffset(); - return true; + return syntaxSupport.runWithSequence(start, (TokenSequence s) -> { + String currentAttrName = null; + while (s.moveNext()) { + Token t = s.token(); + XMLTokenId id = t.id(); + if (id == XMLTokenId.ARGUMENT) { + currentAttrName = t.text().toString(); + if (currentAttrName != null && currentAttrName.equals(attrName)) { + foundOffset = s.offset(); + return true; + } + } else if (id == XMLTokenId.TAG) { + break; } - } else if (id == XMLDefaultTokenContext.TAG) { - break; - } - item = item.getNext(); - } - return false; + } + return false; + }); } public int getFoundOffset() { diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeValueFinder.java b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeValueFinder.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeValueFinder.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/AttributeValueFinder.java @@ -45,12 +45,11 @@ package org.netbeans.modules.spring.beans.refactoring; import javax.swing.text.BadLocationException; -import org.netbeans.editor.BaseDocument; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.SyntaxSupport; -import org.netbeans.editor.TokenID; -import org.netbeans.editor.TokenItem; -import org.netbeans.editor.ext.ExtSyntaxSupport; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; /** * @@ -58,47 +57,51 @@ */ public class AttributeValueFinder { - private final SyntaxSupport syntaxSupport; + private final XMLSyntaxSupport xmlSupport; private final int start; private int foundOffset = -1; private String foundValue; public AttributeValueFinder(SyntaxSupport syntaxSupport, int start) { - this.syntaxSupport = syntaxSupport; this.start = start; + this.xmlSupport = XMLSyntaxSupport.getSyntaxSupport(syntaxSupport.getDocument()); + } + + public AttributeValueFinder(XMLSyntaxSupport syntaxSupport, int start) { + this.start = start; + this.xmlSupport = syntaxSupport; } public boolean find(String attrName) throws BadLocationException { foundOffset = -1; foundValue = null; - BaseDocument doc = syntaxSupport.getDocument(); - if (!(syntaxSupport instanceof ExtSyntaxSupport)) { + if (xmlSupport == null) { return false; } - - TokenItem item = ((ExtSyntaxSupport) syntaxSupport).getTokenChain(start, Math.min(start + 1, doc.getLength())); - if (item == null || item.getTokenID() != XMLDefaultTokenContext.TAG) { + Token item = xmlSupport.getNextToken(start); + if (item == null || item.id() != XMLTokenId.TAG) { return false; } - item = item.getNext(); - String currentAttrName = null; - while (item != null) { - TokenID id = item.getTokenID(); - if (id == XMLDefaultTokenContext.ARGUMENT) { - currentAttrName = item.getImage(); - } else if (id == XMLDefaultTokenContext.VALUE) { - if (currentAttrName != null && currentAttrName.equals(attrName)) { - foundOffset = item.getOffset(); - foundValue = item.getImage(); - return true; + return xmlSupport.runWithSequence(start, (TokenSequence s) -> { + String currentAttrName = null; + while (s.moveNext()) { + Token t = s.token(); + XMLTokenId id = t.id(); + if (id == XMLTokenId.ARGUMENT) { + currentAttrName = t.text().toString(); + } else if (id == XMLTokenId.VALUE) { + if (currentAttrName != null && currentAttrName.equals(attrName)) { + foundOffset = s.offset(); + foundValue = t.text().toString(); + return true; + } + } else if (id == XMLTokenId.TAG) { + break; } - } else if (id == XMLDefaultTokenContext.TAG) { - break; } - item = item.getNext(); - } - return false; + return false; + }); } public int getFoundOffset() { diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyChildFinder.java b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyChildFinder.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyChildFinder.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyChildFinder.java @@ -47,10 +47,8 @@ import org.netbeans.modules.spring.beans.BeansElements; import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils; import org.netbeans.modules.spring.beans.utils.StringUtils; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -74,11 +72,11 @@ foundOffset = -1; value = null; SyntaxElement beanElement = syntaxSupport.getElementChain(start+1); - if(!(beanElement instanceof StartTag)) { + if (!syntaxSupport.isStartTag(beanElement)) { return false; } - Tag beanTag = (Tag) beanElement; + Node beanTag = beanElement.getNode(); if(!BeansElements.BEAN.equals(beanTag.getNodeName())) { return false; } @@ -89,8 +87,9 @@ if(BeansElements.PROPERTY.equals(n.getNodeName())) { String name = SpringXMLConfigEditorUtils.getAttribute(n, BeansAttributes.NAME); if(StringUtils.hasText(name) && propertyName.equals(name)) { - Tag propertyTag = (Tag) n; - AttributeValueFinder delegate = new AttributeValueFinder(syntaxSupport, propertyTag.getElementOffset()); + AttributeValueFinder delegate = new AttributeValueFinder( + syntaxSupport, + syntaxSupport.getNodeOffset(n)); boolean retVal = delegate.find(BeansAttributes.NAME); foundOffset = delegate.getFoundOffset(); value = delegate.getValue(); diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyRefFinder.java b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyRefFinder.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyRefFinder.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/refactoring/PropertyRefFinder.java @@ -50,6 +50,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import javax.swing.text.Position.Bias; import org.netbeans.api.java.source.CompilationController; import org.netbeans.api.java.source.ElementHandle; @@ -68,7 +69,7 @@ import org.netbeans.modules.spring.java.Property; import org.netbeans.modules.spring.java.PropertyFinder; import org.netbeans.modules.spring.java.PropertyType; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.filesystems.FileObject; import org.openide.text.PositionBounds; import org.openide.text.PositionRef; @@ -88,7 +89,7 @@ public PropertyRefFinder(DocumentAccess docAccess, CompilationController cc, RenamedProperty renamedProperty) { this.docAccess = docAccess; BaseDocument document = (BaseDocument) docAccess.getDocument(); - syntaxSupport = (XMLSyntaxSupport) document.getSyntaxSupport(); + syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); this.cc = cc; this.renamedProperty = renamedProperty; } @@ -203,7 +204,7 @@ } // p-namespace - BaseDocument document = syntaxSupport.getDocument(); + Document document = syntaxSupport.getDocument(); String prefix = SpringXMLConfigEditorUtils.getPNamespacePrefix(document, beanOffset); if (prefix == null) { return; diff --git a/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/TestUtils.java b/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/TestUtils.java --- a/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/TestUtils.java +++ b/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/TestUtils.java @@ -51,6 +51,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import org.netbeans.api.lexer.Language; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; import org.netbeans.modules.spring.api.beans.SpringConstants; import org.openide.filesystems.FileUtil; @@ -92,6 +94,7 @@ public static BaseDocument createSpringXMLConfigDocument(String content) throws Exception { Class kitClass = CloneableEditorSupport.getEditorKit(SpringConstants.CONFIG_MIME_TYPE).getClass(); BaseDocument doc = new BaseDocument(kitClass, false); + doc.putProperty(Language.class, XMLTokenId.language()); doc.insertString(0, content, null); return doc; } diff --git a/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/completion/CompletionContextTest.java b/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/completion/CompletionContextTest.java --- a/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/completion/CompletionContextTest.java +++ b/spring.beans/test/unit/src/org/netbeans/modules/spring/beans/completion/CompletionContextTest.java @@ -44,8 +44,11 @@ package org.netbeans.modules.spring.beans.completion; -import junit.framework.TestCase; +import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.api.editor.mimelookup.test.MockMimeLookup; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; +import org.netbeans.junit.NbTestCase; import org.netbeans.modules.spring.beans.TestUtils; import org.netbeans.modules.spring.beans.completion.CompletionContext.CompletionType; import static org.netbeans.spi.editor.completion.CompletionProvider.COMPLETION_QUERY_TYPE; @@ -54,7 +57,17 @@ * * @author Rohan Ranade (Rohan.Ranade@Sun.COM) */ -public class CompletionContextTest extends TestCase { +public class CompletionContextTest extends NbTestCase { + + public CompletionContextTest(String name) { + super(name); + } + + @Override + protected void setUp() throws Exception { + MockMimeLookup.setInstances(MimePath.parse("text/xml"), XMLTokenId.language()); + super.setUp(); + } public void testAttributeValueCompletion() throws Exception { String config = TestUtils.createXMLConfigText(""); BaseDocument doc = TestUtils.createSpringXMLConfigDocument(contents); - final XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport)doc.getSyntaxSupport(); + final XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(doc); doc.render(new Runnable() { public void run() { int beanOffset = contents.indexOf(""); BaseDocument doc = TestUtils.createSpringXMLConfigDocument(contents); - final XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport)doc.getSyntaxSupport(); + final XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(doc); doc.render(new Runnable() { public void run() { int beanOffset = contents.indexOf(""); BaseDocument doc = TestUtils.createSpringXMLConfigDocument(contents); - final XMLSyntaxSupport syntaxSupport = (XMLSyntaxSupport)doc.getSyntaxSupport(); + final XMLSyntaxSupport syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(doc); doc.render(new Runnable() { public void run() { diff --git a/web.beans/nbproject/project.properties b/web.beans/nbproject/project.properties --- a/web.beans/nbproject/project.properties +++ b/web.beans/nbproject/project.properties @@ -40,7 +40,7 @@ # Version 2 license, then the option applies only if the new code is # made subject to such option by the copyright holder -javac.source=1.7 +javac.source=1.8 requires.nb.javac=true test-unit-sys-prop.java.awt.headless=true diff --git a/web.beans/nbproject/project.xml b/web.beans/nbproject/project.xml --- a/web.beans/nbproject/project.xml +++ b/web.beans/nbproject/project.xml @@ -280,6 +280,14 @@ + org.netbeans.modules.xml.lexer + + + + 1.30 + + + org.netbeans.modules.xml.retriever @@ -364,14 +372,6 @@ - org.openide.util.ui - - - - 9.3 - - - org.openide.util @@ -388,6 +388,14 @@ + org.openide.util.ui + + + + 9.3 + + + org.openide.windows diff --git a/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletionManager.java b/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletionManager.java --- a/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletionManager.java +++ b/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletionManager.java @@ -46,9 +46,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.w3c.dom.Node; /** * This class figures out the completion items for various attributes @@ -88,8 +90,8 @@ } String tagName = context.getTag().getNodeName(); - TokenItem attrib = ContextUtilities.getAttributeToken(context.getCurrentToken()); - String attribName = attrib != null ? attrib.getImage() : null; + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; BeansCompletor completor = locateCompletor(tagName, attribName); if (completor != null) { @@ -108,7 +110,7 @@ SyntaxElement curElem = docContext.getCurrentElement(); SyntaxElement prevElem = docContext.getCurrentElement().getPrevious(); - String tagName = (curElem instanceof StartTag) ? ((StartTag) curElem).getTagName() : ((prevElem instanceof StartTag) ? ((StartTag) prevElem).getTagName() : null); + String tagName = curElem.getType() == Node.ELEMENT_NODE ? curElem.getNode().getNodeName() : null; BeansCompletor completor = locateCompletor(tagName, null); if (completor != null) { valueItems.addAll(completor.doCompletion(context)); diff --git a/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletor.java b/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletor.java --- a/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletor.java +++ b/web.beans/src/org/netbeans/modules/web/beans/completion/BeansCompletor.java @@ -108,7 +108,7 @@ return Collections.emptyList(); } FileObject fo = NbEditorUtilities.getFileObject(context.getDocument()); - doJavaCompletion(fo, js, results, typedChars, context.getCurrentToken().getOffset()); + doJavaCompletion(fo, js, results, typedChars, context.getCurrentTokenOffset()); } catch (IOException ex) { Exceptions.printStackTrace(ex); } diff --git a/web.beans/src/org/netbeans/modules/web/beans/completion/CompletionContext.java b/web.beans/src/org/netbeans/modules/web/beans/completion/CompletionContext.java --- a/web.beans/src/org/netbeans/modules/web/beans/completion/CompletionContext.java +++ b/web.beans/src/org/netbeans/modules/web/beans/completion/CompletionContext.java @@ -48,16 +48,14 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.openide.util.Exceptions; import org.w3c.dom.Node; import org.w3c.dom.Text; @@ -65,7 +63,7 @@ * Tracks context information for a code completion scenario */ public class CompletionContext { - private ArrayList existingAttributes; + private List existingAttributes; public static enum CompletionType { TAG, @@ -89,49 +87,61 @@ this.caretOffset = caretOffset; try { - this.support = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport(); + this.support = XMLSyntaxSupport.getSyntaxSupport(doc); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.support = new XMLSyntaxSupport(((BaseDocument)doc)); + this.support = XMLSyntaxSupport.createSyntaxSupport(doc); } this.documentContext = EditorContextFactory.getDocumentContext(doc, caretOffset); this.lastTypedChar = support.lastTypedChar(); - initContext(); + try { + initContext(); + } catch (BadLocationException ex) { + // ignore + } } - private void initContext() { - TokenItem token = documentContext.getCurrentToken(); + private void initContext() throws BadLocationException { + Token token = documentContext.getCurrentToken(); if(token == null) return; - boolean tokenBoundary = (token.getOffset() == caretOffset) - || ((token.getOffset() + token.getImage().length()) == caretOffset); + boolean tokenBoundary = (documentContext.getCurrentTokenOffset() == caretOffset) + || ((documentContext.getCurrentTokenOffset() + token.length()) == caretOffset); - int id = token.getTokenID().getNumericID(); + XMLTokenId id = token.id(); SyntaxElement element = documentContext.getCurrentElement(); + String chars = token.text().toString().trim(); + int tOffset = documentContext.getCurrentTokenOffset(); + switch (id) { // - case XMLDefaultTokenContext.TEXT_ID: - String chars = token.getImage().trim(); + case TEXT: + Token previousTokenItem = support.getPreviousToken(tOffset); + if (previousTokenItem == null) { + completionType = CompletionType.NONE; + break; + } + String text = previousTokenItem.text().toString().trim(); if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals("/>")) { // NOI18N + text.equals("/>")) { // NOI18N completionType = CompletionType.NONE; break; } if (chars != null && chars.equals("") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.VALUE; break; } if (chars != null && !chars.startsWith("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.VALUE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset()); + typedChars = chars.substring(0, caretOffset - tOffset); break; } if (chars != null && !chars.equals("<") && - token.getPrevious().getImage().trim().equals(">")) { // NOI18N + text.equals(">")) { // NOI18N completionType = CompletionType.NONE; break; } @@ -142,54 +152,53 @@ break; //start tag of an element - case XMLDefaultTokenContext.TAG_ID: - if (element instanceof EndTag) { + case TAG: + String tagName = element.getNode().getNodeName(); + if (support.isEndTag(element)) { completionType = CompletionType.NONE; break; } - if (element instanceof EmptyTag) { - if (token != null && - token.getImage().trim().equals("/>")) { + if (support.isEmptyTag(element)) { + if (chars.trim().equals("/>")) { completionType = CompletionType.NONE; break; } - EmptyTag tag = (EmptyTag) element; if (element.getElementOffset() + 1 == this.caretOffset) { completionType = CompletionType.TAG; break; } if (caretOffset > element.getElementOffset() + 1 && - caretOffset <= element.getElementOffset() + 1 + tag.getTagName().length()) { + caretOffset <= element.getElementOffset() + 1 + tagName.length()) { completionType = CompletionType.TAG; - typedChars = tag.getTagName(); + typedChars = tagName; break; } completionType = CompletionType.ATTRIBUTE; break; } - if (element instanceof StartTag) { + if (support.isStartTag(element)) { if (token != null && - token.getImage().trim().equals(">")) { + chars.equals(">")) { completionType = CompletionType.NONE; break; } if (token != null && - token.getImage().trim().startsWith(" previous = support.getPreviousToken(tOffset); + typedChars = previous.text().toString().trim(); completionType = CompletionType.VALUE; break; } @@ -203,41 +212,40 @@ break; //user enters an attribute name - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: completionType = CompletionType.ATTRIBUTE; - typedChars = token.getImage().substring(0, caretOffset - token.getOffset());; + typedChars = chars.substring(0, caretOffset - tOffset); break; //some random character - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: //user enters = character, we should ignore all other operators - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: completionType = CompletionType.NONE; break; //user enters either ' or " - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: if(!tokenBoundary) { completionType = CompletionType.ATTRIBUTE_VALUE; - typedChars = token.getImage().substring(1, caretOffset - token.getOffset()); + typedChars = chars.substring(1, caretOffset - tOffset); } else { completionType = CompletionType.NONE; } break; //user enters white-space character - case XMLDefaultTokenContext.WS_ID: + case WS: completionType = CompletionType.NONE; - TokenItem prev = token.getPrevious(); - while (prev != null && - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID)) { - prev = prev.getPrevious(); + Token prev = support.skip(tOffset, false, XMLTokenId.WS); + if (prev == null) { + completionType = CompletionType.NONE; + break; } - - if(prev.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { - typedChars = prev.getImage(); + if(prev.id() == XMLTokenId.ARGUMENT) { + typedChars = prev.text().toString(); completionType = CompletionType.ATTRIBUTE; - } else if ((prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) || - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID)) { + } else if ((prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG)) { completionType = CompletionType.ATTRIBUTE; } break; @@ -270,27 +278,42 @@ public Node getTag() { SyntaxElement element = documentContext.getCurrentElement(); - return (element instanceof Tag) ? (Node) element : null; + return element.getType() == Node.ELEMENT_NODE ? element.getNode() : null; } - public TokenItem getCurrentToken() { + public Token getCurrentToken() { return documentContext.getCurrentToken(); } + public int getCurrentTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } + + private List getExistingAttributesLocked(TokenSequence ts) { + List existingAttributes = new ArrayList(); + while (ts.movePrevious()) { + Token item = ts.token(); + XMLTokenId tokenId = item.id(); + if (tokenId == XMLTokenId.TAG) { + break; + } + if (tokenId == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } + } + return existingAttributes; + } + public List getExistingAttributes() { - if(existingAttributes != null) - return existingAttributes; - existingAttributes = new ArrayList(); - TokenItem item = documentContext.getCurrentToken().getPrevious(); - while(item != null) { - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.TAG_ID) - break; - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.ARGUMENT_ID) { - existingAttributes.add(item.getImage()); + if (existingAttributes == null) { + try { + existingAttributes = (List)support.runWithSequence( + documentContext.getCurrentTokenOffset(), + this::getExistingAttributesLocked + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); } - item = item.getPrevious(); } return existingAttributes; } diff --git a/web.beans/src/org/netbeans/modules/web/beans/completion/ContextUtilities.java b/web.beans/src/org/netbeans/modules/web/beans/completion/ContextUtilities.java --- a/web.beans/src/org/netbeans/modules/web/beans/completion/ContextUtilities.java +++ b/web.beans/src/org/netbeans/modules/web/beans/completion/ContextUtilities.java @@ -44,13 +44,17 @@ package org.netbeans.modules.web.beans.completion; +import javax.swing.text.BadLocationException; import javax.xml.XMLConstants; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import static org.netbeans.api.xml.lexer.XMLTokenId.ARGUMENT; +import static org.netbeans.api.xml.lexer.XMLTokenId.OPERATOR; import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.w3c.dom.Node; /** * @@ -61,9 +65,9 @@ private ContextUtilities() { } - public static boolean isValueToken(TokenItem currentToken) { + public static boolean isValueToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) { + if (currentToken.id() == XMLTokenId.VALUE) { return true; } } @@ -71,9 +75,9 @@ return false; } - public static boolean isTagToken(TokenItem currentToken) { + public static boolean isTagToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) { + if (currentToken.id() == XMLTokenId.TAG) { return true; } } @@ -81,9 +85,9 @@ return false; } - public static boolean isAttributeToken(TokenItem currentToken) { + public static boolean isAttributeToken(Token currentToken) { if(currentToken != null) { - if (currentToken.getTokenID().getNumericID() == XMLDefaultTokenContext.ARGUMENT_ID) { + if (currentToken.id() == XMLTokenId.ARGUMENT) { return true; } } @@ -91,88 +95,17 @@ return false; } - public static TokenItem getAttributeToken(TokenItem currentToken) { - if(currentToken == null ) + public static Token getAttributeToken(DocumentContext context) { + if(context.getCurrentToken() == null ) { return null; - - if(isValueToken(currentToken)) { - TokenItem equalsToken = currentToken.getPrevious(); - if(equalsToken == null) - return null; - - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; } - - return null; + return context.getSyntaxSupport().getAttributeToken(context.getCurrentTokenOffset()); } - - public static Tag getCurrentTagElement(DocumentContext context) { - SyntaxElement element = context.getCurrentElement(); - if(element instanceof StartTag) { - return (StartTag) element; - } else if(element instanceof EmptyTag) { - return (EmptyTag) element; - } - - return null; - } - - public static TokenItem getAttributeToken(DocumentContext context) { - if(context.getCurrentToken() == null ) - return null; - - if(isValueToken(context.getCurrentToken())) { - TokenItem equalsToken = context.getCurrentToken().getPrevious(); - if(equalsToken == null) - return null; - - //getTokenId() should not return null by JavaDoc. But in reality, it does reutrn null sometimes - // see issue 67661 - if(equalsToken.getTokenID() == null) { - return null; - } - while(equalsToken != null && equalsToken.getTokenID().getNumericID() != XMLDefaultTokenContext.OPERATOR_ID) { - equalsToken = equalsToken.getPrevious(); - } - - if(equalsToken == null) { - return null; - } - - TokenItem argumentToken = equalsToken.getPrevious(); - if(argumentToken == null) - return null; - - while(argumentToken != null && argumentToken.getTokenID().getNumericID() != XMLDefaultTokenContext.ARGUMENT_ID) { - argumentToken = argumentToken.getPrevious(); - } - - return argumentToken; - } - - return null; - } - + public static String getAttributeTokenImage(DocumentContext context) { - TokenItem tok = getAttributeToken(context); + Token tok = getAttributeToken(context); if(tok != null) { - return tok.getImage(); + return tok.text().toString(); } return null; @@ -221,11 +154,12 @@ return nodeName.substring(0, colonIndex); } - public static StartTag getRoot(SyntaxElement se) { - StartTag root = null; + public static SyntaxElement getRoot(SyntaxElement se) { + SyntaxElement root = null; while( se != null) { - if(se instanceof StartTag) { - root = (StartTag)se; + if(se.getType() == Node.ELEMENT_NODE && + ((TagElement)se).isStart()) { + root = se; } se = se.getPrevious(); } diff --git a/web.beans/src/org/netbeans/modules/web/beans/completion/DocumentContext.java b/web.beans/src/org/netbeans/modules/web/beans/completion/DocumentContext.java --- a/web.beans/src/org/netbeans/modules/web/beans/completion/DocumentContext.java +++ b/web.beans/src/org/netbeans/modules/web/beans/completion/DocumentContext.java @@ -55,14 +55,12 @@ import java.util.logging.Logger; import javax.swing.text.BadLocationException; import javax.swing.text.Document; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.w3c.dom.Attr; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -83,9 +81,10 @@ private XMLSyntaxSupport syntaxSupport; private int caretOffset = -1; private SyntaxElement element; - private TokenItem token; + private Token token; + private int tokenOffset; private boolean valid = false; - private StartTag docRoot; + private SyntaxElement docRoot; private String defaultNamespace; private HashMap declaredNamespaces = new HashMap(); @@ -95,10 +94,10 @@ DocumentContext(Document document) { this.document = document; try { - this.syntaxSupport = (XMLSyntaxSupport) ((BaseDocument)document).getSyntaxSupport(); + this.syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); } catch (ClassCastException cce) { LOGGER.log(Level.FINE, cce.getMessage()); - this.syntaxSupport = new XMLSyntaxSupport(((BaseDocument)document)); + this.syntaxSupport = XMLSyntaxSupport.createSyntaxSupport(document); } } @@ -112,7 +111,9 @@ declaredNamespaces.clear(); try { element = syntaxSupport.getElementChain(caretOffset); - token = syntaxSupport.getTokenChain(caretOffset, Math.min(document.getLength(), caretOffset+1)); + int[] bounds = new int[1]; + token = syntaxSupport.getTokenAtPosition(caretOffset, bounds); + tokenOffset = bounds[0]; this.docRoot = ContextUtilities.getRoot(element); populateNamespaces(); } catch (BadLocationException ex) { @@ -125,15 +126,15 @@ return this.valid; } - public int getCurrentTokenId() { + public XMLTokenId getCurrentTokenId() { if (isValid()) { - return token.getTokenID().getNumericID(); + return token.id(); } else { - return -1; + return null; } } - public TokenItem getCurrentToken() { + public Token getCurrentToken() { if (isValid()) { return token; } else { @@ -143,7 +144,7 @@ public String getCurrentTokenImage() { if (isValid()) { - return token.getImage(); + return token.text().toString(); } else { return null; } @@ -153,54 +154,6 @@ return this.element; } - public List getPathFromRoot() { - if (isValid()) { - SyntaxElement elementRef = this.element; - Stack stack = new Stack(); - - while (elementRef != null) { - if ((elementRef instanceof EndTag) || - (elementRef instanceof EmptyTag && stack.isEmpty()) || - (elementRef instanceof StartTag && stack.isEmpty())) { - stack.push(elementRef); - elementRef = elementRef.getPrevious(); - continue; - } - if (elementRef instanceof StartTag) { - StartTag start = (StartTag) elementRef; - if (stack.peek() instanceof EndTag) { - EndTag end = (EndTag) stack.peek(); - if (end.getTagName().equals(start.getTagName())) { - stack.pop(); - } - } else { - SyntaxElement e = (SyntaxElement) stack.peek(); - String tagAtTop = (e instanceof StartTag) ? ((StartTag) e).getTagName() : ((EmptyTag) e).getTagName(); - stack.push(elementRef); - } - } - elementRef = elementRef.getPrevious(); - } - - return createPath(stack); - } - - return Collections.emptyList(); - } - - private List createPath(Stack stack) { - ArrayList pathList = new ArrayList(); - while (!stack.isEmpty()) { - SyntaxElement top = stack.pop(); - String tagName = (top instanceof StartTag) ? ((StartTag) top).getTagName() : ((EmptyTag) top).getTagName(); - if (tagName != null) { - pathList.add(tagName); - } - } - - return Collections.unmodifiableList(pathList); - } - public Document getDocument() { return this.document; } @@ -223,18 +176,22 @@ return declaredNamespaces.values(); } - public StartTag getDocRoot() { + public SyntaxElement getDocRoot() { return docRoot; } public int getCaretOffset() { return this.caretOffset; } + + public int getCurrentTokenOffset() { + return tokenOffset; + } private void populateNamespaces() { // Find the a start or empty tag just before the current syntax element. SyntaxElement element = this.element; - while (element != null && !(element instanceof StartTag) && !(element instanceof EmptyTag)) { + while (element != null && !syntaxSupport.isStartTag(element) && !syntaxSupport.isEmptyTag(element)) { element = element.getPrevious(); } if (element == null) { @@ -244,9 +201,9 @@ // To find all namespace declarations active at the caret offset, we // need to look at xmlns attributes of the current element and its ancestors. Node node = (Node)element; - while (node != null) { - if (node instanceof StartTag || node instanceof EmptyTag) { - NamedNodeMap attributes = ((Tag)node).getAttributes(); + while (node != null && element != null) { + if (syntaxSupport.isStartTag(element) || syntaxSupport.isEmptyTag(element)) { + NamedNodeMap attributes = node.getAttributes(); for (int index = 0; index < attributes.getLength(); index++) { Attr attr = (Attr) attributes.item(index); String attrName = attr.getName(); @@ -297,4 +254,8 @@ hash = 61 * hash + (this.document != null ? this.document.hashCode() : 0); return hash; } + + public XMLSyntaxSupport getSyntaxSupport() { + return syntaxSupport; + } } diff --git a/web.core.syntax/src/org/netbeans/modules/web/core/xmlsyntax/JspXMLTokenContext.java b/web.core.syntax/src/org/netbeans/modules/web/core/xmlsyntax/JspXMLTokenContext.java --- a/web.core.syntax/src/org/netbeans/modules/web/core/xmlsyntax/JspXMLTokenContext.java +++ b/web.core.syntax/src/org/netbeans/modules/web/core/xmlsyntax/JspXMLTokenContext.java @@ -52,7 +52,6 @@ import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; - /** * Token context for JSP pages with XML content. * diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/CatalogEntityResolver.java b/xml.catalog/src/org/netbeans/modules/xml/catalog/CatalogEntityResolver.java --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/CatalogEntityResolver.java +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/CatalogEntityResolver.java @@ -55,6 +55,7 @@ import org.netbeans.api.xml.services.*; import org.openide.util.Lookup; import javax.xml.transform.URIResolver; +import org.openide.util.lookup.ServiceProvider; /** * An entity resolver that can resolve all registrations @@ -68,6 +69,7 @@ * @author Petr Kuzel * @version 1.0 */ +@ServiceProvider(service = UserCatalog.class) public class CatalogEntityResolver extends UserCatalog implements EntityResolver, URIResolver { /** Creates new CatalogEntityResolver */ diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/SystemCatalogProvider.java b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/SystemCatalogProvider.java --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/SystemCatalogProvider.java +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/SystemCatalogProvider.java @@ -46,6 +46,7 @@ import java.io.IOException; import org.netbeans.modules.xml.catalog.spi.CatalogProvider; +import org.openide.util.lookup.ServiceProvider; /** * Provide class representing SystemCatalogReader class. @@ -53,6 +54,7 @@ * @author Petr Kuzel * @version */ +@ServiceProvider(service = CatalogProvider.class) public class SystemCatalogProvider implements CatalogProvider { public Class provideClass() throws IOException, ClassNotFoundException { diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/XCatalogProvider.java b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/XCatalogProvider.java --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/XCatalogProvider.java +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/XCatalogProvider.java @@ -46,6 +46,7 @@ import java.io.IOException; import org.netbeans.modules.xml.catalog.spi.CatalogProvider; +import org.openide.util.lookup.ServiceProvider; /** * Provide class representing XCatalog class. @@ -53,6 +54,7 @@ * @author Petr Kuzel * @version */ +@ServiceProvider(service = CatalogProvider.class) public class XCatalogProvider implements CatalogProvider { public Class provideClass() throws IOException, ClassNotFoundException { diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/sun/SunCatalogProvider.java b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/sun/SunCatalogProvider.java --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/sun/SunCatalogProvider.java +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/impl/sun/SunCatalogProvider.java @@ -46,6 +46,7 @@ import java.io.IOException; import org.netbeans.modules.xml.catalog.spi.CatalogProvider; +import org.openide.util.lookup.ServiceProvider; /** * Provide class representing Catalog reader class. @@ -53,6 +54,7 @@ * @author Petr Kuzel * @version */ +@ServiceProvider(service = CatalogProvider.class) public class SunCatalogProvider implements CatalogProvider { public Class provideClass() throws IOException, ClassNotFoundException { diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/resources/mf-layer.xml b/xml.catalog/src/org/netbeans/modules/xml/catalog/resources/mf-layer.xml --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/resources/mf-layer.xml +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/resources/mf-layer.xml @@ -63,33 +63,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/xml.catalog/src/org/netbeans/modules/xml/catalog/settings/CatalogSettings.java b/xml.catalog/src/org/netbeans/modules/xml/catalog/settings/CatalogSettings.java --- a/xml.catalog/src/org/netbeans/modules/xml/catalog/settings/CatalogSettings.java +++ b/xml.catalog/src/org/netbeans/modules/xml/catalog/settings/CatalogSettings.java @@ -49,7 +49,6 @@ import java.util.logging.Level; import org.netbeans.modules.xml.catalog.lib.IteratorIterator; -import org.openide.*; import org.openide.util.io.NbMarshalledObject; import org.netbeans.modules.xml.catalog.spi.*; @@ -57,6 +56,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ServiceProvider; /** @@ -92,6 +92,7 @@ * * @author Petr Kuzel */ +@ServiceProvider(service = CatalogSettings.class) public final class CatalogSettings implements Externalizable { /** Serial Version UID */ diff --git a/xml.lexer/nbproject/project.xml b/xml.lexer/nbproject/project.xml --- a/xml.lexer/nbproject/project.xml +++ b/xml.lexer/nbproject/project.xml @@ -45,6 +45,15 @@ org.netbeans.modules.xml.lexer + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.41 + + + org.netbeans.modules.lexer diff --git a/xml.lexer/src/org/netbeans/api/xml/lexer/XMLTokenId.java b/xml.lexer/src/org/netbeans/api/xml/lexer/XMLTokenId.java --- a/xml.lexer/src/org/netbeans/api/xml/lexer/XMLTokenId.java +++ b/xml.lexer/src/org/netbeans/api/xml/lexer/XMLTokenId.java @@ -46,6 +46,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.Map; +import org.netbeans.api.editor.mimelookup.MimeRegistration; import org.netbeans.api.lexer.InputAttributes; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.LanguagePath; @@ -144,6 +145,7 @@ } }.language(); + @MimeRegistration(mimeType = "text/xml", service = Language.class) public static Language language() { return language; } diff --git a/xml.lexer/src/org/netbeans/lib/xml/lexer/XMLLexer.java b/xml.lexer/src/org/netbeans/lib/xml/lexer/XMLLexer.java --- a/xml.lexer/src/org/netbeans/lib/xml/lexer/XMLLexer.java +++ b/xml.lexer/src/org/netbeans/lib/xml/lexer/XMLLexer.java @@ -361,10 +361,13 @@ // note: it would be more correct to raise an error here, // and return TAG PartType=Start, BUT some code already expects // unfinished tags to be reported as TEXT. - state = INIT; + state = ISI_TEXT; input.backup(1); + break; + /* return tokenFactory.createToken( XMLTokenId.TEXT, input.readLength()); + */ } break; diff --git a/xml.lexer/src/org/netbeans/lib/xml/lexer/layer.xml b/xml.lexer/src/org/netbeans/lib/xml/lexer/layer.xml --- a/xml.lexer/src/org/netbeans/lib/xml/lexer/layer.xml +++ b/xml.lexer/src/org/netbeans/lib/xml/lexer/layer.xml @@ -45,10 +45,6 @@ - - - - diff --git a/xml.lexer/test/unit/src/org/netbeans/api/xml/lexer/BrokenXMLTest.java b/xml.lexer/test/unit/src/org/netbeans/api/xml/lexer/BrokenXMLTest.java --- a/xml.lexer/test/unit/src/org/netbeans/api/xml/lexer/BrokenXMLTest.java +++ b/xml.lexer/test/unit/src/org/netbeans/api/xml/lexer/BrokenXMLTest.java @@ -66,7 +66,7 @@ */ public void testTokens() throws Exception { XMLTokenId[] expectedIds = {XMLTokenId.PI_START, XMLTokenId.PI_TARGET, XMLTokenId.WS, XMLTokenId.PI_CONTENT, - XMLTokenId.PI_END, XMLTokenId.TEXT, XMLTokenId.TAG, XMLTokenId.TAG, XMLTokenId.TEXT, XMLTokenId.TEXT, XMLTokenId.TEXT, + XMLTokenId.PI_END, XMLTokenId.TEXT, XMLTokenId.TAG, XMLTokenId.TAG, XMLTokenId.TEXT, XMLTokenId.TEXT, XMLTokenId.TAG, XMLTokenId.TAG, XMLTokenId.TEXT, XMLTokenId.TAG, XMLTokenId.ERROR, XMLTokenId.TAG, XMLTokenId.TAG, XMLTokenId.TEXT, XMLTokenId.TAG, XMLTokenId.TAG, XMLTokenId.TEXT }; javax.swing.text.Document document = getDocument("resources/broken.xml"); diff --git a/xml.schema.completion/manifest.mf b/xml.schema.completion/manifest.mf --- a/xml.schema.completion/manifest.mf +++ b/xml.schema.completion/manifest.mf @@ -2,5 +2,5 @@ OpenIDE-Module: org.netbeans.modules.xml.schema.completion OpenIDE-Module-Layer: org/netbeans/modules/xml/schema/completion/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/xml/schema/completion/Bundle.properties -OpenIDE-Module-Specification-Version: 1.31 +OpenIDE-Module-Specification-Version: 1.32 AutoUpdate-Show-In-Client: false diff --git a/xml.schema.completion/nbproject/project.properties b/xml.schema.completion/nbproject/project.properties --- a/xml.schema.completion/nbproject/project.properties +++ b/xml.schema.completion/nbproject/project.properties @@ -30,7 +30,7 @@ # Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun # Microsystems, Inc. All Rights Reserved. -javac.source=1.6 +javac.source=1.8 javadoc.arch=${basedir}/arch.xml # XXX should be deleted in simpletests branch (see project.xml entry): test.qa-functional.cp.extra=\ diff --git a/xml.schema.completion/nbproject/project.xml b/xml.schema.completion/nbproject/project.xml --- a/xml.schema.completion/nbproject/project.xml +++ b/xml.schema.completion/nbproject/project.xml @@ -103,6 +103,15 @@ + org.netbeans.modules.nbjunit + + + + 1 + 1.88 + + + org.netbeans.modules.projectapi @@ -151,7 +160,7 @@ 2 - 1.16 + 1.60 @@ -195,14 +204,6 @@ - org.openide.util.ui - - - - 9.3 - - - org.openide.util @@ -218,6 +219,14 @@ 8.0 + + org.openide.util.ui + + + + 9.3 + + @@ -253,6 +262,10 @@ org.netbeans.modules.xml.xdm + + org.netbeans.modules.xml.catalog + + diff --git a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/CompletionQuery.java b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/CompletionQuery.java --- a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/CompletionQuery.java +++ b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/CompletionQuery.java @@ -57,13 +57,18 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; +import javax.swing.text.AbstractDocument; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.netbeans.api.editor.completion.Completion; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenHierarchy; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; import org.netbeans.modules.xml.schema.completion.util.CompletionContextImpl; import org.netbeans.modules.xml.schema.completion.util.CompletionUtil; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.spi.editor.completion.CompletionItem; import org.netbeans.spi.editor.completion.CompletionResultSet; import org.netbeans.spi.editor.completion.CompletionTask; @@ -120,16 +125,19 @@ protected void prepareQuery(JTextComponent component) { this.component = component; } - + @Override protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) { - XMLSyntaxSupport support = - (XMLSyntaxSupport) ((BaseDocument) doc).getSyntaxSupport(); + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(doc); + if (support == null) { + resultSet.finish(); + return; + } CompletionResultItem endTagResultItem = CompletionUtil.getEndTagCompletionItem( component, (BaseDocument) doc); List completionItems = null; - if (! support.noCompletion(component) && + if (!CompletionUtil.noCompletion(component) && (CompletionUtil.canProvideCompletion((BaseDocument) doc))) { resultSet.setWaitText(NbBundle.getMessage(CompletionQuery.class, "MSG_PreparingXmlSchemas")); // NOI18N @@ -350,7 +358,10 @@ List completionItems = null; //Step 1: create a context - XMLSyntaxSupport support = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport(); + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(doc); + if (support == null) { + return null; + } context = new CompletionContextImpl(primaryFile, support, caretOffset); //Step 2: Accumulate all models and initialize the context diff --git a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/SchemaBasedCompletionProvider.java b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/SchemaBasedCompletionProvider.java --- a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/SchemaBasedCompletionProvider.java +++ b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/SchemaBasedCompletionProvider.java @@ -48,7 +48,7 @@ import org.netbeans.editor.BaseDocument; import org.netbeans.editor.Utilities; import org.netbeans.modules.xml.schema.completion.util.CompletionUtil; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; @@ -76,8 +76,9 @@ } if(doc == null) return 0; - XMLSyntaxSupport support = ((XMLSyntaxSupport)doc.getSyntaxSupport()); - if(support.noCompletion(component) || !CompletionUtil.canProvideCompletion(doc)) { + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(doc); + if(support != null && CompletionUtil.noCompletion(component) || + !CompletionUtil.canProvideCompletion(doc)) { return 0; } diff --git a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionContextImpl.java b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionContextImpl.java --- a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionContextImpl.java +++ b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionContextImpl.java @@ -44,11 +44,12 @@ package org.netbeans.modules.xml.schema.completion.util; import java.net.URI; -import java.net.URISyntaxException; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.AbstractDocument; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import javax.xml.XMLConstants; import javax.xml.namespace.QName; @@ -58,14 +59,9 @@ import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; import org.netbeans.modules.xml.axi.AbstractAttribute; import org.netbeans.modules.xml.axi.Element; import org.openide.filesystems.FileObject; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; import org.netbeans.modules.xml.schema.completion.spi.CompletionContext; import org.netbeans.modules.xml.schema.completion.spi.CompletionContext.CompletionType; import org.netbeans.modules.xml.schema.completion.spi.CompletionModelProvider; @@ -74,9 +70,8 @@ import org.netbeans.modules.xml.schema.completion.util.CompletionUtil.DocRootAttribute; import org.netbeans.modules.xml.schema.model.Schema; import org.netbeans.modules.xml.schema.model.SchemaModel; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.w3c.dom.Attr; @@ -96,11 +91,12 @@ private static final Logger _logger = Logger.getLogger(CompletionContextImpl.class.getName()); - + private XMLSyntaxSupport support; private int completionAtOffset = -1; private FileObject primaryFile; private String typedChars; - private TokenItem token; + private Token token; + private int tokenOffset; private SyntaxElement element; private String attribute; private DocRoot docRoot; @@ -110,12 +106,12 @@ /** * Tags on the path from root to the context element (the one the CC tries to fill) */ - private List elementsFromRoot; + private List elementsFromRoot; private Map schemaLocationMap = new HashMap(); private String schemaLocation; private String noNamespaceSchemaLocation; private String defaultNamespace; - private BaseDocument document; + private Document document; private HashMap nsModelMap = new HashMap(); private List noNSModels = @@ -140,11 +136,14 @@ public CompletionContextImpl(FileObject primaryFile, XMLSyntaxSupport support, int offset) { try { + this.support = support; this.completionAtOffset = offset; this.primaryFile = primaryFile; this.document = support.getDocument(); this.element = support.getElementChain(offset); - this.token = support.getPreviousToken(offset); + int[] off = new int[2]; + this.token = support.getPreviousToken(offset, off); + this.tokenOffset = off[0]; this.docRoot = CompletionUtil.getDocRoot(document); this.lastTypedChar = support.lastTypedChar(); populateNamespaces(); @@ -177,7 +176,7 @@ @Override public BaseDocument getBaseDocument() { - return document; + return (BaseDocument)document; } @Override @@ -238,9 +237,10 @@ * from previously added tags. Tags should be added starting from the root down * to the context position. */ - private void addNamespacesFrom(Tag e) { + private void addNamespacesFrom(SyntaxElement s) { + Node e = s.getNode(); NamedNodeMap attrs = e.getAttributes(); - String nodePrefix = getPrefix(e.getTagName(), false); + String nodePrefix = getPrefix(e.getNodeName(), false); String version = null; String xsltAttrName = null; @@ -281,11 +281,11 @@ * * @param stack path from the context element (index 0) to the root (index N-1). */ - private void addContextNamespaces(List stack) { + private void addContextNamespaces(List stack) { // must iterate from root down to the context element, to properly override // namespaces and replace default/noNamespace information. for (int i = stack.size() - 1; i >= 0; i--) { - Tag t = stack.get(i); + SyntaxElement t = stack.get(i); addNamespacesFrom(t); } } @@ -470,25 +470,26 @@ try { if (isTagAttributeRequired(tokenSequence)) { completionType = CompletionType.COMPLETION_TYPE_ATTRIBUTE; - if (token.getTokenID().equals(XMLDefaultTokenContext.WS)) { + if (token.id() == XMLTokenId.WS) { typedChars = null; } else { - String str = token.getImage(); + String str = token.text().toString(); int e = str.length(); - int l = Math.min(completionAtOffset - token.getOffset() /* initial quote */, e); + int l = Math.min(completionAtOffset - tokenOffset /* initial quote */, e); typedChars = str.substring(0, l); } createPathFromRoot(element); return true; } - int id = token.getTokenID().getNumericID(); + XMLTokenId id = token.id(); switch (id) { //user enters < character - case XMLDefaultTokenContext.TEXT_ID: - String chars = token.getImage().trim(); - String previousTokenText = token.getPrevious() == null ? - "" :token.getPrevious().getImage().trim(); + case TEXT: + String chars = token.text().toString().trim(); + Token previous = support.getPreviousToken(tokenOffset); + String previousTokenText = previous == null ? + "" : previous.text().toString().trim(); if(chars != null && chars.startsWith("&")) { completionType = CompletionType.COMPLETION_TYPE_UNKNOWN; break; @@ -519,18 +520,18 @@ } break; - case XMLDefaultTokenContext.BLOCK_COMMENT_ID: + case BLOCK_COMMENT: completionType = CompletionType.COMPLETION_TYPE_ELEMENT; createPathFromRoot(element); break; //start tag of an element - case XMLDefaultTokenContext.TAG_ID: - if(element instanceof EndTag) { + case TAG: + if(support.isEndTag(element)) { completionType = CompletionType.COMPLETION_TYPE_UNKNOWN; break; } - if (element instanceof EmptyTag) { + if (support.isEmptyTag(element)) { /* if (token != null && token.getImage().trim().equals("/>")) { @@ -538,20 +539,20 @@ break; } */ - EmptyTag tag = (EmptyTag) element; + String tagName = element.getNode().getNodeName(); if ((element.getElementOffset() + 1 == completionAtOffset) || - (token.getOffset() + token.getImage().length() == completionAtOffset)) { + (tokenOffset + token.length()== completionAtOffset)) { completionType = CompletionType.COMPLETION_TYPE_ELEMENT; createPathFromRoot(element.getPrevious()); break; } if (completionAtOffset > element.getElementOffset() + 1 && completionAtOffset <= (element.getElementOffset() + 1 + - tag.getTagName().length())) { + tagName.length())) { completionType = CompletionType.COMPLETION_TYPE_ELEMENT; int index = completionAtOffset - element.getElementOffset() - 1; - typedChars = index < 0 ? tag.getTagName() : - tag.getTagName().substring(0, index); + typedChars = index < 0 ? tagName : + tagName.substring(0, index); createPathFromRoot(element.getPrevious()); break; } @@ -559,10 +560,10 @@ //***???pathFromRoot = getPathFromRoot(element); break; } - - if(element instanceof StartTag) { + if (element.getType() == Node.ELEMENT_NODE && + support.isStartTag(element)) { if(token != null && - token.getImage().trim().equals(">")) { + token.text().toString().trim().equals(">")) { createPathFromRoot(element); completionType = CompletionType.COMPLETION_TYPE_ELEMENT_VALUE; break; @@ -570,10 +571,10 @@ if(element.getElementOffset() + 1 == this.completionAtOffset) { typedChars = null; } else { - StartTag tag = (StartTag)element; + String tagName = element.getNode().getNodeName(); int index = completionAtOffset-element.getElementOffset()-1; - typedChars = index<0?tag.getTagName() : - tag.getTagName().substring(0, index); + typedChars = index < 0 ? tagName : + tagName.substring(0, index); } } completionType = CompletionType.COMPLETION_TYPE_ELEMENT; @@ -581,43 +582,45 @@ break; //user enters an attribute name - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: //***???completionType = CompletionType.COMPLETION_TYPE_ATTRIBUTE; //***???typedChars = token.getImage(); //***???pathFromRoot = getPathFromRoot(element); break; //some random character - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: completionType = CompletionType.COMPLETION_TYPE_UNKNOWN; break; //user enters = character, we should ignore all other operators - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: completionType = CompletionType.COMPLETION_TYPE_UNKNOWN; break; //user enters either ' or " - case XMLDefaultTokenContext.VALUE_ID: { + case VALUE: { //user enters start quote and no end quote exists - if(token.getNext() == null) { - if(lastTypedChar == '\'' || lastTypedChar == '\"') + Token next = support.getNextToken(tokenOffset + token.length()); + if(next == null) { + if(lastTypedChar == '\'' || lastTypedChar == '\"') { typedChars = null; - else - typedChars = token.getImage().substring(1, - token.getImage().indexOf(">")); + } else { + String tt = token.text().toString(); + typedChars = tt.substring(1, tt.indexOf(">")); + } } //user is inside start/end quotes if(lastTypedChar != '\'' && lastTypedChar != '\"') { - String str = token.getImage(); + String str = token.text().toString(); if( str != null && !str.equals("\"\"") && !str.equals("\'\'") && (str.startsWith("\"") || str.startsWith("\'")) && (str.endsWith("\"") || str.endsWith("\'")) ) { int e = str.length() - 1; - int l = Math.min(completionAtOffset - token.getOffset() /* initial quote */, e); + int l = Math.min(completionAtOffset - tokenOffset /* initial quote */, e); typedChars = str.substring(1, l); - if(completionAtOffset == token.getOffset()+1) + if(completionAtOffset == tokenOffset + 1) typedChars = ""; } } @@ -630,27 +633,36 @@ } //user enters white-space character - case XMLDefaultTokenContext.WS_ID: - completionType = CompletionType.COMPLETION_TYPE_UNKNOWN; - TokenItem prev = token.getPrevious(); - while( prev != null && - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID) ) { - prev = prev.getPrevious(); - } - if( (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) || - (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) ) { - //no attr completion for end tags - if (prev.getImage().startsWith(" { + if (!ts.movePrevious()) { + return false; + } + Token prev = ts.token(); + while(ts.movePrevious()) { + prev = ts.token(); + if (prev.id() != XMLTokenId.WS) { + break; + } + } + if( (prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG) ) { + //no attr completion for end tags + if (prev.text().toString().startsWith("null in unexpected situations */ private String findAttributeName() { - TokenItem item = token; - while (item != null) { - int tid = item.getTokenID().getNumericID(); - switch (tid) { - case XMLDefaultTokenContext.VALUE_ID: - case XMLDefaultTokenContext.OPERATOR_ID: - case XMLDefaultTokenContext.WS_ID: - case XMLDefaultTokenContext.TEXT_ID: - item = item.getPrevious(); - break; - case XMLDefaultTokenContext.ARGUMENT_ID: - return item.getImage(); - default: - return null; - } + try { + return support.runWithSequence(tokenOffset, (TokenSequence ts) -> { + Token item = ts.token(); + while (item != null) { + switch (item.id()) { + case VALUE: + case OPERATOR: + case WS: + case TEXT: + if (!ts.movePrevious()) { + return null; + } + item = ts.token(); + break; + case ARGUMENT: + return item.text().toString(); + default: + return null; + } + } + return null; + }); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + return null; } - return null; } public List getDocRootAttributes() { @@ -716,25 +737,26 @@ //1st pass if(se == null) return; - Stack stack = new Stack(); - if(se instanceof EmptyTag) - stack.push((Tag)se); + Stack stack = new Stack<>(); + if(support.isEmptyTag(se)) + stack.push(se); + while( se != null) { - if( (se instanceof EndTag) || - (se instanceof StartTag && stack.isEmpty()) ) { - stack.push((Tag)se); + if ( + (stack.isEmpty() && support.isStartTag(se)) || + support.isEndTag(se)) { + stack.push(se); se = se.getPrevious(); continue; } - if(se instanceof StartTag) { - StartTag start = (StartTag)se; - if(stack.peek() instanceof EndTag) { - EndTag end = (EndTag)stack.peek(); - if(end.getTagName().equals(start.getTagName())) { + if (support.isStartTag(se)) { + if (support.isEndTag(stack.peek())) { + SyntaxElement end = stack.peek(); + if(end.getNode().getNodeName().equals(se.getNode().getNodeName())) { stack.pop(); } } else { - stack.push((Tag)se); + stack.push(se); } } se = se.getPrevious(); @@ -751,14 +773,14 @@ * While creating the path it always adds items to the start of the list so * that the returned path starts from root, all the way to the current tag. */ - private ArrayList createPath(Stack stack) { + private ArrayList createPath(Stack stack) { ArrayList path = new ArrayList(); - ListIterator tags = stack.listIterator(); + ListIterator tags = stack.listIterator(); while(tags.hasNext()) { - Tag tag = tags.next(); + SyntaxElement tag = tags.next(); //add to the start of the list path.add(0, createQName(tag)); - if(isRoot(tag, tags.hasNext()?tags.next():null)) { + if(isRoot(tag, tags.hasNext() ? tags.next() : null)) { return path; } tags.previous();//since we moved twice. @@ -772,18 +794,20 @@ * However, there are exceptions to this and may not work well for cases when * you combine itmes from schemas with/without namespace. */ - private boolean isRoot(Tag thisTag, Tag previousTag) { + private boolean isRoot(SyntaxElement elem, SyntaxElement previousTag) { //no previous => this has to be the root + Node thisTag = elem.getNode(); if(previousTag == null) return true; //if the tag declares a namespace and is diff from default, then it is root - String prefix = CompletionUtil.getPrefixFromTag(thisTag.getTagName()); + String prefix = CompletionUtil.getPrefixFromTag(thisTag.getNodeName()); Attr namespaceAttr = null; + NamedNodeMap attrs = thisTag.getAttributes(); if(prefix==null) { - namespaceAttr = thisTag.getAttributeNode(XMLConstants.XMLNS_ATTRIBUTE); + namespaceAttr = (Attr)attrs.getNamedItem(XMLConstants.XMLNS_ATTRIBUTE); } else { - namespaceAttr = thisTag.getAttributeNode(XMLConstants.XMLNS_ATTRIBUTE+":"+prefix); + namespaceAttr = (Attr)attrs.getNamedItem(XMLConstants.XMLNS_ATTRIBUTE+":"+prefix); } if(namespaceAttr != null) { String namespace = namespaceAttr.getValue(); @@ -801,10 +825,10 @@ } } - return !fromSameNamespace(thisTag, previousTag); + return !fromSameNamespace(thisTag, previousTag.getNode()); } - private String getAttributeValue(Tag tag, String attrName) { + private String getAttributeValue(Node tag, String attrName) { NamedNodeMap attrs = tag.getAttributes(); for(int i=0; i(); - TokenItem item = token.getPrevious(); - while(item != null) { - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.TAG_ID) - break; - if(item.getTokenID().getNumericID() == - XMLDefaultTokenContext.ARGUMENT_ID) { - existingAttributes.add(item.getImage()); - } - item = item.getPrevious(); + try { + support.runWithSequence(tokenOffset, (TokenSequence ts) -> { + if (ts.movePrevious()) { + return null; + } + Token item; + + while(ts.movePrevious()) { + item = ts.token(); + if(item.id() == XMLTokenId.TAG) + break; + if(item.id() == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } + } + return null; + }); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); } return existingAttributes; } diff --git a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionUtil.java b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionUtil.java --- a/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionUtil.java +++ b/xml.schema.completion/src/org/netbeans/modules/xml/schema/completion/util/CompletionUtil.java @@ -88,6 +88,41 @@ public static final Pattern PATTERN_TEXT_TAG_EOLs = Pattern.compile(" + + Builds, tests, and runs the project org.netbeans.modules.xml.text.obsolete90 + + diff --git a/xml.text.obsolete90/manifest.mf b/xml.text.obsolete90/manifest.mf new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/manifest.mf @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: false +OpenIDE-Module: org.netbeans.modules.xml.text.obsolete90 +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/xml/text/obsolete90/Bundle.properties +OpenIDE-Module-Implementation-Version: 1 +OpenIDE-Module-Layer: org/netbeans/modules/xml/text/obsolete90/resources/mf-layer.xml diff --git a/xml.text.obsolete90/nbproject/project.properties b/xml.text.obsolete90/nbproject/project.properties new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/nbproject/project.properties @@ -0,0 +1,4 @@ +is.autoload=true +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial +spec.version.base=1.0 diff --git a/xml.text.obsolete90/nbproject/project.xml b/xml.text.obsolete90/nbproject/project.xml new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/nbproject/project.xml @@ -0,0 +1,182 @@ + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.xml.text.obsolete90 + + + org.netbeans.modules.editor.deprecated.pre65formatting + + + + 0 + 1.32 + + + + org.netbeans.modules.editor.document + + + + 1.10 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.8 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.41 + + + + org.netbeans.modules.editor.structure + + + + 1 + + + + org.netbeans.modules.lexer + + + + 2 + 1.64 + + + + org.netbeans.modules.xml.core + + + + 2 + 1.44 + + + + org.netbeans.modules.xml.lexer + + + + 1.30 + + + + org.netbeans.modules.xml.text + + + + 2 + + + + + org.openide.util + + + + 9.8 + + + + org.openide.util.ui + + + + 9.7 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.editor + + + + + + org.netbeans.modules.editor.mimelookup + + + + org.netbeans.modules.editor.mimelookup.impl + + + + + org.netbeans.modules.editor.settings.storage + + + + org.netbeans.modules.editor.structure + + + + org.netbeans.modules.editor.util + + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.projectapi.nb + + + + org.netbeans.modules.xml.lexer + + + + org.netbeans.modules.xml.text + + + + + + org.netbeans.modules.xml.xam + + + + org.netbeans.modules.xml.xdm + + + + org.openide.util.ui + + + + org.openide.util.lookup + + + + + + org.netbeans.modules.xml.text.api + org.netbeans.modules.xml.text.indent + org.netbeans.modules.xml.text.syntax + org.netbeans.modules.xml.text.syntax.dom + + + + diff --git a/xml.text/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java rename from xml.text/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java --- a/xml.text/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/api/XMLDefaultTokenContext.java @@ -43,6 +43,7 @@ */ package org.netbeans.modules.xml.text.api; +import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.netbeans.editor.TokenContext; @@ -58,8 +59,9 @@ * @version 1.00 * @contributor(s) XML Modifications Sandeep Singh Randhawa * @integrator Petr Kuzel + * @deprecated This API uses an obsolete (Ext)Syntax API. Clients should use new Lexer API. */ - +@Deprecated public class XMLDefaultTokenContext extends TokenContext implements XMLTokenIDs { diff --git a/xml.text/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java rename from xml.text/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java --- a/xml.text/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/indent/XMLFormatter.java @@ -55,6 +55,7 @@ import org.netbeans.editor.ext.FormatWriter; import org.netbeans.editor.BaseDocument; import org.netbeans.modules.editor.structure.formatting.TagBasedFormatter; +import org.netbeans.modules.xml.text.indent.XMLFormatSupport; import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; diff --git a/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/Bundle.properties b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/Bundle.properties new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/Bundle.properties @@ -0,0 +1,5 @@ +OpenIDE-Module-Long-Description=\ + The SyntaxElement API was desinged around the old and now long-deprecated parser. \ + This module provides backward compatibility for module implementors who did not migrate to the new lexer and new SyntaxElement API found in the XML Text Editor module. +OpenIDE-Module-Name=XML Text Editor (obsolete) +OpenIDE-Module-Short-Description=Obsolete and deprecated APIs from XML Text Editor module diff --git a/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/ComplexValueSettingsFactory.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/ComplexValueSettingsFactory.java new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/ComplexValueSettingsFactory.java @@ -0,0 +1,61 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.obsolete90; + +import java.util.Collections; +import java.util.List; +import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; +import org.netbeans.modules.xml.text.syntax.DTDTokenContext; + +/** + * + * @author sdedic + */ +public class ComplexValueSettingsFactory { + public static List getXMLTokenContext() { + return Collections.singletonList(XMLDefaultTokenContext.context); + } + // XXX: use lexer + public static List getDTDTokenContext() { + return Collections.singletonList(DTDTokenContext.context); + } +} diff --git a/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/XMLSyntaxBridgeImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/XMLSyntaxBridgeImpl.java new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/XMLSyntaxBridgeImpl.java @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.obsolete90; + +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import org.netbeans.api.editor.mimelookup.MimeRegistration; +import org.netbeans.api.editor.mimelookup.MimeRegistrations; +import org.netbeans.editor.BaseDocument; +import org.netbeans.editor.SyntaxSupport; +import org.netbeans.modules.xml.text.syntax.DTDKit; +import org.netbeans.modules.xml.text.syntax.DTDSyntaxTokenMapper; +import org.netbeans.modules.xml.text.syntax.DTDTokenContext; +import org.netbeans.modules.xml.text.syntax.ENTKit; +import org.netbeans.modules.xml.text.syntax.XMLDefaultSyntax; +import org.netbeans.modules.xml.text.syntax.XMLKit; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.bridge.LegacySyntaxBridge; +import org.netbeans.modules.xml.text.syntax.javacc.DTDSyntaxTokenManager; +import org.netbeans.modules.xml.text.syntax.javacc.lib.JJEditorSyntax; + +/** + * + * @author sdedic + */ +@MimeRegistrations({ + @MimeRegistration(service = LegacySyntaxBridge.class, mimeType = "text/xml"), + @MimeRegistration(service = LegacySyntaxBridge.class, mimeType = "application/xml-dtd"), + @MimeRegistration(service = LegacySyntaxBridge.class, mimeType = "text/xml-external-parsed-entity") +}) +public class XMLSyntaxBridgeImpl implements LegacySyntaxBridge { + + @Override + public org.netbeans.editor.Syntax createSyntax(EditorKit host, Document doc, String mimeType) { + if (DTDKit.MIME_TYPE.equals(mimeType)) { + return new JJEditorSyntax( + new DTDSyntaxTokenManager(null).new Bridge(), + new DTDSyntaxTokenMapper(), + DTDTokenContext.contextPath + ); + + } else if (XMLKit.MIME_TYPE.equals(mimeType)) { + return new XMLDefaultSyntax(); + } else if (ENTKit.MIME_TYPE.equals(mimeType)) { + return new XMLDefaultSyntax(); + } else { + return null; + } + } + + @Override + public SyntaxSupport createSyntaxSupport(EditorKit host, Document doc, String mimeType) { + if (XMLKit.MIME_TYPE.equals(mimeType) || ENTKit.MIME_TYPE.equals(mimeType)) { + return new XMLSyntaxSupport((BaseDocument)doc); + } else { + return null; + } + } +} diff --git a/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/DTDEditor-preferences.xml copy from xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml copy to xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/DTDEditor-preferences.xml --- a/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/DTDEditor-preferences.xml @@ -46,7 +46,5 @@ - - - + diff --git a/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/XMLEditor-preferences.xml copy from xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml copy to xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/XMLEditor-preferences.xml --- a/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/XMLEditor-preferences.xml @@ -46,9 +46,5 @@ - - - - - + diff --git a/xml.text/src/org/netbeans/modules/xml/text/resources/mf-layer.xml b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/mf-layer.xml copy from xml.text/src/org/netbeans/modules/xml/text/resources/mf-layer.xml copy to xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/mf-layer.xml --- a/xml.text/src/org/netbeans/modules/xml/text/resources/mf-layer.xml +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/obsolete90/resources/mf-layer.xml @@ -45,306 +45,32 @@ --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDSyntaxTokenMapper.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/DTDSyntaxTokenMapper.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/DTDSyntaxTokenMapper.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/DTDSyntaxTokenMapper.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDTokenContext.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/DTDTokenContext.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/DTDTokenContext.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/DTDTokenContext.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/SyntaxElement.java @@ -45,13 +45,11 @@ package org.netbeans.modules.xml.text.syntax; import java.lang.ref.WeakReference; -import java.util.*; import org.w3c.dom.*; import javax.swing.text.*; -import org.netbeans.editor.ext.*; import org.netbeans.editor.*; import org.openide.ErrorManager; @@ -67,7 +65,7 @@ * * @version 1.0 */ -public abstract class SyntaxElement { +public abstract class SyntaxElement implements org.netbeans.modules.xml.text.api.dom.SyntaxElement { // to do do not handle prolog as text! // support PIs @@ -134,7 +132,7 @@ void setPrevious(SyntaxElement se) { previous = new WeakReference(se); } - + /** * Get previous SyntaxElement. Weakly cache results. * @return previous SyntaxElement or null at document begining @@ -243,6 +241,25 @@ public String toString() { return "Error" + super.toString(); // NOI18N } + + @Override + public int getType() { + return NODE_ERROR; + } + + @Override + public Node getNode() { + return null; + } + + @Override + public SyntaxElement getParentElement() { + SyntaxElement x = this; + while (x != null && x.getType() != Node.ELEMENT_NODE) { + x = x.getPrevious(); + } + return x; + } } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/UnicodeClasses.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/UnicodeClasses.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/UnicodeClasses.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/UnicodeClasses.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLDefaultSyntax.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLDefaultSyntax.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/XMLDefaultSyntax.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLDefaultSyntax.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupport.java @@ -73,7 +73,7 @@ * @author Petr Kuzel - use before strategy, use tokens whenever possible * @version 0.8 */ -public class XMLSyntaxSupport extends ExtSyntaxSupport implements XMLTokenIDs { +public final class XMLSyntaxSupport extends ExtSyntaxSupport implements XMLTokenIDs { private Reference reference = new SoftReference(null); // cached helper private String systemId = null; // cached refernce to DTD diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxTokenMapper.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxTokenMapper.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxTokenMapper.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxTokenMapper.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLTokenContext.java @@ -43,8 +43,6 @@ */ package org.netbeans.modules.xml.text.syntax; -import org.netbeans.editor.BaseTokenCategory; -import org.netbeans.editor.BaseTokenID; import org.netbeans.editor.TokenContext; import org.netbeans.editor.TokenContextPath; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLTokenIDs.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLTokenIDs.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/XMLTokenIDs.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/XMLTokenIDs.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/AttrImpl.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; import java.util.*; import javax.swing.text.BadLocationException; @@ -51,6 +53,7 @@ import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; import org.netbeans.editor.*; +import org.netbeans.modules.xml.*; /** * Holds attribute: name-value pairs. It is returned by Tag diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CDATASectionImpl.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/CommentImpl.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DOMImplementationImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DOMImplementationImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DOMImplementationImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DOMImplementationImpl.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentImpl.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.SyntaxElement; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/DocumentTypeImpl.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EmptyTag.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import java.util.*; import org.w3c.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EndTag.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.SyntaxElement; import java.util.*; import org.w3c.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/EntityReferenceImpl.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/ProcessingInstructionImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/ProcessingInstructionImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/ProcessingInstructionImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/ProcessingInstructionImpl.java diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/StartTag.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.SyntaxElement; import java.util.*; import org.w3c.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/SyntaxNode.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.SyntaxElement; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; @@ -72,6 +74,15 @@ super( support, first, to); } + @Override + public int getType() { + return getNodeType(); + } + + @Override + public Node getNode() { + return this; + } /** * Default implementation returning first previous SyntaxNode * or null. It is StartTag aware. @@ -341,5 +352,10 @@ public void setIdAttributeNode(Attr a, boolean b) { throw new UOException (); } + + @Override + public org.netbeans.modules.xml.text.api.dom.SyntaxElement getParentElement() { + return (SyntaxElement)getParentNode(); + } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Tag.java @@ -44,6 +44,8 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; import java.util.*; import javax.swing.text.BadLocationException; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/TextImpl.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.syntax.dom; +import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.w3c.dom.*; import org.netbeans.modules.xml.text.syntax.*; import org.netbeans.modules.xml.spi.dom.*; diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Util.java b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Util.java rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Util.java rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Util.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/Util.java +++ b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/Util.java @@ -81,34 +81,7 @@ * @return the same value of stripped substring of it. */ public static String actualAttributeValue(String attributeValue) { - int ltIndex = attributeValue.indexOf('<'); - int gtIndex = attributeValue.indexOf('>'); - int firstUnwantedIndex = -1; - if (gtIndex != -1) { - if (ltIndex != -1 && ltIndex < gtIndex) { - firstUnwantedIndex = ltIndex; - } else { - firstUnwantedIndex = gtIndex; - } - } else { - firstUnwantedIndex = ltIndex; - } - - if (firstUnwantedIndex != -1) { - char charAtIndex = attributeValue.charAt(firstUnwantedIndex); - while (charAtIndex == ' ' || charAtIndex == '\t' || charAtIndex == '\n' || - charAtIndex == '\r' || charAtIndex == '<' || charAtIndex == '>') { - firstUnwantedIndex--; - if (firstUnwantedIndex < 0) { - break; - } - charAtIndex = attributeValue.charAt(firstUnwantedIndex); - } - - return attributeValue.substring(0, firstUnwantedIndex + 1); - } else { - return attributeValue; - } + return org.netbeans.modules.xml.text.api.XMLTextUtils.actualAttributeValue(attributeValue); } /** @@ -118,18 +91,7 @@ * @return a string that may contain '<', '>', '\'', '"', '&'. */ public static String replaceEntityStringsWithChars(String value) { - StringBuffer buf = new StringBuffer(value); - for (int entity = 0; entity < knownEntityStrings.length; entity++) { - String curEntityString = knownEntityStrings[entity]; - int indexOfEntity = buf.toString().indexOf(curEntityString); - while (indexOfEntity != -1) { - buf.replace(indexOfEntity, indexOfEntity + curEntityString.length(), - new String(new char[]{knownEntityChars[entity]})); - indexOfEntity = buf.toString().indexOf(curEntityString); - } - } - - return buf.toString(); + return org.netbeans.modules.xml.text.api.XMLTextUtils.replaceCharsWithEntityStrings(value); } /** @@ -139,27 +101,7 @@ * @return a string that may contain <", ">", "'", """ and "&" */ public static String replaceCharsWithEntityStrings(String value) { - if (value == null) { - return null; - } - StringBuffer replBuf = new StringBuffer(value.length()); - for (int ind = 0; ind < value.length(); ind++) { - boolean charReplaced = false; - char curChar = value.charAt(ind); - for (int entity = 0; entity < knownEntityChars.length; entity++) { - if (curChar == knownEntityChars[entity]) { - replBuf.append(knownEntityStrings[entity]); - charReplaced = true; - break; - } - } - - if (!charReplaced) { - replBuf.append(curChar); - } - } - - return replBuf.toString(); + return org.netbeans.modules.xml.text.api.XMLTextUtils.replaceCharsWithEntityStrings(value); } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/dom/package.html b/xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/package.html rename from xml.text/src/org/netbeans/modules/xml/text/syntax/dom/package.html rename to xml.text.obsolete90/src/org/netbeans/modules/xml/text/syntax/dom/package.html diff --git a/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample1.pass b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample1.pass new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample1.pass @@ -0,0 +1,17 @@ + + + + + + 30 + + + + + index.jsp + + + diff --git a/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2-.pass b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2-.pass new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2-.pass @@ -0,0 +1,1716 @@ + + + + + + + + + + + + + + + + + + + You need to have ant 1.6.3 at least to build NetBeans. + + + + + + + + + + + + + + + + + + + + + + + + + + + + You have stray *.class files in ${basedir}/antsrc which you must remove. + Probably you failed to clean your sources before updating them from CVS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> + <changes> + + + + </changes> + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> + <apis> + + + + </apis> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The org-openide-util/javadoc.css has to exist as we are refering to + it from to master module javadoc pages. If it does not anymore, update + the javadoctools/export*.xsl templates. + + + + + + + + + + + + + +NetBeans API Index + + + + + + + + +<H2>Frame Alert</H2> +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +Link to<A HREF="overview-summary.html">Non-frame version.</A> + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NetBeans dev build + ------------------ + Number: ${buildnumber} + Date: ${buildday} + Branding: + Branch: trunk + Tag: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Build created; see NetBeans-${buildnum}.zip (in nbbuild/). + If you like, you may run the IDE straight from + the ${netbeans.dest}/bin/ directory. + (For example, type: ant tryme) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Repeat @{clusters-to-build} + + + + + + + + + + + + + Dependency prop :${one.cluster.name}-hasNoDependencies: + Cluster dep :${one.cluster.dependencies}: + + Cluster dep prp:${test.prop}: + + + + + + + + + + + + Cluster ${one.cluster.name} is :${test1.prop}: + + + + + + + ${one-cluster-modules} + Dependencies: ${one-cluster-dependencies} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %define global_product_version ${pkg.version} + %define global_product_release 00 + %define _prefix ${pkg.rpm.prefix} + Version: %{global_product_version} + Release: %{global_product_release} + Group: ${pkg.rpm.group} + Copyright: ${pkg.rpm.copyright} + Vendor: ${pkg.vendor} + URL: ${pkg.rpm.url} + Prefix: %_prefix + AutoReqProv: no + Name: ${pkg.rpm.name} + Summary: ${pkg.name} + %description + ${pkg.desc} + + %files + + %erpm_map ${pkg.rpm.map} nb_destdir + + %dir ${pkg.rpm.map} + + ${pkg.rpm.map}/${one.cluster.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PKG=${pkg.svr4.pkg} + NAME=${pkg.name} + ARCH=sparc + VERSION=${pkg.version} + MAXINST=${pkg.svr4.maxinst} + CATEGORY=${pkg.svr4.category} + SUNW_PKGVERS=${pkg.svr4.sunw_pkgvers} + DESC=${pkg.desc} + VENDOR=${pkg.vendor} + HOTLINE=${pkg.svr4.hotline} + EMAIL=${pkg.email} + CLASSES=${pkg.svr4.classes} + BASEDIR=${pkg.svr4.basedir} + PKGINST=${pkg.svr4.pkginst} + + + + + + + + + + + + + Will not delete ${test.user.dir} because ${test.user.dir.lock} still exists; kill any running process and delete lock file if necessary + + + + + Starting the IDE as a sanity check... + WARNING - the sanity-start target is deprecated. Use commit-validation instead. + + + + + + + + + + + + + + + + + + + + Finished starting the IDE, pay attention to any reported errors. + + + + + + + + + + + WARNING - the nozip-check target is deprecated. Use all-nozip instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + *** WARNING *** + You do not seem to have the modules needed to run the commit validation test suite. + You may not commit any changes into the CVS repository without running these tests. + For more information: http://www.netbeans.org/community/guidelines/commit.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Public packages has changed! *** + + Differences were found while comparing file + ${check.public.packages.template} + with + ${check.public.packages.generated} + + This means that the set of public packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of public packages, then please + update the golden file at + ${check.public.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Friend packages has changed! *** + + Differences were found while comparing file + ${check.friend.packages.template} + with + ${check.friend.packages.generated} + + This means that the set of friend packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of friend packages, then please + update the golden file at + ${check.friend.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Shared packages has changed! *** + + Differences were found while comparing file + ${check.shared.packages.template} + with + ${check.shared.packages.generated} + + This means that the set of shared packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Removing shared packages is ok. Adding shared packages is silly, complicates + and slows down module system and startup of the application. Do not do that! + If you are removing a shared package please update + ${check.shared.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of external libraries has changed! *** + + Differences were found while comparing file + ${check.external.libraries.template} + with + ${check.external.libraries.generated} + + This means that the set of external libraries (JARs that are not NetBeans + modules or does not have NetBeans-Own-Library: true in manifest) has + changed since the previously known one. Some libraries may have been added, + some of them may have been removed, they MD5 checksum or size has been changed. + + Changing the external libraries is ok, but requires legal approval everytime + new version of a library is put into the product. If you have the approval + want to change the list of external libraries, then please + update the golden file at + ${check.external.libraries.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of modules has changed! *** + + Differences were found while comparing file + ${check.modules.template} + with + ${check.modules.generated} + + This means that the set of modules changed since the previously known one. + Adding or removing a module significatly affects the set of APIs the + product offers and as such is subject to review. If you passed + your review and want to change the list of modules, then please + update the golden file at + ${check.modules.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** List of dependencies has changed! *** + + Differences were found while comparing file + ${check.dependencies.template} + with + ${check.dependencies.generated} + + This means that the set of dependencies changed since the previously known one. + Adding a dependency can restrict the ways how a final product can be assembled + and as such it forms an important aspect of API and is subject to review. + If you passed your review or you are sure you want to change the + list of dependencies, then please update the golden file at + ${check.dependencies.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and dependencies being important: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Layout of files has changed! *** + + Differences were found while comparing file ${check.files.layout.generated} with + ${check.files.layout.template} + This means that the layout of files changed since the previously known one. + Some files may have been added, some of them may have been removed or renamed. + + Changing the layout may or may not be ok. If you are sure that you want to + change the layout of files, then update the golden file at + ${check.files.layout.golden} + and run the test once again. If you got this warning without intending + to change the layout of files, think twice whether your commit is really + correct and consider asking for a review first. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and files layout being an API: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Select a top-level module (e.g. "java") to display results for: + + ${listfile}:1: Matches follow... (click on hyperlinks from IDE!) + (warning: 'exclude' directives not honored here yet) + + + + + + + + + + + + + + diff --git a/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2.pass b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2.pass new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/test/unit/data/goldenfiles/org/netbeans/modules/xml/text/indent/XMLFormatterTest/testReformatSample2.pass @@ -0,0 +1,1739 @@ + + + + + + + + + + + + + + + + + + + You need to have ant 1.6.3 at least to build NetBeans. + + + + + + + + + + + + + + + + + + + + + + + + + + + + You have stray *.class files in ${basedir}/antsrc which you must remove. + Probably you failed to clean your sources before updating them from CVS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> + <changes> + + + + </changes> + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> + <apis> + + + + </apis> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The org-openide-util/javadoc.css has to exist as we are refering to + it from to master module javadoc pages. If it does not anymore, update + the javadoctools/export*.xsl templates. + + + + + + + + + + + + + +NetBeans API Index + + + + + + + + +<H2>Frame Alert</H2> +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +Link to<A HREF="overview-summary.html">Non-frame version.</A> + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NetBeans dev build + ------------------ + Number: ${buildnumber} + Date: ${buildday} + Branding: + Branch: trunk + Tag: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Build created; see NetBeans-${buildnum}.zip (in nbbuild/). + If you like, you may run the IDE straight from + the ${netbeans.dest}/bin/ directory. + (For example, type: ant tryme) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Repeat @{clusters-to-build} + + + + + + + + + + + + + Dependency prop :${one.cluster.name}-hasNoDependencies: + Cluster dep :${one.cluster.dependencies}: + + Cluster dep prp:${test.prop}: + + + + + + + + + + + + Cluster ${one.cluster.name} is :${test1.prop}: + + + + + + + ${one-cluster-modules} + Dependencies: ${one-cluster-dependencies} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %define global_product_version ${pkg.version} + %define global_product_release 00 + %define _prefix ${pkg.rpm.prefix} + Version: %{global_product_version} + Release: %{global_product_release} + Group: ${pkg.rpm.group} + Copyright: ${pkg.rpm.copyright} + Vendor: ${pkg.vendor} + URL: ${pkg.rpm.url} + Prefix: %_prefix + AutoReqProv: no + Name: ${pkg.rpm.name} + Summary: ${pkg.name} + %description + ${pkg.desc} + + %files + + %erpm_map ${pkg.rpm.map} nb_destdir + + %dir ${pkg.rpm.map} + + ${pkg.rpm.map}/${one.cluster.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PKG=${pkg.svr4.pkg} + NAME=${pkg.name} + ARCH=sparc + VERSION=${pkg.version} + MAXINST=${pkg.svr4.maxinst} + CATEGORY=${pkg.svr4.category} + SUNW_PKGVERS=${pkg.svr4.sunw_pkgvers} + DESC=${pkg.desc} + VENDOR=${pkg.vendor} + HOTLINE=${pkg.svr4.hotline} + EMAIL=${pkg.email} + CLASSES=${pkg.svr4.classes} + BASEDIR=${pkg.svr4.basedir} + PKGINST=${pkg.svr4.pkginst} + + + + + + + + + + + + + Will not delete ${test.user.dir} because ${test.user.dir.lock} still exists; kill any running process and delete lock file if necessary + + + + + Starting the IDE as a sanity check... + WARNING - the sanity-start target is deprecated. Use commit-validation instead. + + + + + + + + + + + + + + + + + + + + Finished starting the IDE, pay attention to any reported errors. + + + + + + + + + + + WARNING - the nozip-check target is deprecated. Use all-nozip instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + *** WARNING *** + You do not seem to have the modules needed to run the commit validation test suite. + You may not commit any changes into the CVS repository without running these tests. + For more information: http://www.netbeans.org/community/guidelines/commit.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Public packages has changed! *** + + Differences were found while comparing file + ${check.public.packages.template} + with + ${check.public.packages.generated} + + This means that the set of public packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of public packages, then please + update the golden file at + ${check.public.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Friend packages has changed! *** + + Differences were found while comparing file + ${check.friend.packages.template} + with + ${check.friend.packages.generated} + + This means that the set of friend packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of friend packages, then please + update the golden file at + ${check.friend.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Shared packages has changed! *** + + Differences were found while comparing file + ${check.shared.packages.template} + with + ${check.shared.packages.generated} + + This means that the set of shared packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Removing shared packages is ok. Adding shared packages is silly, complicates + and slows down module system and startup of the application. Do not do that! + If you are removing a shared package please update + ${check.shared.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of external libraries has changed! *** + + Differences were found while comparing file + ${check.external.libraries.template} + with + ${check.external.libraries.generated} + + This means that the set of external libraries (JARs that are not NetBeans + modules or does not have NetBeans-Own-Library: true in manifest) has + changed since the previously known one. Some libraries may have been added, + some of them may have been removed, they MD5 checksum or size has been changed. + + Changing the external libraries is ok, but requires legal approval everytime + new version of a library is put into the product. If you have the approval + want to change the list of external libraries, then please + update the golden file at + ${check.external.libraries.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of modules has changed! *** + + Differences were found while comparing file + ${check.modules.template} + with + ${check.modules.generated} + + This means that the set of modules changed since the previously known one. + Adding or removing a module significatly affects the set of APIs the + product offers and as such is subject to review. If you passed + your review and want to change the list of modules, then please + update the golden file at + ${check.modules.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** List of dependencies has changed! *** + + Differences were found while comparing file + ${check.dependencies.template} + with + ${check.dependencies.generated} + + This means that the set of dependencies changed since the previously known one. + Adding a dependency can restrict the ways how a final product can be assembled + and as such it forms an important aspect of API and is subject to review. + If you passed your review or you are sure you want to change the + list of dependencies, then please update the golden file at + ${check.dependencies.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and dependencies being important: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Layout of files has changed! *** + + Differences were found while comparing file ${check.files.layout.generated} with + ${check.files.layout.template} + This means that the layout of files changed since the previously known one. + Some files may have been added, some of them may have been removed or renamed. + + Changing the layout may or may not be ok. If you are sure that you want to + change the layout of files, then update the golden file at + ${check.files.layout.golden} + and run the test once again. If you got this warning without intending + to change the layout of files, think twice whether your commit is really + correct and consider asking for a review first. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and files layout being an API: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Select a top-level module (e.g. "java") to display results for: + + ${listfile}:1: Matches follow... (click on hyperlinks from IDE!) + (warning: 'exclude' directives not honored here yet) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/netbeans_build.xml b/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/netbeans_build.xml new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/netbeans_build.xml @@ -0,0 +1,1739 @@ + + + + + + + + + + + + + + + + + + + You need to have ant 1.6.3 at least to build NetBeans. + + + + + + + + + + + + + + + + + + + + + + + + + + + + You have stray *.class files in ${basedir}/antsrc which you must remove. + Probably you failed to clean your sources before updating them from CVS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> +<changes> + + + + </changes> + + + + + + + + + + <?xml version="1.0" encoding="UTF-8"?> +<apis> + + + + </apis> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The org-openide-util/javadoc.css has to exist as we are refering to + it from to master module javadoc pages. If it does not anymore, update + the javadoctools/export*.xsl templates. + + + + + + + + + + + + + +NetBeans API Index + + + + + + + + +<H2>Frame Alert</H2> +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +Link to<A HREF="overview-summary.html">Non-frame version.</A> + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NetBeans dev build +------------------ +Number: ${buildnumber} +Date: ${buildday} +Branding: +Branch: trunk +Tag: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Build created; see NetBeans-${buildnum}.zip (in nbbuild/). +If you like, you may run the IDE straight from +the ${netbeans.dest}/bin/ directory. +(For example, type: ant tryme) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Repeat @{clusters-to-build} + + + + + + + + + + + + + Dependency prop :${one.cluster.name}-hasNoDependencies: + Cluster dep :${one.cluster.dependencies}: + + Cluster dep prp:${test.prop}: + + + + + + + + + + + + Cluster ${one.cluster.name} is :${test1.prop}: + + + + + + + ${one-cluster-modules} + Dependencies: ${one-cluster-dependencies} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%define global_product_version ${pkg.version} +%define global_product_release 00 +%define _prefix ${pkg.rpm.prefix} +Version: %{global_product_version} +Release: %{global_product_release} +Group: ${pkg.rpm.group} +Copyright: ${pkg.rpm.copyright} +Vendor: ${pkg.vendor} +URL: ${pkg.rpm.url} +Prefix: %_prefix +AutoReqProv: no +Name: ${pkg.rpm.name} +Summary: ${pkg.name} +%description +${pkg.desc} + +%files + +%erpm_map ${pkg.rpm.map} nb_destdir + +%dir ${pkg.rpm.map} + +${pkg.rpm.map}/${one.cluster.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +PKG=${pkg.svr4.pkg} +NAME=${pkg.name} +ARCH=sparc +VERSION=${pkg.version} +MAXINST=${pkg.svr4.maxinst} +CATEGORY=${pkg.svr4.category} +SUNW_PKGVERS=${pkg.svr4.sunw_pkgvers} +DESC=${pkg.desc} +VENDOR=${pkg.vendor} +HOTLINE=${pkg.svr4.hotline} +EMAIL=${pkg.email} +CLASSES=${pkg.svr4.classes} +BASEDIR=${pkg.svr4.basedir} +PKGINST=${pkg.svr4.pkginst} + + + + + + + + + + + + + Will not delete ${test.user.dir} because ${test.user.dir.lock} still exists; kill any running process and delete lock file if necessary + + + + + Starting the IDE as a sanity check... + WARNING - the sanity-start target is deprecated. Use commit-validation instead. + + + + + + + + + + + + + + + + + + + + Finished starting the IDE, pay attention to any reported errors. + + + + + + + + + + + WARNING - the nozip-check target is deprecated. Use all-nozip instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + *** WARNING *** + You do not seem to have the modules needed to run the commit validation test suite. + You may not commit any changes into the CVS repository without running these tests. + For more information: http://www.netbeans.org/community/guidelines/commit.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Public packages has changed! *** + + Differences were found while comparing file + ${check.public.packages.template} + with + ${check.public.packages.generated} + + This means that the set of public packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of public packages, then please + update the golden file at + ${check.public.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Friend packages has changed! *** + + Differences were found while comparing file + ${check.friend.packages.template} + with + ${check.friend.packages.generated} + + This means that the set of friend packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Changing the packages may or may not be ok. It means that an api of + whole product changes and as such it is subject to review. If you passed + your review and want to change the list of friend packages, then please + update the golden file at + ${check.friend.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** Shared packages has changed! *** + + Differences were found while comparing file + ${check.shared.packages.template} + with + ${check.shared.packages.generated} + + This means that the set of shared packages changed since the previously known one. + Some packages may have been added, some of them may have been removed + Either by changing manifest of a module or by adding or removing a class file + from a module package. + + + Removing shared packages is ok. Adding shared packages is silly, complicates + and slows down module system and startup of the application. Do not do that! + If you are removing a shared package please update + ${check.shared.packages.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of external libraries has changed! *** + + Differences were found while comparing file + ${check.external.libraries.template} + with + ${check.external.libraries.generated} + + This means that the set of external libraries (JARs that are not NetBeans + modules or does not have NetBeans-Own-Library: true in manifest) has + changed since the previously known one. Some libraries may have been added, + some of them may have been removed, they MD5 checksum or size has been changed. + + Changing the external libraries is ok, but requires legal approval everytime + new version of a library is put into the product. If you have the approval + want to change the list of external libraries, then please + update the golden file at + ${check.external.libraries.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + ! + *** List of modules has changed! *** + + Differences were found while comparing file + ${check.modules.template} + with + ${check.modules.generated} + + This means that the set of modules changed since the previously known one. + Adding or removing a module significatly affects the set of APIs the + product offers and as such is subject to review. If you passed + your review and want to change the list of modules, then please + update the golden file at + ${check.modules.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** List of dependencies has changed! *** + + Differences were found while comparing file + ${check.dependencies.template} + with + ${check.dependencies.generated} + + This means that the set of dependencies changed since the previously known one. + Adding a dependency can restrict the ways how a final product can be assembled + and as such it forms an important aspect of API and is subject to review. + If you passed your review or you are sure you want to change the + list of dependencies, then please update the golden file at + ${check.dependencies.golden} + and run the test once again. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and dependencies being important: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + *** Layout of files has changed! *** + + Differences were found while comparing file ${check.files.layout.generated} with + ${check.files.layout.template} + This means that the layout of files changed since the previously known one. + Some files may have been added, some of them may have been removed or renamed. + + Changing the layout may or may not be ok. If you are sure that you want to + change the layout of files, then update the golden file at + ${check.files.layout.golden} + and run the test once again. If you got this warning without intending + to change the layout of files, think twice whether your commit is really + correct and consider asking for a review first. + + Read more about the Verification Framework: + http://openide.netbeans.org/proposals/arch/clusters.html#verify + + Look at for information about reviews: + http://openide.netbeans.org/tutorial/review-steps.html + + Check the page about APIs and files layout being an API: + http://openide.netbeans.org/tutorial/api-design.html#api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Select a top-level module (e.g. "java") to display results for: + + ${listfile}:1: Matches follow... (click on hyperlinks from IDE!) + (warning: 'exclude' directives not honored here yet) + + + + + + + + + + + + + + diff --git a/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/web.xml b/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/web.xml new file mode 100644 --- /dev/null +++ b/xml.text.obsolete90/test/unit/data/input/XMLFormatterTest/testReformat/web.xml @@ -0,0 +1,17 @@ + + + + + +30 + + + + + index.jsp + + + diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java rename from xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java rename to xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java +++ b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/indent/XMLFormatterTest.java @@ -79,7 +79,7 @@ public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new XMLFormatterTest("testReformatSample1")); - //suite.addTest(new XMLFormatterTest("testReformatSample2")); + suite.addTest(new XMLFormatterTest("testReformatSample2")); return suite; } diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/AbstractTestCase.java copy from xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java copy to xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/AbstractTestCase.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java +++ b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/AbstractTestCase.java @@ -39,7 +39,7 @@ * * Portions Copyrighted 2007 Sun Microsystems, Inc. */ -package org.netbeans.modules.xml.text; +package org.netbeans.modules.xml.text.syntax; import java.io.BufferedReader; import java.io.IOException; @@ -52,13 +52,11 @@ import org.netbeans.api.lexer.Language; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.netbeans.modules.xml.xam.ModelSource; import org.netbeans.modules.xml.xdm.XDMModel; import org.netbeans.modules.xml.xdm.diff.DefaultElementIdentity; import org.netbeans.modules.xml.xdm.diff.DiffFinder; import org.netbeans.modules.xml.xdm.diff.Difference; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; @@ -89,6 +87,10 @@ } protected static BaseDocument getResourceAsDocument(String path) throws Exception { + // AbstractTestCase was repackaged, tests typically contain path rooted at xml.text package. + if (path.startsWith("syntax/")) { + path = path.substring(7); + } InputStream in = AbstractTestCase.class.getResourceAsStream(path); BaseDocument sd = new BaseDocument(true, "text/xml"); //NOI18N BufferedReader br = new BufferedReader(new InputStreamReader(in,"UTF-8")); diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java copy from xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java copy to xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java +++ b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java @@ -45,7 +45,6 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.AbstractTestCase; /** * diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/invalid.xml b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/invalid.xml copy from xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/invalid.xml copy to xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/invalid.xml diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/test.xml b/xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/test.xml copy from xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/test.xml copy to xml.text.obsolete90/test/unit/src/org/netbeans/modules/xml/text/syntax/test.xml diff --git a/xml.text/apichanges.xml b/xml.text/apichanges.xml --- a/xml.text/apichanges.xml +++ b/xml.text/apichanges.xml @@ -107,6 +107,70 @@ + + Syntax API deprecated + + + + + +

+ The xml.text.syntax API uses the old and long deprecated lexer. The API is now moved to a new compatibility-only + xml.text.deprecated90 module and a new API in org.netbeans.modules.xml.text.api.dom package is offered. +

+

+ The following classes/packages have been moved to xml.text.obsolete90 module: +

+
    +
  • + org.netbeans.modules.xml.text.syntax +
      +
    • DTDSyntaxTokenMapper
    • +
    • DTDTokenContext
    • +
    • SyntaxElement
    • +
    • UnicodeClasses
    • +
    • XMLDefaultSyntax
    • +
    • XMLSyntaxSupport
    • +
    • XMLSyntaxTokenMapper
    • +
    • XMLTokenIDs
    • +
    +
  • +
  • + org.netbeans.modules.xml.text.syntax.dom +
      +
    • AttrImpl
    • +
    • CDataSectionImpl
    • +
    • CommentImpl
    • +
    • DocumentTypeImpl
    • +
    • EmptyTag
    • +
    • EndTag
    • +
    • EntityReferenceImpl
    • +
    • ProcessingInstructionImpl
    • +
    • StartTag
    • +
    • SyntaxNode
    • +
    • TextImpl
    • +
    • Util
    • +
    +
  • +
  • + org.netbeans.modules.xml.text.indent +
      +
    • XMLFormatter
    • +
    +
  • +
  • + org.netbeans.modules.xml.text.api +
      +
    • XMLDefaultTokenContext
    • +
    +
  • +
+
+ + + + +
Removing old settings classes diff --git a/xml.text/manifest.mf b/xml.text/manifest.mf --- a/xml.text/manifest.mf +++ b/xml.text/manifest.mf @@ -3,4 +3,5 @@ OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/xml/text/resources/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/xml/text/resources/mf-layer.xml AutoUpdate-Show-In-Client: false -OpenIDE-Module-Specification-Version: 1.54 +OpenIDE-Module-Implementation-Version: 1 + diff --git a/java.source/module-auto-deps.xml b/xml.text/module-auto-deps.xml copy from java.source/module-auto-deps.xml copy to xml.text/module-auto-deps.xml --- a/java.source/module-auto-deps.xml +++ b/xml.text/module-auto-deps.xml @@ -48,17 +48,14 @@ - The old editor settings and completion APIs have been deprecated, see http://wiki.netbeans.org/EditorSettingsUpgrade and update your module. + XML SyntaxElement API that depends on obsolete Lexer was deprecated and removed from main module. - + - - - - + diff --git a/xml.text/nbproject/project.properties b/xml.text/nbproject/project.properties --- a/xml.text/nbproject/project.properties +++ b/xml.text/nbproject/project.properties @@ -40,7 +40,7 @@ # Version 2 license, then the option applies only if the new code is # made subject to such option by the copyright holder. -javac.source=1.7 +javac.source=1.8 test.unit.cp.extra=${openide.dir}/core/openide.jar:${openide.loaders.dir}/core/openide-loaders.jar test.unit.run.cp.extra=${test.unit.cp.extra} @@ -52,3 +52,5 @@ test.config.stableBTD.excludes=\ org/netbeans/modules/xml/text/completion/CompletionJTest.class,\ org/netbeans/modules/xml/text/syntax/ColoringTest.class +spec.version.base=1.60.0 + diff --git a/xml.text/nbproject/project.xml b/xml.text/nbproject/project.xml --- a/xml.text/nbproject/project.xml +++ b/xml.text/nbproject/project.xml @@ -50,6 +50,15 @@ org.netbeans.modules.xml.text + org.netbeans.api.annotations.common + + + + 1 + 1.28 + + + org.netbeans.api.progress @@ -131,6 +140,14 @@ + org.netbeans.modules.editor.document + + + + 1.0 + + + org.netbeans.modules.editor.fold @@ -149,6 +166,12 @@ + org.netbeans.modules.editor.indent.support + + 1.40 + + + org.netbeans.modules.editor.lib @@ -167,14 +190,6 @@ - org.netbeans.modules.editor.document - - - - 1.0 - - - org.netbeans.modules.editor.mimelookup @@ -297,7 +312,7 @@ - 7.61 + 7.61 @@ -325,14 +340,6 @@ - org.openide.util.ui - - - - 9.3 - - - org.openide.util @@ -349,6 +356,14 @@ + org.openide.util.ui + + + + 9.3 + + + org.openide.windows @@ -356,12 +371,6 @@ 6.2 - - org.netbeans.modules.editor.indent.support - - 1.40 - - @@ -450,12 +459,13 @@ org.netbeans.modules.xml.schema.abe org.netbeans.modules.xml.schema.completion org.netbeans.modules.xml.schema.ui.basic + org.netbeans.modules.xml.text.obsolete90 org.netbeans.modules.xsl org.netbeans.modules.xslt.core org.netbeans.modules.xml.text.api + org.netbeans.modules.xml.text.api.dom org.netbeans.modules.xml.text.navigator.base org.netbeans.modules.xml.text.syntax - org.netbeans.modules.xml.text.syntax.dom diff --git a/xml.text/src/org/netbeans/modules/xml/text/ComplexValueSettingsFactory.java b/xml.text/src/org/netbeans/modules/xml/text/ComplexValueSettingsFactory.java --- a/xml.text/src/org/netbeans/modules/xml/text/ComplexValueSettingsFactory.java +++ b/xml.text/src/org/netbeans/modules/xml/text/ComplexValueSettingsFactory.java @@ -42,14 +42,10 @@ package org.netbeans.modules.xml.text; -import java.util.Collections; -import java.util.List; import org.netbeans.editor.Acceptor; import org.netbeans.editor.AcceptorFactory; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; import org.netbeans.modules.xml.text.indent.DTDIndentEngine; import org.netbeans.modules.xml.text.indent.XMLIndentEngine; -import org.netbeans.modules.xml.text.syntax.DTDTokenContext; import org.openide.text.IndentEngine; /** @@ -62,10 +58,6 @@ // XML settings factory methods // ----------------------------------------------------------------------- - // XXX: use lexer - public static List getXMLTokenContext() { - return Collections.singletonList(XMLDefaultTokenContext.context); - } // XXX: use new editor.indent API public static IndentEngine getXMLIndentEngine() { return new XMLIndentEngine(); @@ -81,10 +73,6 @@ // DTD settings factory methods // ----------------------------------------------------------------------- - // XXX: use lexer - public static List getDTDTokenContext() { - return Collections.singletonList(DTDTokenContext.context); - } // XXX: use new editor.indent API public static IndentEngine getDTDIndentEngine() { return new DTDIndentEngine(); diff --git a/xml.text/src/org/netbeans/modules/xml/text/api/XMLTextUtils.java b/xml.text/src/org/netbeans/modules/xml/text/api/XMLTextUtils.java new file mode 100644 --- /dev/null +++ b/xml.text/src/org/netbeans/modules/xml/text/api/XMLTextUtils.java @@ -0,0 +1,203 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.api; + +import org.netbeans.api.editor.document.AtomicLockDocument; +import org.netbeans.api.editor.document.LineDocument; +import org.netbeans.api.editor.document.LineDocumentUtils; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.indent.XMLLexerFormatter; + +/** + * Miscellaneous utilities for working with XML in text form. This class + * replaces the old Util class which contains references to old lexer and was + * removed to the {@code xml.text.obsolete90} module. + * + * @author sdedic + * @since 1.60 + */ +public final class XMLTextUtils { + private XMLTextUtils() {} + + /** + * MIME type for the text/xml documents. + */ + public static final String XML_MIME = "text/xml"; + + static String[] knownEntityStrings = {"<", ">", "'", """, "&"}; + + static char[] knownEntityChars = {'<', '>', '\'', '"', '&'}; + + /** + * Handle fuzziness of attribute end detection. Advances the passed TokenSequence + * to the token after attribute value end delimiter. The delimiter (quote, doublequote) + * is passed as a parameter. The method returns the token after the attribute value if the delimiter is + * found and positions the TokenSequence to the returned token. If there's no delimiter, + * the method returns {@code null} and the TokenSequence position/state is not defined. + * + * @return Token after attribute value or null. + */ + public static Token skipAttributeValue(TokenSequence ts, char delim) { + boolean ok = true; + for (; ok; ok = ts.moveNext()) { + Token next = ts.token(); + CharSequence cs = next.text(); + if (cs.charAt(cs.length() - 1) == delim) { + ts.moveNext(); + return ts.token(); + } + } + return null; + } + + /** + * This method looks for '<' and '>' characters in attributes values and + * returns whitespace-stripped substring which does not contain '<' or '>'. + * This method should be used to calculate an attribute value which has + * not currently been closed. + * @param attributeValue an original attribute value + * @return the same value of stripped substring of it. + */ + public static String actualAttributeValue(String attributeValue) { + int ltIndex = attributeValue.indexOf('<'); // NOI18N + int gtIndex = attributeValue.indexOf('>'); // NOI18N + int firstUnwantedIndex = -1; + if (gtIndex != -1) { + if (ltIndex != -1 && ltIndex < gtIndex) { + firstUnwantedIndex = ltIndex; + } else { + firstUnwantedIndex = gtIndex; + } + } else { + firstUnwantedIndex = ltIndex; + } + + if (firstUnwantedIndex != -1) { + char charAtIndex = attributeValue.charAt(firstUnwantedIndex); + while (charAtIndex == ' ' || charAtIndex == '\t' || charAtIndex == '\n' || + charAtIndex == '\r' || charAtIndex == '<' || charAtIndex == '>') { + firstUnwantedIndex--; + if (firstUnwantedIndex < 0) { + break; + } + charAtIndex = attributeValue.charAt(firstUnwantedIndex); + } + + return attributeValue.substring(0, firstUnwantedIndex + 1); + } else { + return attributeValue; + } + } + + /** + * Replaces "<", ">", "'", """, "&" with + * '<', '>', '\'', '"', '&'. + * @param a string that may contain <", ">", "'", """ and "&" + * @return a string that may contain '<', '>', '\'', '"', '&'. + */ + public static String replaceEntityStringsWithChars(String value) { + StringBuffer buf = new StringBuffer(value); + for (int entity = 0; entity < knownEntityStrings.length; entity++) { + String curEntityString = knownEntityStrings[entity]; + int indexOfEntity = buf.toString().indexOf(curEntityString); + while (indexOfEntity != -1) { + buf.replace(indexOfEntity, indexOfEntity + curEntityString.length(), + new String(new char[]{knownEntityChars[entity]})); + indexOfEntity = buf.toString().indexOf(curEntityString); + } + } + + return buf.toString(); + } + + /** + * Replaces '<', '>', '\'', '"', '&' with + * "<", ">", "'", """, "&". + * @param a string that may contain '<', '>', '\'', '"', '&'. + * @return a string that may contain <", ">", "'", """ and "&" + */ + public static String replaceCharsWithEntityStrings(String value) { + if (value == null) { + return null; + } + StringBuffer replBuf = new StringBuffer(value.length()); + for (int ind = 0; ind < value.length(); ind++) { + boolean charReplaced = false; + char curChar = value.charAt(ind); + for (int entity = 0; entity < knownEntityChars.length; entity++) { + if (curChar == knownEntityChars[entity]) { + replBuf.append(knownEntityStrings[entity]); + charReplaced = true; + break; + } + } + + if (!charReplaced) { + replBuf.append(curChar); + } + } + + return replBuf.toString(); + } + + + /** + * Convenience method to reformat portion of document using XML reformatter. + * @param doc + * @param startOffset + * @param endOffset + * @throw IllegalArgumentException if the document implementation is not compatible + */ + public static void reformat(final LineDocument doc, final int startOffset, final int endOffset) { + final XMLLexerFormatter formatter = new XMLLexerFormatter(null); + AtomicLockDocument ald = LineDocumentUtils.asRequired(doc, AtomicLockDocument.class); + ald.runAtomic(new Runnable() { + public void run() { + formatter.doReformat(doc, startOffset, endOffset); + } + }); + } + +} + diff --git a/xml.text/src/org/netbeans/modules/xml/text/api/dom/SyntaxElement.java b/xml.text/src/org/netbeans/modules/xml/text/api/dom/SyntaxElement.java new file mode 100644 --- /dev/null +++ b/xml.text/src/org/netbeans/modules/xml/text/api/dom/SyntaxElement.java @@ -0,0 +1,125 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.api.dom; + +import javax.swing.text.Document; +import org.netbeans.api.annotations.common.CheckForNull; +import org.w3c.dom.Node; + +/** + * Abstract predecessor for all syntax elements - nodes, tags, attributes. + * SyntaxElement represents a piece of XML document, similar to W3C Node, exposes offset + * into the underlying text. Since the syntax model + * can represent an error, which is not a W3C Node. For regular pieces of + * text, W3C Node can be obtained ({@link #getNode}. Nodes obtained from SyntaxElements can be converted back + * using {@link XMLSyntaxSupport#getSyntaxElement}. + *

+ * Obtaining previous or next element may result in lexing through the doucment - a document read + * lock is internally obtained. If the caller plans to traverse through the document, document read lock for the + * whole operation should be obtained, i.e. using {@link Document#render}. + *

+ * Erroneous pieces of text are represented by SyntaxElement, which is NOT convertible to a Node. Error elements + * have the {@link #getType} or {@link #NODE_ERROR}. + *

+ * Note: use {@link #getType} instead of {@code instanceof} operator to check for a particular + * element type. Do not downcast the {@code SyntaxElement}, use {@link #getNode} to get the DOM Node + * implementation. If the {@link #getType} returns {@link Node#ELEMENT_NODE}, it is safe to downcast + * {@code SyntaxElement} to a {@link TagElement} and use extended interface. + * + * @author sdedic + * @sice 1.60 + */ +public interface SyntaxElement { + /** + * Special type of element which represent an Erroneous piece of text + */ + public static final int NODE_ERROR = -1; + + /** + * Returns the next element in textual order. + * @return next element or {@code null} + */ + @CheckForNull + public SyntaxElement getNext(); + + /** + * Provides the previous lexical element, in textual order + * @return previous element or {@code null} + */ + @CheckForNull + public SyntaxElement getPrevious(); + + /** + * @return length of the element, including children + */ + public int getElementLength(); + + /** + * Provides element's offset in the underlying document. Note that unless + * accessed under document read-lock, the offset may not point a the correct place + * in the document. + * @return offset of the element start + */ + public int getElementOffset(); + + /** + * Returns type of the node. The return value is one of the W3C Node types, + * or {@link #NODE_ERROR} + * @return type of element + */ + public int getType(); + + /** + * Returns Node, if the instance can be represented in W3C DOM model. + * @return represented Node or {@code null}. + */ + @CheckForNull + public T getNode(); + + /** + * Returns the parent element. + * @return parent element or {@code null} + */ + @CheckForNull + public SyntaxElement getParentElement(); + +} diff --git a/xml.text/src/org/netbeans/modules/xml/text/api/dom/TagElement.java b/xml.text/src/org/netbeans/modules/xml/text/api/dom/TagElement.java new file mode 100644 --- /dev/null +++ b/xml.text/src/org/netbeans/modules/xml/text/api/dom/TagElement.java @@ -0,0 +1,95 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.api.dom; + +import org.netbeans.api.annotations.common.CheckForNull; + +/** + * Interface implemented by start/end tags. Use it to check what kind + * of tag the SyntaxElement is. SyntaxElement can be only casted if its + * {@link SyntaxElement#getType) returns {@link Node#ELEMENT_NODE}. + *

+ * {@link #getStartTag} and {@link #getEndTag} can be used to navigate over to + * the paired element (and then possibly next in the textual order). Note that start + * tag returns itself as start tag, and end tag returns itself from its {@code getEndTag}. + * A self-closing tag will return itself from both methods. + *

+ * In order to access element's name or attributes, please use DOM API (e.g. + * {@code element.getNode().getNodeName()} to get tag name). + * + * @author Svatopluk Dedic + * @since 1.60 + */ +public interface TagElement extends SyntaxElement { + + /** + * @return true, if the element is a regular start element + */ + public boolean isStart(); + + /** + * @return true, if the element is a regular closing element. + */ + public boolean isEnd(); + + /** + * @return true, if self-closing element without any textual content + */ + public boolean isSelfClosing(); + + /** + * Start element for this TagElement. Returns itself if {@link #isStart} or {@link #isSelfClosing()} is true. + * May return {@code null} if the document is not well formed + * @return corresponding start element. + */ + @CheckForNull + public TagElement getStartTag(); + + /** + * Element element for this TagElement. Returns itself if {@link #isEnd} or {@link #isSelfClosing()} is true. + * May return {@code null} if the document is not well formed + * @return corresponding start element. + */ + @CheckForNull + public TagElement getEndTag(); + +} diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupport.java b/xml.text/src/org/netbeans/modules/xml/text/api/dom/XMLSyntaxSupport.java rename from xml.text/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupport.java rename to xml.text/src/org/netbeans/modules/xml/text/api/dom/XMLSyntaxSupport.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupport.java +++ b/xml.text/src/org/netbeans/modules/xml/text/api/dom/XMLSyntaxSupport.java @@ -42,113 +42,488 @@ * made subject to such option by the copyright holder. */ -package org.netbeans.modules.xml.text.dom; +package org.netbeans.modules.xml.text.api.dom; +import com.sun.istack.internal.NotNull; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Deque; +import java.util.EnumSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Stack; import java.util.WeakHashMap; +import java.util.concurrent.Callable; +import java.util.function.BiPredicate; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.api.annotations.common.NullUnknown; +import org.netbeans.api.editor.document.LineDocument; import org.netbeans.api.lexer.Token; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.xml.lexer.XMLTokenId; +import static org.netbeans.api.xml.lexer.XMLTokenId.ARGUMENT; +import static org.netbeans.api.xml.lexer.XMLTokenId.OPERATOR; import org.netbeans.editor.BaseDocument; -import org.openide.util.WeakListeners; +import org.netbeans.modules.xml.text.dom.BaseSyntaxElement; +import org.netbeans.modules.xml.text.dom.CDATASection; +import org.netbeans.modules.xml.text.dom.Comment; +import org.netbeans.modules.xml.text.dom.DocumentType; +import org.netbeans.modules.xml.text.dom.EmptyTag; +import org.netbeans.modules.xml.text.dom.EndTag; +import org.netbeans.modules.xml.text.dom.ProcessingInstruction; +import org.netbeans.modules.xml.text.dom.StartTag; +import org.netbeans.modules.xml.text.dom.TextImpl; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; /** - * Creates higher level syntax elements (DOM nodes) above token chain. - * + * Creates higher level syntax elements (DOM nodes) above token chain from XML lexer. + * The support class provides API to access lexical tokens around a particular location + * and build a navigable DOM-like structure for the text over the lexer output so the + * clients may read attributes, values and traverse the document. The structure may + * be built incrementally on demand so if the client traverses or works with the entire + * structure, the document should be read-locked; otherwise the element starts/ends may get + * screwed by concurrent document mutations. + *

+ * The XMLSyntaxSupport creates DOM node implementations based on the lexer tokens. The entire + * structure is coupled together but its entry points are only weakly referenced; once the caller + * looses all references to SyntaxElements and XMLSyntaxSupport, the entire structure may + * be collected. + *

+ * SyntaxElements are created on-demand and incrementally. + * It's not guaranteed that {@link #getElementChain} returns the same instance + * for the same offset if called multiple times. Also when document is traversed starting from + * different SyntaxElements, the same offset/place in the document may be represented by + * different SyntaxElement instances in both traversals. Use {@link SyntaxElement#getElementOffset} to + * check if the underlying location is the same. + *

+ * In order to traverse through lexical {@link Token}s, the client may call {@link #runWithSequence(int, org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable)} + * and get access to the {@link TokenSequence} of XML tokens. User code executes with document + * read-locked and all calls from user code to {@link #getPreviousToken(int)}, {@link #getNextToken(int)} will use that + * same sequence, so the sequence can be queried for current offset or repositioned. + * * @author Samaresh Panda + * @author Svatopluk Dedic + * @since 1.60 */ -public class XMLSyntaxSupport { +public final class XMLSyntaxSupport { /** Holds last character user have typed. */ - private char lastInsertedChar = 'X'; // NOI18N private final DocumentMonitor documentMonitor; - private BaseDocument document; - private static WeakHashMap supportMap = - new WeakHashMap(); + private final BaseDocument document; + private final static Map> supportMap = + new WeakHashMap<>(); /** Creates new XMLSyntaxSupport */ private XMLSyntaxSupport(BaseDocument doc) { this.document = doc; - documentMonitor = new DocumentMonitor(); - DocumentListener l = WeakListeners.document(documentMonitor, doc); - doc.addDocumentListener(l); + documentMonitor = createDocumentMonitor(); + } + + private DocumentMonitor createDocumentMonitor() { + synchronized (document) { + Object o = document.getProperty(DocumentMonitor.class); + if (o != null) { + return (DocumentMonitor)o; + } + DocumentMonitor m = new DocumentMonitor(); + document.addDocumentListener(m); + document.putProperty(DocumentMonitor.class, m); + return m; + } + } + + /** + * Creates a new instance for the given document. The instance will not be + * registered anywhere; the caller is responsible for bookkeeping. The method + * can return null if the document implementation is not appropriate (does + * not offer appropriate API/services). NB editor documents are guaranteed + * to work with this support. + * + * @param d document + * @return XML support instance, or {@code null} for incompatible documents. + */ + @CheckForNull + public static XMLSyntaxSupport createSyntaxSupport(Document d) { + if (d == null) { + throw new NullPointerException("Document may not be null"); + } + if (!(d instanceof BaseDocument)) { + return null; + } + BaseDocument doc = (BaseDocument)d; + return new XMLSyntaxSupport(doc); } - public static XMLSyntaxSupport getSyntaxSupport(BaseDocument doc) { - XMLSyntaxSupport support = supportMap.get(doc); + /** + * Obtains XML Syntax support for the document. The instance may be shared + * with different callers working with the same Document instance. May return + * {@code null} for an incompatible Document; NB Editor documents are guaranteed + * to work. + * + * @param d underlying document + * @return syntax support + */ + @CheckForNull + public static XMLSyntaxSupport getSyntaxSupport(Document d) { + if (d == null) { + throw new NullPointerException("Document may not be null"); + } + if (!(d instanceof BaseDocument)) { + return null; + } + BaseDocument doc = (BaseDocument)d; + XMLSyntaxSupport support = null; + Reference refSupport = supportMap.get(doc); + if (refSupport != null) { + support = refSupport.get(); + } if(support != null) return support; support = new XMLSyntaxSupport(doc); - supportMap.put(doc, support); + supportMap.put(doc, new WeakReference<>(support)); return support; } - public BaseDocument getDocument() { + /** + * @return underlying Document instance + */ + @NotNull + public LineDocument getDocument() { return document; } /** + * Run the given operation on a read-locked document. + * @param return type + * @param userCode code to execute under the lock + * @return result of user code. + * @throws BadLocationException propagated from the user code + * @throws IllegalStateException if a checked exception occurs in user code + */ + @NullUnknown + public T runLocked(Callable userCode) throws BadLocationException { + try { + ((AbstractDocument)document).readLock(); + return userCode.call(); + } catch (BadLocationException | RuntimeException ex) { + throw ex; + } catch (Exception ex) { + throw new IllegalStateException(ex); + } finally { + ((AbstractDocument)document).readUnlock(); + } + } + + /** + * Callback interface for user operation, which runs on lexical token sequence. + * If the client needs to iterativaly traverse {@link TokenSequence} of tokens in the document, + * calling {@link #getNextToken(int)} could be expensive and unreliable, as each call locks/unlocks the + * document. Clients may use {@link #runWithSequence(org.netbeans.api.lexer.Token, org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable)} + * to get access to the TokenSequence and work with it under document read lock. + * + * @param result of the user code + */ + public interface SequenceCallable { + /** + * Callback which receives the TokenSequence instance + * @param sequence initialized TokenSequence + * @return user-defined value + * @throws BadLocationException should be thrown if navigation fails; propagated from the {@code runWithSequence} + */ + public T call(@NonNull TokenSequence sequence) throws BadLocationException; + } + + private ThreadLocal cachedSequence = new ThreadLocal<>(); + + private TokenSequence getSequence() { + TokenSequence cached = cachedSequence.get(); + if (cached != null) { + return cached; + } + TokenHierarchy th = TokenHierarchy.get(((AbstractDocument)document)); + TokenSequence ts = th.tokenSequence(); + return ts; + } + + /** + * Executes user code on token sequence from the document. + * Read-locks the document, obtains {@link TokenSequence} from the Lexer and executes {@code userCode} + * passing the initialized sequence. The sequence is moved to the desired offset and the token that contains + * or starts at that position. The client can move the sequence elsewhere. + *

+ * If the {@code userCode} calls this {@code SyntaxSupport} methods like {@link #getNextToken(int)}, they will use + * the same TokenSequence as passed to {@code userCode}. This allows to combine navigation calls from {@link XMLSyntaxSupport} + * with client's own sequence movements. The TokenSequence instance passed to {@code userCode} can be queried for + * current token offset after navigation. + * + * @param + * @param offset offset to position the sequence at + * @param userCode code to execute + * @return user-defined value + * @throws BadLocationException if the user code throws BadLocationException + * @throws IllegalStateException if the user code throws a checked exception + */ + @NullUnknown + public T runWithSequence(int offset, SequenceCallable userCode) throws BadLocationException { + T result; + TokenSequence old = null; + try { + ((AbstractDocument)document).readLock(); + old = cachedSequence.get(); + cachedSequence.remove(); + TokenSequence ts = getSequence(); + if (ts == null) { + throw new BadLocationException("No sequence for position", offset); // NOI18N + } + cachedSequence.set(ts); + synchronized (ts) { + ts.move(offset); + ts.moveNext(); + result = userCode.call(ts); + } + } finally { + cachedSequence.set(old); + ((AbstractDocument)document).readUnlock(); + } + return result; + } + + /** + * Exeutes user code with {@link TokenSequence} positioned at a particular token. + * This convenience method works much like {@link #runWithSequence(int, org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable)}, + * except that Token (its starting offset) is used to position the sequence instead of raw offset value. + * + * @param + * @param startFrom token to start from + * @param userCode user code to execute + * @return user-defined value + * @throws BadLocationException if the user code throws BadLocationException + */ + public T runWithSequence(Token startFrom, SequenceCallable userCode) throws BadLocationException { + T result; + TokenSequence old = null; + try { + ((AbstractDocument)document).readLock(); + old = cachedSequence.get(); + cachedSequence.remove(); + TokenHierarchy th = TokenHierarchy.get(((AbstractDocument)document)); + TokenSequence ts = th.tokenSequence(); + if (ts == null) { + throw new BadLocationException("No sequence for position", startFrom.offset(null)); // NOI18N + } + cachedSequence.set(ts); + synchronized (ts) { + ts.move(startFrom.offset(th)); + ts.moveNext(); + result = userCode.call(ts); + } + } finally { + cachedSequence.set(old); + ((AbstractDocument)document).readUnlock(); + } + return result; + } + + /** * Get token at given offet or previous one if at token boundary. - * It does not lock the document. + * It does not lock the document. + *

+ * Note: if the call is made within {@link #runWithSequence(int, org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable)} exection scope, the + * search for previous token will use the same TokenSequence as passed to executed user callback. + * * @param offset valid position in document * @return TokenItem or null at the document beginning. */ - public Token getPreviousToken( int offset) throws BadLocationException { + public Token getPreviousToken( int offset) throws BadLocationException { if (offset == 0) return null; if (offset < 0) throw new BadLocationException("Offset " + offset + " cannot be less than 0.", offset); //NOI18N ((AbstractDocument)document).readLock(); try { - TokenHierarchy th = TokenHierarchy.get(((AbstractDocument)document)); - TokenSequence ts = th.tokenSequence(); - return getToken(ts, offset, false); + TokenSequence ts = getSequence(); + synchronized (ts) { + return getToken(ts, offset, false, null); + } } finally { ((AbstractDocument)document).readUnlock(); } } - + /** * Get token at given offet or previous one if at token boundary. - * It does not lock the document. + * + * It does not lock the document. + *

+ * Note: if the call is made within {@link #runWithSequence(int, org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable)} exection scope, the + * search for previous token will use the same TokenSequence as passed to executed user callback. + *

+ * This variant returns start + end (after the token) offsets for the caller's convenience. + * * @param offset valid position in document + * @param tokenBounds output; will receive token start and end positions * @return TokenItem or null at the document beginning. */ - public Token getNextToken( int offset) throws BadLocationException { + public Token getPreviousToken(int offset, int[] tokenBounds) throws BadLocationException { if (offset == 0) return null; if (offset < 0) throw new BadLocationException("Offset " + offset + " cannot be less than 0.", offset); //NOI18N ((AbstractDocument)document).readLock(); try { - TokenHierarchy th = TokenHierarchy.get(((AbstractDocument)document)); - TokenSequence ts = th.tokenSequence(); - return getToken(ts, offset, true); + TokenSequence ts = getSequence(); + synchronized (ts) { + return getToken(ts, offset, false, tokenBounds); + } } finally { ((AbstractDocument)document).readUnlock(); } } - private Token getToken(TokenSequence ts, int offset, boolean next) { - ts.move(offset); - Token token = ts.token(); - //there are cases when this could be null - //in which case use the next one. - if(token == null) - ts.moveNext(); + /** + * Returns the token occupying the given position. The token either extends over this position, or + * it starts at that position (first token's char offset == offset). + * + * @param offset offset in text for which the Token should be produced + * @return XML token occupying the position + * @throws BadLocationException + */ + public Token getTokenAtPosition(int offset, int[] tokenBounds) throws BadLocationException { + return getNextToken(offset + 1, tokenBounds); + } + /** + * Retrieves the start of an attribute token. If the passed position does not correspond to + * attribute value, operator or whitespace (between attribute name and value), {@code null} + * is returned. + *

+ * Convenience method. + * + * @param offset starting offset + * @return token corresponding to the attribute name ({@link XMLTokenId#ARGUMENT}). + */ + public Token getAttributeToken(int offset) { + try { + return this.>runWithSequence(offset, (TokenSequence ts) -> { + Token currentToken = ts.token(); + if(currentToken.id() != XMLTokenId.VALUE) { + return null; + } + Token equalsToken = null; + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == OPERATOR) { + equalsToken = t; + break; + } else if (t.id() == XMLTokenId.ARGUMENT) { + return t; + } else if (t.id() != XMLTokenId.WS) { + return null; + } + } + if(equalsToken == null) { + return null; + } + while (ts.movePrevious()) { + Token t = ts.token(); + if (t.id() == ARGUMENT) { + return t; + } else if (t.id() != XMLTokenId.WS) { + return null; + } + } + return null; + }); + } catch (BadLocationException ex) { + } + return null; + } + + + /** + * Get token at given offet or previous one if at token boundary. + * It does not lock the document. Returns {@code null} for invalid offsets. + * + * @param offset valid position in document + * @return Token instance + */ + public Token getNextToken( int offset) throws BadLocationException { + if (offset == 0) { + offset = 1; + } + if (offset < 0) throw new BadLocationException("Offset " + + offset + " cannot be less than 0.", offset); //NOI18N + ((AbstractDocument)document).readLock(); + try { + TokenSequence ts = getSequence(); + synchronized (ts) { + return getToken(ts, offset, true, null); + } + } finally { + ((AbstractDocument)document).readUnlock(); + } + } + + /** + * Get token at given offet or previous one if at token boundary. + * It does not lock the document. Returns {@code null} for invalid offsets. + *

+ * This variant returns start + end (after the token) offsets for the caller's convenience. + * + * @param offset valid position in document + * @param tokenBounds output; will receive token start and end positions + * @return Token instance + */ + public Token getNextToken( int offset, int[] tokenBounds) throws BadLocationException { + if (offset == 0) return null; + if (offset < 0) throw new BadLocationException("Offset " + + offset + " cannot be less than 0.", offset); //NOI18N + ((AbstractDocument)document).readLock(); + try { + TokenSequence ts = getSequence(); + synchronized (ts) { + return getToken(ts, offset, true, tokenBounds); + } + } finally { + ((AbstractDocument)document).readUnlock(); + } + } + + private Token getToken(TokenSequence ts, int offset, boolean next, int[] startOffset) { + int diff = ts.move(offset); + boolean ok; if(next) { - ts.moveNext(); + ok = ts.moveNext(); + } else if (diff > 0) { + ok = ts.moveNext(); } else { - ts.movePrevious(); + ok = ts.movePrevious(); } - token = ts.token(); - return token; + if (!ok) { + return null; + } + if (startOffset != null) { + startOffset[0] = ts.offset(); + if (startOffset.length > 1) { + startOffset[1] = ts.offset() + ts.token().length(); + } + } + return ts.token(); } @@ -158,13 +533,13 @@ * @param offset Offset in document where to search for SyntaxElement. * @return SyntaxElement Element surrounding or laying BEFORE the offset * or null at document begining. + * @throws javax.swing.text.BadLocationException when offset is invalid or navigation fails */ public SyntaxElement getElementChain(final int offset ) throws BadLocationException { ((AbstractDocument)document).readLock(); try { - TokenHierarchy th = TokenHierarchy.get(((AbstractDocument)document)); - TokenSequence ts = th.tokenSequence(); + TokenSequence ts = getSequence(); Token token = initialize(ts, offset); if(token == null) return null; @@ -198,13 +573,16 @@ } private Token initialize(TokenSequence ts, int offset) { - ts.move(offset); + int diff = ts.move(offset); Token token = ts.token(); - if(token == null) { - if(!ts.moveNext()) + if (diff > 0) { + if (!ts.moveNext()) { return null; - token = ts.token(); + } + } else if (!ts.movePrevious()) { + return null; } + token = ts.token(); XMLTokenId id = token.id(); String image = token.text().toString(); if ( id == XMLTokenId.WS || @@ -267,7 +645,7 @@ } case TEXT: { - return new Text(this, token, start, end); + return new TextImpl(this, token, start, end); } case TAG: { @@ -289,62 +667,28 @@ } case ERROR: { - return new SyntaxElement.Error(this, token, start, end ); + return new BaseSyntaxElement.Error(this, token, start, end ); } } return null; } - /** - * No completion inside PI, CDATA, comment section. - * True only inside PI or CDATA section, false otherwise. - * @param target + /** + * Returns last inserted character. + * It's most likely one recently typed by user. Note that in order to start capturing + * editor events, the XMLSupport must be activated for the document. When XMLSupport is first + * created for a Document, it does not provide any lastTypedChar; the subsequent edits are + * recorded. */ - public static boolean noCompletion(JTextComponent target) { - if(target == null || target.getCaret() == null) - return false; - int offset = target.getCaret().getDot(); - if(offset < 0) - return false; - //no completion inside CDATA or comment section - BaseDocument document = (BaseDocument)target.getDocument(); - ((AbstractDocument)document).readLock(); - try { - TokenHierarchy th = TokenHierarchy.get(document); - TokenSequence ts = th.tokenSequence(); - if(ts == null) - return false; - ts.move(offset); - Token token = ts.token(); - if(token == null) { - ts.moveNext(); - token = ts.token(); - if(token == null) - return false; - } - if( token.id() == XMLTokenId.CDATA_SECTION || - token.id() == XMLTokenId.BLOCK_COMMENT || - token.id() == XMLTokenId.PI_START || - token.id() == XMLTokenId.PI_END || - token.id() == XMLTokenId.PI_CONTENT || - token.id() == XMLTokenId.PI_TARGET ) { - return true; - } - } finally { - ((AbstractDocument)document).readUnlock(); - } - - return false; - } - - /** Returns last inserted character. It's most likely one recently typed by user. */ public final char lastTypedChar() { - return lastInsertedChar; + return documentMonitor.lastInsertedChar; } /** Keep track of last typed character */ - private class DocumentMonitor implements DocumentListener { + private static class DocumentMonitor implements DocumentListener { + + private char lastInsertedChar = 'X'; // NOI18N public void changedUpdate(DocumentEvent e) { } @@ -362,5 +706,174 @@ public void removeUpdate(DocumentEvent e) { } } + + /** + * Determines if the SyntaxElement is a start or end tag. + * + * @param n element to test + * @return true, if the element is a start or end tag. False if Node does not represent a tag, or for an empty tag + */ + public boolean isNormalTag(SyntaxElement n) { + return isStartTag(n) || isEndTag(n); + } + + /** + * Determines if the SyntaxElement is a start tag. + * Returns {@code false} if Node does not represent a start tag, or is a self-closed (empty content) tag + * @param n element to test + * @return true, if the element is a start tag. + */ + public boolean isStartTag(SyntaxElement n) { + return n instanceof StartTag; + } + + /** + * Returns true iff the element is a self-closing tag. + * Returns true if and only if the SyntaxElement represents a self-closing tag without content. False otherwise. + * @param n element to check + * @return true, if self-closing tag + */ + public boolean isEmptyTag(SyntaxElement n) { + return n instanceof EmptyTag; + } + + /** + * Determines if the SyntaxElement is an end tag. + * Returns {@code false} if Node does not represent an end tag, or is a self-closed (empty content) tag + * @param n element to test + * @return true, if the element is a start tag. + */ + public boolean isEndTag(SyntaxElement n) { + return n instanceof EndTag; + } + + /** + * Returns text offset of the Node start in the underlying document. + * Returns -1 if the offset could not be determined. Use this method to find out + * offset of a DOM Node obtained from a {@link SyntaxElement} or {@link XMLSyntaxSupport} + * @param n + * @return offset or -1 if the offset could not be determined. + */ + public int getNodeOffset(Node n) { + if (!(n instanceof SyntaxElement)) { + if (n instanceof Document) { + return 0; + } + return -1; + } + return ((SyntaxElement)n).getElementOffset(); + } + + /** + * Obtains a SyntaxElement for the W3C Node, if possible. + * @param n the Node + * @return corresponding SyntaxElement or {@code null}. + */ + public SyntaxElement getSyntaxElement(Node n) { + if (n instanceof SyntaxElement) { + return (SyntaxElement)n; + } else { + return null; + } + } + + /** + * Convenience method to get attribute value as string. Returns {@code null} + * if the Node is not a start/empty element, or does not contain attribute of the specified name. + * For namespaced names, you must use the exact {@code prefix:localName}. + * + * @param n node + * @param name attribute name + * @return attribute (string) value or {@code null} if no such attribute exist for element n. + */ + public static String getAttributeValue(Node n, String name) { + NamedNodeMap a = n.getAttributes(); + if (a == null) { + return null; + } + Node item = a.getNamedItem(name); + if (item == null) { + return null; + } + return item.getNodeValue(); + } + + /** + * Constructs a path from the root of the document to the given syntax element. + * + * @param element the element to start with + * @return top-down path of SyntaxElements from the document root towards the original SyntaxElement + */ + public List getPathFromRoot(SyntaxElement element) { + Deque stack = new ArrayDeque<>(); + SyntaxElement elementRef = element; + while (elementRef != null) { + if (isEndTag(element) || + (isEmptyTag(elementRef) && stack.isEmpty()) || + (isStartTag(elementRef) && stack.isEmpty())) { + stack.push(elementRef); + elementRef = elementRef.getPrevious(); + continue; + } + if (isStartTag(elementRef)) { + if (isEndTag(stack.peek())) { + SyntaxElement end = stack.peek(); + if (end.getNode().getNodeName().equals(elementRef.getNode().getNodeName())) { + stack.pop(); + } + } else { + SyntaxElement e = stack.peek(); + stack.push(elementRef); + } + } + elementRef = elementRef.getPrevious(); + } + // reverse: + List res = new ArrayList<>(stack.size()); + while ((elementRef = stack.poll()) != null) { + res.add(elementRef); + } + return res; + } + + /** + * Skips forward or backward specified token types. Simplified variant of {@link #skip(int, boolean, java.util.function.BiPredicate)}, + * only token types to skip can be specified. The first token of type other than those passed in {@code skipTokens} will be returned from the method. + * + * @param offset position to start at. + * @param forward true means froward, false backward + * @param skipTokens token types to skip + * @return first token whose type does not match the specified values + * @throws BadLocationException + */ + public Token skip(int offset, boolean forward, XMLTokenId... skipTokens) throws BadLocationException { + EnumSet en = EnumSet.copyOf(Arrays.asList(skipTokens)); + return skip(offset, forward, (TokenSequence s, Token t) -> en.contains(t.id())); + } + + /** + * Skips tokens matched by the predicate from the given offset. Positions {@link TokenSequence} on the specified offset, + * then traverses either forward or backward, depending on a parameter until the predicate returns false. + * The token for which the predicate failed will be returned as the return value. + * + * @param offset offset to start traversal + * @param forward true for forward traversal, false for backward + * @param pred predicate to match tokens. Method skips tokens that satisfy the predicate (until the first which does not) + * @return + * @throws BadLocationException + */ + public Token skip(int offset, boolean forward, BiPredicate> pred) throws BadLocationException { + Token tukac = runWithSequence(offset, (TokenSequence s) -> { + s.move(offset); + while ((forward && s.moveNext()) || (!forward && s.movePrevious())) { + if (!pred.test(s, s.token())) { + return s.token(); + } + } + return null; + }); + return tukac; + } + } diff --git a/projectapi/src/org/netbeans/spi/project/package.html b/xml.text/src/org/netbeans/modules/xml/text/api/dom/package.html copy from projectapi/src/org/netbeans/spi/project/package.html copy to xml.text/src/org/netbeans/modules/xml/text/api/dom/package.html --- a/projectapi/src/org/netbeans/spi/project/package.html +++ b/xml.text/src/org/netbeans/modules/xml/text/api/dom/package.html @@ -36,20 +36,28 @@ made subject to such option by the copyright holder. Contributor(s): + +Portions Copyrighted 2016 Sun Microsystems, Inc. --> - -Support for defining project types. - -

Each kind of project in the system needs to be loaded by a -{@link org.netbeans.spi.project.ProjectFactory}, which defines how to recognize -projects on disk, load their metadata into memory, and save their metadata back -to disk. {@link org.netbeans.spi.project.ProjectState} is used to let the -factory mark a project as being modified in memory.

- -

Projects will normally put implementations of several interfaces such as -{@link org.netbeans.spi.project.ActionProvider} into their lookup.

- +

+ API for read-only access XML structure using DOM-like interface. Implemented over XML lexer, + so the structure can be obtained even on malformed, unfinished or errneous documents. + The caller may obtain a SyntaxElement corresponding to a given textual position in the XML document. + The SyntaxElement can be used to both read contents (attributes, tag name, ...) of the document, + or navigate to sibling, predecessor, parent or child Elements. SyntaxElement can be converted to + DOM Node; DOM Nodes obtained originally as a result of SyntaxElement conversion can be converted + back to SyntaxElements so the caller can retrieve their position within the document. +

+

+ It is advisable to perform searches or navigation through the document under a document read (write) + lock. Implementations in this package read-lock the document internally, but generally no lock is + preserved across method calls. +

+

+ The design / structure of the API is intentionally almost the same as with the obsoleted api located in + org.netbeans.modules.xml.text.syntax.dom package to make the existing code migration easier. +

diff --git a/xml.text/src/org/netbeans/modules/xml/text/breadcrumbs/BreadcrumbProvider.java b/xml.text/src/org/netbeans/modules/xml/text/breadcrumbs/BreadcrumbProvider.java --- a/xml.text/src/org/netbeans/modules/xml/text/breadcrumbs/BreadcrumbProvider.java +++ b/xml.text/src/org/netbeans/modules/xml/text/breadcrumbs/BreadcrumbProvider.java @@ -62,7 +62,7 @@ import org.netbeans.modules.editor.structure.api.DocumentElementListener; import org.netbeans.modules.editor.structure.api.DocumentModel; import org.netbeans.modules.editor.structure.api.DocumentModelException; -import org.netbeans.modules.xml.text.structure.XMLDocumentModelProvider; +import static org.netbeans.modules.xml.text.structure.XMLConstants.*; import org.openide.cookies.OpenCookie; import org.openide.loaders.DataObject; import org.openide.util.Exceptions; @@ -151,11 +151,11 @@ DocumentElement el = mdl.getLeafElementForOffset(pos); OUT: while (el != null) { switch (el.getType()) { - case XMLDocumentModelProvider.XML_TAG: - case XMLDocumentModelProvider.XML_EMPTY_TAG: - case XMLDocumentModelProvider.XML_PI: - case XMLDocumentModelProvider.XML_CDATA: - case XMLDocumentModelProvider.XML_DOCTYPE: + case XML_TAG: + case XML_EMPTY_TAG: + case XML_PI: + case XML_CDATA: + case XML_DOCTYPE: break OUT; default: el = el.getParentElement(); @@ -220,14 +220,14 @@ @Override public String getHtmlDisplayName() { switch (docEl.getType()) { - case XMLDocumentModelProvider.XML_TAG: - case XMLDocumentModelProvider.XML_EMPTY_TAG: + case XML_TAG: + case XML_EMPTY_TAG: return docEl.getName(); - case XMLDocumentModelProvider.XML_PI: + case XML_PI: return docEl.getName(); - case XMLDocumentModelProvider.XML_CDATA: + case XML_CDATA: return Bundle.LABEL_CDATA(); - case XMLDocumentModelProvider.XML_DOCTYPE: + case XML_DOCTYPE: return Bundle.LABEL_DOCTYPE(); default: // unsupported nodes @@ -243,17 +243,17 @@ String resource; switch (docEl.getType()) { - case XMLDocumentModelProvider.XML_TAG: - case XMLDocumentModelProvider.XML_EMPTY_TAG: + case XML_TAG: + case XML_EMPTY_TAG: resource = TAG_16; break; - case XMLDocumentModelProvider.XML_PI: + case XML_PI: resource = PI_16; break; - case XMLDocumentModelProvider.XML_CDATA: + case XML_CDATA: resource = CDATA_16; break; - case XMLDocumentModelProvider.XML_DOCTYPE: + case XML_DOCTYPE: resource = DOCTYPE_16; break; default: @@ -293,11 +293,11 @@ List children = new ArrayList<>(); for (DocumentElement ch : docEl.getChildren()) { switch (ch.getType()) { - case XMLDocumentModelProvider.XML_TAG: - case XMLDocumentModelProvider.XML_EMPTY_TAG: - case XMLDocumentModelProvider.XML_PI: - case XMLDocumentModelProvider.XML_CDATA: - case XMLDocumentModelProvider.XML_DOCTYPE: + case XML_TAG: + case XML_EMPTY_TAG: + case XML_PI: + case XML_CDATA: + case XML_DOCTYPE: children.add(createElement(ch, this)); break; default: diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/GrammarManager.java b/xml.text/src/org/netbeans/modules/xml/text/completion/GrammarManager.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/GrammarManager.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/GrammarManager.java @@ -62,9 +62,8 @@ import org.netbeans.modules.xml.api.model.GrammarEnvironment; import org.netbeans.modules.xml.api.model.GrammarQuery; import org.netbeans.modules.xml.api.model.GrammarQueryManager; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.dom.SyntaxNode; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.filesystems.FileChangeAdapter; import org.openide.filesystems.FileChangeListener; import org.openide.filesystems.FileEvent; @@ -293,8 +292,8 @@ while (en.hasMoreElements()) { Node next = (Node) en.nextElement(); - if (next instanceof SyntaxNode) { - SyntaxNode node = (SyntaxNode) next; + if (next instanceof SyntaxElement) { + SyntaxElement node = (SyntaxElement) next; int start = node.getElementOffset(); int end = start + node.getElementLength(); if (end > max) max = end; @@ -359,10 +358,10 @@ SyntaxElement first = syntax.getElementChain(1); while (true) { if (first == null) break; - if (first instanceof SyntaxNode) { - SyntaxNode node = (SyntaxNode) first; + Node node = first.getNode(); + if (node != null) { ctx.add(node); - if (node.ELEMENT_NODE == node.getNodeType()) { + if (Node.ELEMENT_NODE == node.getNodeType()) { break; } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/NodeSelector.java b/xml.text/src/org/netbeans/modules/xml/text/completion/NodeSelector.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/NodeSelector.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/NodeSelector.java @@ -56,8 +56,8 @@ import org.netbeans.editor.BaseDocument; import org.netbeans.modules.xml.api.model.GrammarQuery; import org.netbeans.modules.xml.api.model.HintContext; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.modules.xml.text.completion.XMLCompletionQuery; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.nodes.Sheet; @@ -139,7 +139,7 @@ if (syntaxSupport == null) { Document doc = pane.getDocument(); if (doc instanceof BaseDocument) { - syntaxSupport = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport(); + syntaxSupport = XMLSyntaxSupport.getSyntaxSupport((BaseDocument)doc); } if (syntaxSupport == null) { return; diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/SyntaxQueryHelper.java b/xml.text/src/org/netbeans/modules/xml/text/completion/SyntaxQueryHelper.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/SyntaxQueryHelper.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/SyntaxQueryHelper.java @@ -45,12 +45,14 @@ package org.netbeans.modules.xml.text.completion; import javax.swing.text.BadLocationException; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; -import org.netbeans.editor.*; import org.netbeans.modules.xml.api.model.HintContext; -import org.netbeans.modules.xml.text.syntax.*; -import org.netbeans.modules.xml.text.syntax.dom.*; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -71,9 +73,13 @@ public final static int COMPLETION_TYPE_ENTITY = 4; public final static int COMPLETION_TYPE_NOTATION = 5; public final static int COMPLETION_TYPE_DTD = 6; + + private XMLSyntaxSupport support; /** Currect oken or previous one if at token boundary */ - private TokenItem token = null; + private Token token = null; + + private int tokenOffset; private String preText = ""; @@ -91,10 +97,16 @@ /** Creates a new instance of SyntaxQueryHelper */ public SyntaxQueryHelper(XMLSyntaxSupport sup, int offset) throws BadLocationException, IllegalStateException { + this.support = sup; tunedOffset = offset; - token = sup.getPreviousToken( tunedOffset); + sup.runWithSequence(tunedOffset, (TokenSequence seq) -> { + token = sup.getPreviousToken(tunedOffset); + tokenOffset = seq.offset(); + return null; + }); + if( token != null ) { // inside document - tokenBoundary = token.getOffset() + token.getImage().length() == tunedOffset; + tokenBoundary = tokenOffset + token.length() == tunedOffset; } else { //??? start of document no choice now, but should be prolog if not followed by it throw new BadLocationException("No token found at current position", offset); // NOI18N @@ -102,17 +114,17 @@ // find out last typed chars that can hint - int itemOffset = token.getOffset(); + int itemOffset = tokenOffset; preText = ""; erase = 0; int eraseRight = 0; - int id = token.getTokenID().getNumericID(); + XMLTokenId id = token.id(); // determine last typed text, prefix text if ( tokenBoundary == false ) { - preText = token.getImage().substring( 0, tunedOffset - token.getOffset() ); + preText = token.text().toString().substring( 0, tunedOffset - tokenOffset); if ("".equals(preText)) throw new IllegalStateException("Cannot get token prefix at " + tunedOffset); // manipulate tunedOffset to delete rest of an old name @@ -121,11 +133,11 @@ if (sup.lastTypedChar() != '<' && sup.lastTypedChar() != '&') { switch (id) { - case XMLDefaultTokenContext.TAG_ID: - case XMLDefaultTokenContext.CHARACTER_ID: - case XMLDefaultTokenContext.ARGUMENT_ID: + case TAG: + case CHARACTER: + case ARGUMENT: - int i = token.getImage().length(); + int i = token.length(); int tail = i - (tunedOffset - itemOffset); tunedOffset += tail; eraseRight = tail; @@ -134,12 +146,12 @@ } } else { switch (id) { - case XMLDefaultTokenContext.TEXT_ID: - case XMLDefaultTokenContext.TAG_ID: - case XMLDefaultTokenContext.ARGUMENT_ID: - case XMLDefaultTokenContext.CHARACTER_ID: - case XMLCompletionQuery.PI_CONTENT_ID: - preText = token.getImage(); + case TEXT: + case TAG: + case ARGUMENT: + case CHARACTER: + case PI_CONTENT: + preText = token.text().toString(); break; } } @@ -147,18 +159,18 @@ // adjust how much do you want to erase from the preText switch (id) { - case XMLDefaultTokenContext.TAG_ID: + case TAG: // do not erase start delimiters erase = preText.length() - 1 + eraseRight; break; - case XMLDefaultTokenContext.CHARACTER_ID: + case CHARACTER: //entity references erase = preText.length() + -1 + eraseRight; break; - case XMLDefaultTokenContext.ARGUMENT_ID: + case ARGUMENT: erase = preText.length() + eraseRight; break; - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: erase = preText.length(); if (erase > 0 && (preText.charAt(0) == '\'' || preText.charAt(0) == '"')) { // Because of attribute values, preText is adjusted in initContext @@ -172,14 +184,18 @@ if (element == null) throw new IllegalStateException("There exists a token therefore a syntax element must exist at " + offset + ", too."); // completion request originates from area covered by DOM, - if (element instanceof SyntaxNode && ((SyntaxNode)element).getNodeType() != Node.DOCUMENT_TYPE_NODE) { - completionType = initContext(); + if (element.getType() != SyntaxElement.NODE_ERROR && element.getType() != Node.DOCUMENT_TYPE_NODE) { + completionType = support.runLocked(this::initContext); } else { // prolog, internal DTD no completition yet completionType = COMPLETION_TYPE_DTD; } } + public int getTokenOffset() { + return tokenOffset; + } + /** * Find out what to complete: attribute, value, element, entity or notation? *

@@ -207,12 +223,11 @@ * COMPLETION_TYPE_ENTITY = 4, * COMPLETION_TYPE_NOTATION = 5. */ - private int initContext() { - int id = token.getTokenID().getNumericID(); - SyntaxNode syntaxNode = (SyntaxNode)element; - + private int initContext() throws BadLocationException { + XMLTokenId id = token.id(); + final Node syntaxNode = element.getNode(); switch ( id) { - case XMLDefaultTokenContext.TEXT_ID: + case TEXT: if ( preText.endsWith("<" ) || preText.endsWith("")) { + if (token.text().toString().endsWith(">")) { ctx.init(syntaxNode, preText); return COMPLETION_TYPE_VALUE; } else { @@ -253,25 +267,25 @@ ctx.init(syntaxNode, preText.substring(1)); return COMPLETION_TYPE_ELEMENT; } - } else if(EndTag.class.equals(syntaxNode.getClass()) && preText.startsWith("")) { + if ("".equals(preText) && token.text().toString().endsWith(">")) { ctx.init(syntaxNode, preText); return COMPLETION_TYPE_VALUE; } } break; - case XMLDefaultTokenContext.VALUE_ID: + case VALUE: if (preText.endsWith("&")) { ctx.init(syntaxNode, ""); return COMPLETION_TYPE_ENTITY; } else if ("".equals(preText)) { //??? improve check to addres inner '"' - String image = token.getImage(); + String image = token.text().toString(); char ch = image.charAt(image.length()-1); // findout if it is closing ' @@ -283,23 +297,33 @@ return COMPLETION_TYPE_UNKNOWN; } - boolean closing = false; - TokenItem prev = token.getPrevious(); + int res = support.runWithSequence(tokenOffset, (TokenSequence seq) -> { + Token prev = support.getPreviousToken(tokenOffset); + boolean closing = false; - while (prev != null) { - int tid = prev.getTokenID().getNumericID(); - if (tid == XMLDefaultTokenContext.VALUE_ID) { - closing = true; - break; - } else if (tid == XMLDefaultTokenContext.CHARACTER_ID) { - prev = prev.getPrevious(); + while (prev != null) { + XMLTokenId tid = prev.id(); + if (tid == XMLTokenId.VALUE) { + closing = true; + break; + } else if (tid == XMLTokenId.CHARACTER) { + if (!seq.movePrevious()) { + return COMPLETION_TYPE_UNKNOWN; + } + prev = seq.token(); + } else { + break; + } + } + if (closing == false) { + ctx.init(syntaxNode, preText); + return COMPLETION_TYPE_VALUE; } else { - break; + return COMPLETION_TYPE_UNKNOWN; } - } - if (closing == false) { - ctx.init(syntaxNode, preText); - return COMPLETION_TYPE_VALUE; + }); + if (res != COMPLETION_TYPE_UNKNOWN) { + return res; } } else { ctx.init(syntaxNode, preText); @@ -312,11 +336,11 @@ int maxOffsetLessThanCurrent = -1; Node curAttrNode = null; for (int ind = 0; ind < attrs.getLength(); ind++) { - AttrImpl attr = (AttrImpl)attrs.item(ind); - int attrTokOffset = attr.getFirstToken().getOffset(); - if (attrTokOffset > maxOffsetLessThanCurrent && attrTokOffset < token.getOffset()) { + SyntaxElement attr = (SyntaxElement)attrs.item(ind); + int attrTokOffset = attr.getElementOffset(); + if (attrTokOffset > maxOffsetLessThanCurrent && attrTokOffset < tokenOffset) { maxOffsetLessThanCurrent = attrTokOffset; - curAttrNode = attr; + curAttrNode = (Node)attr; } } @@ -333,19 +357,18 @@ } break; - case XMLDefaultTokenContext.OPERATOR_ID: + case OPERATOR: if ("".equals(preText)) { - if ("=".equals(token.getImage())) { + if ("=".equals(token.text())) { ctx.init(syntaxNode, ""); return COMPLETION_TYPE_VALUE; } } break; - case XMLDefaultTokenContext.WS_ID: - if ((StartTag.class.equals(syntaxNode.getClass()) - || EmptyTag.class.equals(syntaxNode.getClass())) - && !token.getImage().startsWith("/")) { + case WS: + if (support.isNormalTag(element) + && !token.text().toString().startsWith("/")) { ctx.init((Element)syntaxNode, ""); // GrammarQuery.v2 takes Element ctx return COMPLETION_TYPE_ATTRIBUTE; } else { @@ -354,15 +377,14 @@ } // break; - case XMLDefaultTokenContext.ARGUMENT_ID: - if (StartTag.class.equals(syntaxNode.getClass()) - || EmptyTag.class.equals(syntaxNode.getClass())) { + case ARGUMENT: + if (support.isStartTag(element) + || support.isEmptyTag(element)) { //try to find the current attribute - Tag tag = (Tag)syntaxNode; - NamedNodeMap nnm = tag.getAttributes(); + NamedNodeMap nnm = syntaxNode.getAttributes(); for(int i = 0; i < nnm.getLength(); i++) { - AttrImpl attrNode = (AttrImpl)nnm.item(i); - if(attrNode.getFirstToken().getOffset() == token.getOffset()) { + Attr attrNode = (Attr)nnm.item(i); + if(support.getNodeOffset(attrNode) == tokenOffset) { ctx.init(attrNode, preText); } } @@ -373,7 +395,7 @@ } break; - case XMLDefaultTokenContext.CHARACTER_ID: // entity reference + case CHARACTER: // entity reference if (preText.startsWith("&#")) { // character ref, ignore return COMPLETION_TYPE_UNKNOWN; @@ -384,7 +406,7 @@ ctx.init(syntaxNode, preText.substring(1)); return COMPLETION_TYPE_ENTITY; } else if ("".equals(preText)) { - if (token.getImage().endsWith(";")) { + if (token.text().toString().endsWith(";")) { ctx.init(syntaxNode, preText); return COMPLETION_TYPE_VALUE; } @@ -408,7 +430,7 @@ } /** Current token or previous one if at token boundary. */ - public TokenItem getToken() { + public Token getToken() { return token; } diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionProvider.java b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionProvider.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionProvider.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionProvider.java @@ -49,19 +49,20 @@ import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.netbeans.api.editor.completion.Completion; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.SyntaxSupport; -import org.netbeans.editor.TokenItem; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.editor.Utilities; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.editor.ext.ExtSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; import org.netbeans.spi.editor.completion.CompletionItem; import org.netbeans.spi.editor.completion.CompletionResultSet; import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; /** @@ -80,16 +81,116 @@ @Override public int getAutoQueryTypes(JTextComponent component, String typedText) { - SyntaxSupport support = Utilities.getDocument(component).getSyntaxSupport(); + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(component.getDocument()); if( (support == null) || !(support instanceof XMLSyntaxSupport)) return 0; - int type = ((XMLSyntaxSupport)support).checkCompletion(component, typedText, false); + int type = checkCompletion(support, component, typedText, false); if(type == ExtSyntaxSupport.COMPLETION_POPUP) return COMPLETION_QUERY_TYPE; return 0; } + + /** Schedule content update making completion visible. */ + public static final int COMPLETION_POPUP = 0; + /** Cancel request without changing completion visibility. */ + public static final int COMPLETION_CANCEL = 1; + /** Update content immediatelly if it's currently visible. */ + public static final int COMPLETION_REFRESH = 2; + /** Schedule content update if it's currently visible. */ + public static final int COMPLETION_POST_REFRESH = 3; + /** Hide completion. */ + public static final int COMPLETION_HIDE = 4; + + private int checkCompletion(XMLSyntaxSupport support, JTextComponent target, String typedText, boolean visible ) { + + if( !visible ) { + int retVal = COMPLETION_CANCEL; + switch( typedText.charAt( typedText.length()-1 ) ) { + case '/': + int dotPos = target.getCaret().getDot(); + BaseDocument doc = (BaseDocument)target.getDocument(); + if (dotPos >= 2) { // last char before inserted slash + try { + String txtBeforeSpace = doc.getText(dotPos-2, 2); + if( txtBeforeSpace.equals("': + dotPos = target.getCaret().getDot(); + try { + SyntaxElement sel = support.getElementChain(dotPos); + if(support.isStartTag(sel)) { + retVal = COMPLETION_POPUP; + } + } catch (BadLocationException e) { + //ignore + } + break; + } + if(noCompletion(support, target)) + return COMPLETION_HIDE; + return retVal; + } else { // the pane is already visible + switch (typedText.charAt(0)) { + case '>': + case ';': + return COMPLETION_HIDE; + } + //requestedAutoCompletion = true; + return COMPLETION_POST_REFRESH; //requery it + } + } + + /** + * No completion inside PI, CDATA, comment section. + * True only inside PI or CDATA section, false otherwise. + * @param target + */ + boolean noCompletion(XMLSyntaxSupport support, JTextComponent target) { + if(target == null || target.getCaret() == null) + return false; + int offset = target.getCaret().getDot(); + if(offset < 0) + return false; + //no completion inside CDATA or comment section + try { + return support.runWithSequence(offset, (TokenSequence ts) -> { + Token token = ts.token(); + if (token == null) { + ts.moveNext(); + token = ts.token(); + if (token == null) { + return false; + } + } + if (token.id() == XMLTokenId.CDATA_SECTION + || token.id() == XMLTokenId.BLOCK_COMMENT + || token.id() == XMLTokenId.PI_START + || token.id() == XMLTokenId.PI_END + || token.id() == XMLTokenId.PI_CONTENT + || token.id() == XMLTokenId.PI_TARGET) { + return true; + } + return false; + }); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + return false; + } @Override public CompletionTask createTask(int queryType, JTextComponent component) { @@ -112,16 +213,14 @@ @Override protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) { - SyntaxSupport syntaxSupport = Utilities.getSyntaxSupport(component); // fix for issue #185876 - XMLSyntaxSupport support = (syntaxSupport instanceof XMLSyntaxSupport ? - (XMLSyntaxSupport) syntaxSupport : null); + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(doc); if (!ENABLED || support == null) { resultSet.finish(); return; } resultSet.setWaitText(NbBundle.getMessage(XMLCompletionProvider.class, "MSG_loading_dtd")); - List items = QUERY.query(component, caretOffset, support); + List items = QUERY.query(component, caretOffset, XMLSyntaxSupport.getSyntaxSupport((BaseDocument)doc)); if(items != null) resultSet.addAllItems(items); resultSet.finish(); } @@ -166,10 +265,10 @@ //test whether we are just in text and eventually close the opened completion //this is handy after end tag autocompletion when user doesn't complete the //end tag and just types a text - XMLSyntaxSupport sup = (XMLSyntaxSupport)doc.getSyntaxSupport().get(XMLSyntaxSupport.class); + XMLSyntaxSupport sup = XMLSyntaxSupport.getSyntaxSupport(doc); try { - TokenItem ti = sup.getTokenChain(caretOffset <= 0 ? 0 : caretOffset - 1, caretOffset); - if(ti != null && ti.getTokenID() == XMLDefaultTokenContext.TEXT && !ti.getImage().startsWith("<") && !ti.getImage().startsWith("&")) { + Token ti = sup.getNextToken(caretOffset <= 0 ? 1 : caretOffset - 1); + if(ti != null && ti.id()== XMLTokenId.TEXT && !ti.text().toString().startsWith("<") && !ti.text().toString().startsWith("&")) { hideCompletion(); } }catch(BadLocationException e) { diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionQuery.java b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionQuery.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionQuery.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLCompletionQuery.java @@ -52,7 +52,6 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Document; import org.netbeans.api.lexer.Token; -import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenId; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.xml.lexer.XMLTokenId; @@ -62,12 +61,13 @@ import org.netbeans.editor.*; import org.openide.ErrorManager; -import org.netbeans.modules.xml.text.syntax.*; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.modules.xml.api.model.*; import org.netbeans.modules.xml.spi.dom.UOException; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; import org.netbeans.modules.xml.text.bracematch.XMLBraceMatcher; -import org.netbeans.modules.xml.text.syntax.dom.SyntaxNode; import org.netbeans.spi.editor.completion.CompletionItem; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; /** @@ -83,7 +83,7 @@ * @version 1.01 */ -public class XMLCompletionQuery implements XMLTokenIDs { +public class XMLCompletionQuery { // the name of a property indentifing cached query public static final String DOCUMENT_GRAMMAR_BINDING_PROP = "doc-bind-query"; @@ -103,11 +103,9 @@ * @param support syntax-support that will be used during resolving of the query. * @return result of the query or null if there's no result. */ - public List query(JTextComponent component, int offset, SyntaxSupport support) { + public List query(JTextComponent component, int offset, XMLSyntaxSupport sup) { BaseDocument doc = (BaseDocument)component.getDocument(); if (doc == null) return null; - XMLSyntaxSupport sup = (XMLSyntaxSupport)support.get(XMLSyntaxSupport.class); - if( sup == null ) return null;// No SyntaxSupport for us, no hint for user try { SyntaxQueryHelper helper = new SyntaxQueryHelper(sup, offset); @@ -165,7 +163,7 @@ ***************************************************************/ if (list.isEmpty() && helper.getPreText().startsWith(""; } - } else if (helper.getToken().getTokenID() == XMLTokenIDs.VALUE) { - String c = helper.getToken().getImage(); + } else if (helper.getToken().id() == XMLTokenId.VALUE) { + String c = helper.getToken().text().toString(); delLen = c.length(); if (c.charAt(0) == '"' || c.charAt(0) == '\'') { @@ -363,7 +361,7 @@ if (c.charAt(l) == '"' || c.charAt(l) == '\'') { delLen--; } - } else if (helper.getToken().getTokenID() == XMLTokenIDs.TAG) { + } else if (helper.getToken().id() == XMLTokenId.TAG) { String tagName = shouldCloseTag(helper, doc, sup); if (tagName != null) { suffix = ""; @@ -437,25 +435,31 @@ return result; } - private String shouldCloseTag(SyntaxQueryHelper helper, Document doc, XMLSyntaxSupport sup) { - TokenItem ti = helper.getToken(); - TokenItem previous = ti.getPrevious(); - if (previous == null || previous.getTokenID() != XMLTokenIDs.TAG) { + private String shouldCloseTagLocked(TokenSequence ts) { + if (!ts.movePrevious()) { + return null; + } + Token previous = ts.token(); + if (previous.id() != XMLTokenId.TAG) { // preceded by something else than tag name, i.e. argument, operator... return null; } - String tagName = previous.getImage(); + String tagName = previous.text().toString(); if (tagName.equals(">")) { // NOI18N // closing brace of a tag, iterate towards tag's begin, skip attributes and their values. - previous = previous.getPrevious(); - while (previous != null && previous.getTokenID() != XMLTokenIDs.TAG) { - previous = previous.getPrevious(); + boolean ok; + + while (ok = !ts.movePrevious()) { + previous = ts.token(); + if (previous.id() == XMLTokenId.TAG) { + break; + } } - if (previous == null) { + if (!ok) { return null; } // got tagname. - tagName = previous.getImage(); + tagName = previous.text().toString(); } if (tagName.startsWith(END_TAG_PREFIX)) { // traversal through preceding tags, counting end-start pairs not implemented. @@ -465,8 +469,7 @@ } // tag name does not include end sharp brace tagName = tagName.substring(1, tagName.length()).trim(); - TokenSequence s = (TokenSequence)TokenHierarchy.get(doc).tokenSequence(); - if (isClosingEndTagFoundAfter(ti.getOffset(), s, tagName)) { + if (isClosingEndTagFoundAfter(ts.offset(), ts, tagName)) { // I know, there may be multiple levels of the same tag name, and the innermost may // be missing... return null; @@ -474,6 +477,16 @@ return tagName; } + private String shouldCloseTag(SyntaxQueryHelper helper, Document doc, XMLSyntaxSupport sup) { + Token ti = helper.getToken(); + try { + return sup.runWithSequence(helper.getTokenOffset(), this::shouldCloseTagLocked); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + return null; + } + public static final String TAG_FIRST_CHAR = "<", //NOI18N TAG_LAST_CHAR = ">", //NOI18N @@ -583,14 +596,17 @@ * @param prefix that is prepended to created ElementResult e.g. ' findStartTag(SyntaxNode text, String prefix) { + private static List findStartTag(SyntaxElement text, String prefix) { //if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("XMLCompletionQuery.findStartTag: text=" + text); - Node parent = text.getParentNode(); + SyntaxElement parentEl = text.getParentElement(); + if (parentEl == null) { + return Collections.EMPTY_LIST; + } + Node parent = parentEl.getNode(); if (parent == null) { return Collections.EMPTY_LIST; } - String name = parent.getNodeName(); //if ( Util.THIS.isLoggable() ) Util.THIS.debug(" name=" + name); if ( name == null ) { @@ -606,7 +622,7 @@ return list; } - private static List findStartTag(SyntaxNode text) { + private static List findStartTag(SyntaxElement text) { return findStartTag(text, ""); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLResultItem.java b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLResultItem.java --- a/xml.text/src/org/netbeans/modules/xml/text/completion/XMLResultItem.java +++ b/xml.text/src/org/netbeans/modules/xml/text/completion/XMLResultItem.java @@ -62,11 +62,13 @@ import javax.swing.JLabel; import javax.swing.UIManager; import org.netbeans.api.editor.completion.Completion; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.queries.FileEncodingQuery; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.xml.api.model.GrammarResult; import org.netbeans.modules.xml.api.model.DescriptionSource; -import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.spi.editor.completion.CompletionDocumentation; import org.netbeans.spi.editor.completion.CompletionItem; import org.netbeans.spi.editor.completion.CompletionResultSet; @@ -240,23 +242,19 @@ } return true; } - - //+++ fix for issues #166462, #173122 - // (http://www.netbeans.org/issues/show_bug.cgi?id=166462) - // (http://www.netbeans.org/issues/show_bug.cgi?id=173122) - private boolean isTextRemovingAllowable(JTextComponent component, - BaseDocument doc, String replaceToText, int offset) throws BadLocationException { - XMLSyntaxSupport support = (XMLSyntaxSupport) - org.netbeans.editor.Utilities.getSyntaxSupport(component); - TokenItem tokenItem = support.getTokenChain(offset, doc.getLength()); - boolean isTextRemovingAllowable = (tokenItem == null); - if (! isTextRemovingAllowable) { - String tokenItemImage = tokenItem.getImage(); + + private boolean isRemovingAvailableLocked(TokenSequence ts, Document doc, int offset, String replaceToText) { + ts.move(position); + boolean isTextRemovingAllowable = true; + + while (ts.moveNext() && isTextRemovingAllowable) { + Token tokenItem = ts.token(); + String tokenItemImage = tokenItem.text().toString(); if ((tokenItemImage != null) && (tokenItemImage.length() > 0)) { // See also issue #228865. In this case, the token also may include a prefix // of the replacement value String replaceInclPrefix; - int offs = Math.max(0, offset - tokenItem.getOffset()); + int offs = Math.max(0, offset - ts.offset()); replaceInclPrefix = tokenItemImage.substring(0, offs) + replaceToText; int diffPos = getFirstDiffPosition(tokenItemImage, replaceInclPrefix); diffPos = diffPos == 0 ? 1 : diffPos; @@ -268,10 +266,8 @@ strText = replaceInclPrefix.length() >= diffPos ? replaceInclPrefix.substring(0, diffPos) : replaceInclPrefix; - TokenID tokenID = tokenItem.getTokenID(); - int id = (tokenID != null ? tokenID.getNumericID() : -1); - - isTextRemovingAllowable = (id == XMLDefaultTokenContext.TAG_ID ? + XMLTokenId id = tokenItem.id(); + isTextRemovingAllowable = (id == XMLTokenId.TAG ? ! strImg.startsWith(strText) /* <= for tags */ : strImg.startsWith(strText) /* <= for attributes */); } @@ -280,6 +276,15 @@ return isTextRemovingAllowable; } + //+++ fix for issues #166462, #173122 + // (http://www.netbeans.org/issues/show_bug.cgi?id=166462) + // (http://www.netbeans.org/issues/show_bug.cgi?id=173122) + private boolean isTextRemovingAllowable(JTextComponent component, + BaseDocument doc, String replaceToText, int offset) throws BadLocationException { + XMLSyntaxSupport support = XMLSyntaxSupport.getSyntaxSupport(component.getDocument()); + return support.runWithSequence(offset, (TokenSequence ts) -> isRemovingAvailableLocked(ts, doc, offset, replaceToText)); + } + /** * Calculates the index of the first difference between two strings. * If they are differenent starting the first character, then 0 is returned. diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/Attr.java b/xml.text/src/org/netbeans/modules/xml/text/dom/AttrImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/dom/Attr.java rename to xml.text/src/org/netbeans/modules/xml/text/dom/AttrImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/Attr.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/AttrImpl.java @@ -44,13 +44,25 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import java.util.*; +import javax.swing.text.BadLocationException; +import org.netbeans.api.editor.document.AtomicLockDocument; +import org.netbeans.api.editor.document.LineDocument; +import org.netbeans.api.editor.document.LineDocumentUtils; import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.xml.spi.dom.AbstractNode; import org.netbeans.modules.xml.spi.dom.NodeListImpl; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.XMLTextUtils; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport.SequenceCallable; +import org.openide.util.Exceptions; +import org.w3c.dom.DOMException; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; @@ -65,23 +77,27 @@ * @author Petr Kuzel * @author asgeir@dimonsoftware.com */ -public class Attr extends AbstractNode implements org.w3c.dom.Attr { +public class AttrImpl extends AbstractNode implements org.w3c.dom.Attr, SyntaxElement { + private Token first; + private SyntaxElement parent; + private XMLSyntaxSupport syntax; // that produced us + private int index; - private Token first; - - private Element parent; - - private XMLSyntaxSupport syntax; // that produced us - - Attr(XMLSyntaxSupport syntax, Token first, Element parent) { + AttrImpl(XMLSyntaxSupport syntax, Token first, SyntaxElement parent, int index) { this.parent = parent; this.first = first; this.syntax = syntax; + this.index = index; } public Token getFirstToken() { return first; } + + @Override + public SyntaxElement getParentElement() { + return parent; + } /** * @return list of child nodes (Text or EntityReference), never null @@ -97,6 +113,52 @@ return new NodeListImpl(list); } + + @Override + public SyntaxElement getNext() { + if (parent == null) { + return null; + } + NamedNodeMap attrs = ((Element)parent.getNode()).getAttributes(); + if (index < attrs.getLength() - 1) { + return (SyntaxElement)attrs.item(index + 1); + } else { + return parent.getNext(); + } + } + + @Override + public SyntaxElement getPrevious() { + if (parent == null) { + return null; + } + NamedNodeMap attrs = ((Element)parent.getNode()).getAttributes(); + if (index > 0) { + return (SyntaxElement)attrs.item(index - 1); + } else { + return parent.getPrevious(); + } + } + + @Override + public int getElementLength() { + return getLength(); + } + + @Override + public int getElementOffset() { + return first.offset(null); + } + + @Override + public int getType() { + return Node.ATTRIBUTE_NODE; + } + + @Override + public Node getNode() { + return this; + } /** * Get next sibling for non syntax element text. @@ -120,39 +182,67 @@ } public Node getNextSibling() { - return null; //according to DOM-1spec + if (parent == null) { + return null; + } + NamedNodeMap attrs = ((Element)parent.getNode()).getAttributes(); + if (index < attrs.getLength() - 1) { + return attrs.item(index + 1); + } else { + return null; + } } public Node getPreviousSibling() { - return null; //according to DOM-1 spec + if (parent == null) { + return null; + } + NamedNodeMap attrs = ((Element)parent.getNode()).getAttributes(); + if (index > 0) { + return attrs.item(index - 1); + } else { + return null; + } + } + + private Node getFirstChildLocked(TokenSequence ts) { + while (ts.moveNext()) { + Token t = ts.token(); + if (t.id() == XMLTokenId.VALUE) { + // fuzziness to relax minor tokenization changes + CharSequence image = t.text(); + if (image.length() == 1) { + char test = image.charAt(0); + if (test == '"' || test == '\'') { + if (ts.moveNext()) { + t = ts.token(); + } else { + return null; + } + } + } + + if (t.id() == XMLTokenId.VALUE) { + return new TextImpl(syntax, t, ts.offset(), ts.offset() + t.length(), this); + } else { + return null; + } + } + } + return null; } public Node getFirstChild() { -// TokenItem next = first; -// for (; next != null; next = next.getNext()) { -// if (next.getTokenID() == VALUE) { -// // fuzziness to relax minor tokenization changes -// String image = next.getImage(); -// if (image.length() == 1) { -// char test = image.charAt(0); -// if (test == '"' || test == '\'') { -// next = next.getNext(); -// } -// } -// break; // we are after opening "'" -// } -// } -// if (next == null) return null; -// if (next.getTokenID() == VALUE) { -// return new TextImpl(syntax, next, this); //!!! strip out ending "'", return standalone "'" token -// } else { -// throw new RuntimeException("Not recognized yet: " + next.getTokenID()); -// } - return null; + try { + return syntax.runWithSequence(first, this::getFirstChildLocked); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + return null; + } } public Node getLastChild() { - throw new RuntimeException("Not implemented yet"); + return getFirstChild(); } public String getNodeName() { @@ -160,8 +250,7 @@ } public String getName() { - //return first.getImage(); - return null; + return first.text().toString(); } public boolean getSpecified() { @@ -169,82 +258,106 @@ } public void setValue(String value) { -// // Initialize oldValueStartPos and oldValueLength parameters -// int oldValueStartPos = -1; -// int oldValueLength = 0; -// boolean notClosed = false; -// char firstChar = '"'; -// char lastChar = '\0'; -// TokenItem next = first; -// for (; next != null; next = next.getNext()) { -// TokenID nextId = next.getTokenID(); -// -// if (oldValueStartPos != -1 && nextId != VALUE && nextId != CHARACTER) { -// break; -// } -// -// String nextImage = next.getImage(); -// -// String actualImage = Util.actualAttributeValue(nextImage); -// if (!nextImage.equals(actualImage)) { -// notClosed = true; -// nextImage = actualImage; -// } -// -// if (nextId == VALUE && oldValueStartPos == -1 && nextImage.length() > 0) { -// oldValueStartPos = next.getOffset(); -// if (nextImage.charAt(0) == '"' || nextImage.charAt(0) == '\'') { -// firstChar = nextImage.charAt(0); -// oldValueStartPos++; -// oldValueLength--; -// } -// } -// -// if (oldValueStartPos != -1 && nextImage.length() > 0) { -// oldValueLength += nextImage.length(); -// lastChar = nextImage.charAt(nextImage.length()-1); -// } -// -// if (notClosed) { -// break; -// } -// } -// -// if (lastChar == firstChar) { -// oldValueLength--; -// } -// -// // Replace known entities -// value = Util.replaceCharsWithEntityStrings(value); -// -// // Close the attribute if it was non-closed -// if (notClosed) { -// value += firstChar; -// } -// -// // Replace the text in the document -// BaseDocument doc = (BaseDocument)syntax.getDocument(); -// doc.atomicLock(); -// try { -// doc.remove(oldValueStartPos, oldValueLength); -// doc.insertString(oldValueStartPos, value, null); -// doc.invalidateSyntaxMarks(); -// } catch( BadLocationException e ) { -// throw new DOMException(DOMException.INVALID_STATE_ERR , e.getMessage()); -// } finally { -// doc.atomicUnlock(); -// } -// -// // Update the status of this object -// try { -// int endOffset = oldValueStartPos + oldValueLength; -// if (endOffset > doc.getLength()) { -// endOffset = doc.getLength(); -// } -// first = syntax.getTokenChain(first.getOffset(), endOffset); -// } catch (BadLocationException e) { -// throw new DOMException(DOMException.INVALID_STATE_ERR , e.getMessage()); -// } + class H implements SequenceCallable { + int oldValueStartPos = -1; + int oldValueLength = 0; + boolean notClosed = false; + char firstChar = '"'; + char lastChar = '\0'; + + @Override + public Object call(TokenSequence ts) throws BadLocationException { + Token next = first; + while (ts.moveNext()) { + next = ts.token(); + XMLTokenId nextId = next.id(); + + if (oldValueStartPos != -1 && nextId != XMLTokenId.VALUE && nextId != XMLTokenId.CHARACTER) { + break; + } + + String nextImage = next.text().toString(); + + String actualImage = XMLTextUtils.actualAttributeValue(nextImage); + if (!nextImage.equals(actualImage)) { + notClosed = true; + nextImage = actualImage; + } + + if (nextId == XMLTokenId.VALUE && oldValueStartPos == -1 && nextImage.length() > 0) { + oldValueStartPos = ts.offset(); + if (nextImage.charAt(0) == '"' || nextImage.charAt(0) == '\'') { + firstChar = nextImage.charAt(0); + oldValueStartPos++; + oldValueLength--; + } + } + + if (oldValueStartPos != -1 && nextImage.length() > 0) { + oldValueLength += nextImage.length(); + lastChar = nextImage.charAt(nextImage.length()-1); + } + + if (notClosed) { + break; + } + } + if (lastChar == firstChar) { + oldValueLength--; + } + + return null; + } + } + H h = new H(); + try { + syntax.runWithSequence(first.offset(null), h); + } catch (BadLocationException ex) { + throw new DOMException(DOMException.INVALID_STATE_ERR , ex.getMessage()); + } + + // Replace known entities + value = XMLTextUtils.replaceCharsWithEntityStrings(value); + + // Close the attribute if it was non-closed + if (h.notClosed) { + value += h.firstChar; + } + + // Replace the text in the document + final LineDocument doc = syntax.getDocument(); + AtomicLockDocument ald = LineDocumentUtils.asRequired(doc, AtomicLockDocument.class); + final BadLocationException[] ex = new BadLocationException[1]; + final int fOldValStartPos = h.oldValueStartPos; + final int fOldValLen = h.oldValueLength; + final String fValue = value; + ald.runAtomic(() -> {; + try { + doc.remove(fOldValStartPos, fOldValLen); + doc.insertString(fOldValStartPos, fValue, null); + //doc.invalidateSyntaxMarks(); + } catch( BadLocationException e ) { + ex[0] = e; + } + }); + if (ex[0] != null) { + throw new DOMException(DOMException.INVALID_STATE_ERR , ex[0].getMessage()); + } + + // Update the status of this object + try { + int endOffset = fOldValStartPos + fOldValLen; + if (endOffset > doc.getLength()) { + endOffset = doc.getLength(); + } + syntax.runWithSequence(first.offset(null), + (TokenSequence ts) -> { + first = ts.token(); + return null; + }); + } catch (BadLocationException e) { + throw new DOMException(DOMException.INVALID_STATE_ERR , e.getMessage()); + } } public void setNodeValue(String value) { @@ -259,42 +372,56 @@ return getValue(); } + private String getValueLocked(TokenSequence ts) { + StringBuilder sb = new StringBuilder(); + boolean valStarted = false; + V: while (ts.moveNext()) { + Token t = ts.token(); + switch (t.id()) { + case CHARACTER: + if (!valStarted) { + return null; + } + // fall through + case VALUE: { + String image = t.text().toString(); + String actual = XMLTextUtils.actualAttributeValue(image); + valStarted = true; + if (!image.equals(actual)) { + sb.append(actual); + break; + } else { + sb.append(image); + } + break; + } + case WS: + case OPERATOR: + break; + default: + break V; + } + } + // Remove " and ' around the attribute value + if (sb.length() > 0) { + char firstChar = sb.charAt(0); + if (firstChar == '"' || firstChar == '\'') { + sb.deleteCharAt(0); + if (sb.length() > 0 && sb.charAt(sb.length()-1) == firstChar) { + sb.deleteCharAt(sb.length()-1); + } + } + } + return XMLTextUtils.replaceEntityStringsWithChars(sb.toString()); + } + public String getValue() { -// // Find the first value token. Should be after "name=" -// TokenItem next = first; -// for (; next != null; next = next.getNext()) { -// if (next.getTokenID() == VALUE) { -// break; -// } -// } -// -// // Add values of all value and character entity -// StringBuffer buf = new StringBuffer(); -// while (next != null && (next.getTokenID() == VALUE || next.getTokenID() == CHARACTER)) { -// String image = next.getImage(); -// String actual = Util.actualAttributeValue(image); -// if (!image.equals(actual)) { -// buf.append(actual); -// break; -// } else { -// buf.append(image); -// } -// next = next.getNext(); -// } -// -// // Remove " and ' around the attribute value -// if (buf.length() > 0) { -// char firstChar = buf.charAt(0); -// if (firstChar == '"' || firstChar == '\'') { -// buf.deleteCharAt(0); -// if (buf.length() > 0 && buf.charAt(buf.length()-1) == firstChar) { -// buf.deleteCharAt(buf.length()-1); -// } -// } -// } -// -// return Util.replaceEntityStringsWithChars(buf.toString()); - return null; + try { + return syntax.runWithSequence(first, this::getValueLocked); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + return null; + } } public short getNodeType() { @@ -307,7 +434,10 @@ public Element getOwnerElement() { // ((Tag)parent).retokenizeObject(); - return parent; + if (parent == null) { + return null; + } + return (Element)parent.getNode(); } /** diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxElement.java b/xml.text/src/org/netbeans/modules/xml/text/dom/BaseSyntaxElement.java rename from xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxElement.java rename to xml.text/src/org/netbeans/modules/xml/text/dom/BaseSyntaxElement.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxElement.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/BaseSyntaxElement.java @@ -46,10 +46,13 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import java.lang.ref.WeakReference; import javax.swing.text.BadLocationException; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.w3c.dom.Node; /** @@ -64,19 +67,19 @@ * * @version 1.0 */ -public abstract class SyntaxElement { +public abstract class BaseSyntaxElement implements org.netbeans.modules.xml.text.api.dom.SyntaxElement { protected XMLSyntaxSupport support; private WeakReference first; //a weak reference to the fist TokenItem of this SE - private WeakReference previous; // WR to the cached previous element - private WeakReference next; // WR to the cached next element + private WeakReference previous; // WR to the cached previous element + private WeakReference next; // WR to the cached next element // let it be visible by static inner classes extending us protected int offset; // original position in document protected int length; // original lenght in document /** Creates new SyntaxElement */ - SyntaxElement(XMLSyntaxSupport support, Token token, int start, int end) { + BaseSyntaxElement(XMLSyntaxSupport support, Token token, int start, int end) { this.support = support; this.offset = start; this.length = end-start; @@ -118,11 +121,11 @@ return length; } - void setNext(SyntaxElement se) { + void setNext(BaseSyntaxElement se) { next = new WeakReference(se); } - void setPrevious(SyntaxElement se) { + void setPrevious(BaseSyntaxElement se) { previous = new WeakReference(se); } @@ -131,8 +134,8 @@ * @return previous SyntaxElement or null at document begining * or illegal location. */ - public SyntaxElement getPrevious() { - SyntaxElement cached_previous = (previous == null) ? null : previous.get(); + public BaseSyntaxElement getPrevious() { + BaseSyntaxElement cached_previous = (previous == null) ? null : previous.get(); if( cached_previous != null ) return cached_previous; try { @@ -141,7 +144,7 @@ return null; } //data not inialized yet or GC'ed already - we need to parse again - SyntaxElement new_previous = support.getElementChain( getElementOffset() - 1 ); + BaseSyntaxElement new_previous = (BaseSyntaxElement)support.getElementChain( getElementOffset() - 1 ); if( new_previous != null ) { setPrevious(new_previous); //weakly cache the element new_previous.setNext(this); @@ -160,13 +163,13 @@ * @return next SyntaxElement or null at document end * or illegal location. */ - public SyntaxElement getNext() { - SyntaxElement cached_next = next == null ? null : next.get(); + public BaseSyntaxElement getNext() { + BaseSyntaxElement cached_next = next == null ? null : next.get(); if( cached_next != null ) return cached_next; try { //data not inialized yet or GC'ed already - we need to parse again - SyntaxElement new_next = support.getElementChain( offset+length); + BaseSyntaxElement new_next = (BaseSyntaxElement)support.getElementChain( offset+length + 1); if( new_next != null ) { setNext(new_next); //weakly cache the element new_next.setPrevious(this); @@ -179,7 +182,7 @@ return null; } } - + /** * Print element content for debug purposes. */ @@ -199,16 +202,20 @@ * DOM Node equals. It's not compatible with Object's equals specs! */ public boolean equals(Object obj) { - if (obj instanceof SyntaxElement) { - if (((SyntaxElement)obj).offset == offset) return true; + if (obj instanceof BaseSyntaxElement) { + if (((BaseSyntaxElement)obj).offset == offset) return true; } return false; } + public String getName() { + return null; + } + /** * It may stop some DOM traversing. //!!! */ - public static class Error extends SyntaxElement { + public static class Error extends BaseSyntaxElement { public Error( XMLSyntaxSupport support, Token first, int start, int end ) { super( support, first, start, end); } @@ -216,6 +223,25 @@ public String toString() { return "Error" + super.toString(); // NOI18N } + + @Override + public int getType() { + return NODE_ERROR; + } + + @Override + public Node getNode() { + return null; + } + + @Override + public SyntaxElement getParentElement() { + BaseSyntaxElement x = this; + while (x != null && x.getType() != Node.ELEMENT_NODE) { + x = x.getPrevious(); + } + return x; + } } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/CDATASection.java b/xml.text/src/org/netbeans/modules/xml/text/dom/CDATASection.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/CDATASection.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/CDATASection.java @@ -44,27 +44,48 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; +import org.w3c.dom.Node; /** * CDATA section representation. */ -public class CDATASection extends Text { +public class CDATASection extends TextImpl implements org.w3c.dom.CDATASection { /** * Create content text node. */ - CDATASection(XMLSyntaxSupport support, Token from, int start, int end) { + public CDATASection(XMLSyntaxSupport support, Token from, int start, int end) { super( support, from, start, end); } + @Override + public String getNodeValue() { + String text = first().text().toString(); + int start = 0; + int end = text.length(); + if (text.startsWith("")) { + end = text.length() - 3; + } + return text.substring(start, end); + } + // /** // * Create attribute text node. // */ // CDATASection(XMLSyntaxSupport syntax, Token from, Attr parent) { // super( syntax, from, parent); // } + + @Override + public short getNodeType() { + return Node.CDATA_SECTION_NODE; + } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/Comment.java b/xml.text/src/org/netbeans/modules/xml/text/dom/Comment.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/Comment.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/Comment.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.xml.spi.dom.ROException; @@ -57,7 +58,7 @@ */ public class Comment extends SyntaxNode implements org.w3c.dom.Comment { - Comment(XMLSyntaxSupport support, Token from, int start, int end) { + public Comment(XMLSyntaxSupport support, Token from, int start, int end) { super( support, from, start, end); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/Document.java b/xml.text/src/org/netbeans/modules/xml/text/dom/Document.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/Document.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/Document.java @@ -45,12 +45,13 @@ package org.netbeans.modules.xml.text.dom; import org.netbeans.modules.xml.spi.dom.*; +import org.w3c.dom.DOMException; public class Document extends AbstractNode implements org.w3c.dom.Document { - SyntaxElement syntax; + BaseSyntaxElement syntax; - Document(SyntaxElement element) { + Document(BaseSyntaxElement element) { syntax = element; } @@ -273,6 +274,5 @@ } } - } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/DocumentType.java b/xml.text/src/org/netbeans/modules/xml/text/dom/DocumentType.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/DocumentType.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/DocumentType.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.xml.spi.dom.*; @@ -55,7 +56,7 @@ */ public class DocumentType extends SyntaxNode implements org.w3c.dom.DocumentType { - DocumentType(XMLSyntaxSupport syntax, Token first, int start, int end) { + public DocumentType(XMLSyntaxSupport syntax, Token first, int start, int end) { super (syntax, first, start, end); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/EmptyTag.java b/xml.text/src/org/netbeans/modules/xml/text/dom/EmptyTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/EmptyTag.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/EmptyTag.java @@ -45,6 +45,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; import org.w3c.dom.*; @@ -52,10 +53,10 @@ public class EmptyTag extends Tag { - EmptyTag(XMLSyntaxSupport support, Token from, int start, int end) { - super( support, from, start, end); + public EmptyTag(XMLSyntaxSupport support, Token from, int start, int end) { + super( support, from, start, end, from.text().toString().substring(1)); } - + public boolean hasChildNodes() { return false; } @@ -64,13 +65,28 @@ return NodeListImpl.EMPTY; } - protected Tag getEndTag() { + public Tag getEndTag() { return this; } - protected Tag getStartTag() { + public Tag getStartTag() { return this; } + + @Override + public boolean isStart() { + return false; + } + + @Override + public boolean isEnd() { + return false; + } + + @Override + public boolean isSelfClosing() { + return true; + } public String toString() { StringBuffer ret = new StringBuffer( "EmptyTag(\"" + name + "\" " ); diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/EndTag.java b/xml.text/src/org/netbeans/modules/xml/text/dom/EndTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/EndTag.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/EndTag.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import java.util.*; import org.netbeans.api.lexer.Token; @@ -57,9 +58,11 @@ */ public class EndTag extends Tag { - EndTag(XMLSyntaxSupport support, Token from, int start, int end) { - super( support, from, start, end); - this.name = from.text().toString(); + public EndTag(XMLSyntaxSupport support, Token from, int start, int end) { + super(support, from, start, end, from.text().toString().substring(2)); + if (name.equals("")) { // NOI18N + // self-closing tag ? -- TODO + } } /** @@ -75,7 +78,7 @@ } public boolean hasChildNodes() { - SyntaxElement prev = getPrevious(); + BaseSyntaxElement prev = getPrevious(); if (prev == null) return false; if (prev instanceof EndTag && ((EndTag)prev).getStartTag() == null) return false; if (prev instanceof StartTag) return false; @@ -95,7 +98,7 @@ return new NodeListImpl(list); } - protected Tag getStartTag() { + public Tag getStartTag() { SyntaxNode prev = findPrevious(); @@ -121,9 +124,25 @@ return null; } - protected Tag getEndTag() { + public Tag getEndTag() { return this; } + + @Override + public boolean isStart() { + return false; + } + + @Override + public boolean isEnd() { + return true; + } + + @Override + public boolean isSelfClosing() { + return false; + } + public String toString() { return "EndTag(\"" + name + "\") " + first(); diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/EntityReference.java b/xml.text/src/org/netbeans/modules/xml/text/dom/EntityReference.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/EntityReference.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/EntityReference.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; import org.w3c.dom.Node; diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/ProcessingInstruction.java b/xml.text/src/org/netbeans/modules/xml/text/dom/ProcessingInstruction.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/ProcessingInstruction.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/ProcessingInstruction.java @@ -44,6 +44,7 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; @@ -56,13 +57,13 @@ * * @author Petr Kuzel */ -public final class ProcessingInstruction extends SyntaxNode { +public final class ProcessingInstruction extends SyntaxNode implements org.w3c.dom.ProcessingInstruction { private String target; private String content; /** Creates a new instance of ProcessingInstructionImpl */ - ProcessingInstruction(XMLSyntaxSupport syntax, Token first, + public ProcessingInstruction(XMLSyntaxSupport syntax, Token first, int start, int end, String target, String content) { super(syntax, first, start, end); this.target = target; @@ -90,5 +91,14 @@ public void setData(String data) throws DOMException { throw new ROException(); } - + + @Override + public String getTarget() { + return getNodeName(); + } + + @Override + public String getData() { + return getNodeValue(); + } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/StartTag.java b/xml.text/src/org/netbeans/modules/xml/text/dom/StartTag.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/StartTag.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/StartTag.java @@ -44,22 +44,23 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import java.util.*; import org.netbeans.api.lexer.Token; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.modules.xml.spi.dom.NodeListImpl; +import org.netbeans.modules.xml.text.api.dom.TagElement; import org.w3c.dom.*; public class StartTag extends Tag { - StartTag(XMLSyntaxSupport support, Token from, int start, int end) { - super( support, from, start, end); - this.name = from.text().toString(); + public StartTag(XMLSyntaxSupport support, Token from, int start, int end) { + super( support, from, start, end, from.text().toString().substring(1)); } public boolean hasChildNodes() { - SyntaxElement next = getNext(); + BaseSyntaxElement next = getNext(); if (next == null) return false; // if not well-formed if (next instanceof StartTag && ((StartTag)next).getEndTag() == null) return false; @@ -80,11 +81,11 @@ return new NodeListImpl(list); } - protected Tag getStartTag() { + public Tag getStartTag() { return this; } - protected Tag getEndTag() { + public Tag getEndTag() { SyntaxNode next = findNext(); @@ -116,5 +117,16 @@ return ret.toString() + " " + first() + ")"; } + public boolean isStart() { + return true; + } + + public boolean isEnd() { + return false; + } + + public boolean isSelfClosing() { + return false; + } } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxNode.java b/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxNode.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxNode.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/SyntaxNode.java @@ -44,10 +44,13 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.modules.xml.spi.dom.*; import org.netbeans.api.lexer.Token; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.w3c.dom.Text; import org.w3c.dom.TypeInfo; import org.w3c.dom.UserDataHandler; @@ -67,13 +70,22 @@ * @version 1.0 */ -public abstract class SyntaxNode extends SyntaxElement implements org.w3c.dom.Node { +public abstract class SyntaxNode extends BaseSyntaxElement implements org.w3c.dom.Node { /** Creates new SyntaxNode */ SyntaxNode(XMLSyntaxSupport support, Token first, int start, int end) { super( support, first, start, end); } + @Override + public int getType() { + return getNodeType(); + } + + @Override + public Node getNode() { + return this; + } /** * Default implementation returning first previous SyntaxNode * or null. It is StartTag aware. @@ -92,8 +104,8 @@ /** * Find previous SyntaxNode instance or null. */ - static SyntaxNode findPrevious(SyntaxElement el) { - SyntaxElement prev = el.getPrevious(); + static SyntaxNode findPrevious(BaseSyntaxElement el) { + BaseSyntaxElement prev = el.getPrevious(); while ((prev instanceof SyntaxNode) == false) { if (prev == null) return null; prev = prev.getPrevious(); @@ -125,8 +137,8 @@ /** * Find previous SyntaxNode instance or null. */ - static SyntaxNode findNext(SyntaxElement el) { - SyntaxElement next = el.getNext(); + static SyntaxNode findNext(BaseSyntaxElement el) { + BaseSyntaxElement next = el.getNext(); while ((next instanceof SyntaxNode) == false) { if (next == null) return null; next = next.getNext(); @@ -141,6 +153,11 @@ return findNext(this); } + public SyntaxElement getParentElement() { + Node n = getParentNode(); + return n instanceof SyntaxElement ? (SyntaxElement)n : null; + } + /** * First previous start tag at higher level is my parent. * Skip all end-tag start-tag pairs at the same level. @@ -338,5 +355,4 @@ public void setIdAttributeNode(org.w3c.dom.Attr a, boolean b) { throw new UOException (); } - } diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/Tag.java b/xml.text/src/org/netbeans/modules/xml/text/dom/Tag.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/Tag.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/Tag.java @@ -44,10 +44,19 @@ package org.netbeans.modules.xml.text.dom; -import java.util.Collection; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import java.util.Map; +import java.util.HashMap; +import java.util.LinkedHashMap; +import javax.swing.text.BadLocationException; import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.spi.dom.NamedNodeMapImpl; import org.netbeans.modules.xml.spi.dom.ROException; import org.netbeans.modules.xml.spi.dom.UOException; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.openide.util.Exceptions; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -61,14 +70,15 @@ * equals. The equals is used for syntax element * purposes. */ -public abstract class Tag extends SyntaxNode implements org.w3c.dom.Element { +public abstract class Tag extends SyntaxNode implements org.w3c.dom.Element, TagElement { protected NamedNodeMap domAttributes; protected String name; - Tag(XMLSyntaxSupport support, Token from, int start, int end) { + Tag(XMLSyntaxSupport support, Token from, int start, int end, String name) { super(support, from, start, end); + this.name = name; } public final short getNodeType() { @@ -83,54 +93,84 @@ return name; } + private Map parseAttributes(TokenSequence ts) { + HashMap map = new LinkedHashMap(3); + + int index = 0; + SCAN_LOOP: + while (ts.moveNext()) { + Token next = ts.token(); + XMLTokenId id = next.id(); + String name; + String value; + if (id == XMLTokenId.ARGUMENT) { + Token attributeStart = next; + name = next.text().toString(); + while (next.id() != XMLTokenId.VALUE) { + if (!ts.moveNext()) { + break SCAN_LOOP; + } + next = ts.token(); + if (next.id() == XMLTokenId.ERROR) { + break SCAN_LOOP; + } + } + + // fuzziness to relax minor tokenization changes + String image = next.text().toString(); + char test = image.charAt(0); + if (image.length() == 1) { + if (test == '"' || test == '\'') { + if (!ts.moveNext()) { + break SCAN_LOOP; + } + next = ts.token(); + } + } + + value = next.text().toString(); + + Object key = NamedNodeMapImpl.createKey(name); + map.put(key, new AttrImpl(support, attributeStart, this, index++)); + + next = skipAttributeValue(ts, test); + if (next == null) { + break SCAN_LOOP; + } + } else if (id == XMLTokenId.WS) { + // just skip + } else { + break; // end of element markup + } + } + return map; + } + + private static Token skipAttributeValue(TokenSequence ts, char delim) { + do { + Token t = ts.token(); + if (t.text().charAt(t.length() - 1) == delim) { + return ts.moveNext() ? ts.token() : null; + } + } while (ts.moveNext()); + return null; + } + /** * Create properly bound attributes and cache results. * Parse attributes from first token. */ public synchronized NamedNodeMap getAttributes() { - -// HashMap map = new LinkedHashMap(3); -// -// SCAN_LOOP: -// for (TokenItem next = first().getNext(); next != null; next = next.getNext()) { -// TokenID id = next.getTokenID(); -// String name; -// String value; -// if (id == ARGUMENT) { -// TokenItem attributeStart = next; -// name = next.getImage(); -// while (next.getTokenID() != VALUE) { -// next = next.getNext(); -// if (next == null || next.getTokenID() == ERROR) break SCAN_LOOP; -// } -// -// // fuzziness to relax minor tokenization changes -// String image = next.getImage(); -// char test = image.charAt(0); -// if (image.length() == 1) { -// if (test == '"' || test == '\'') { -// next = next.getNext(); -// } -// } -// -// if (next == null) break SCAN_LOOP; -// value = next.getImage(); -// -// Object key = NamedNodeMapImpl.createKey(name); -// map.put(key, new AttrImpl(support, attributeStart, this)); -// -// next = Util.skipAttributeValue(next, test); -// if (next == null) break SCAN_LOOP; -// } else if (id == WS) { -// // just skip -// } else { -// break; // end of element markup -// } -// } -// -// // domAttributes = new NamedNodeMapImpl(map); -// return new NamedNodeMapImpl(map); - return null; + try { + return new NamedNodeMapImpl( + support.runWithSequence(offset, (TokenSequence ts) -> { + return parseAttributes(ts); + }) + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + return null; + } } public String getAttribute(String name) { @@ -276,9 +316,9 @@ return list.item(list.getLength()); } - protected abstract Tag getStartTag(); + public abstract Tag getStartTag(); - protected abstract Tag getEndTag(); + public abstract Tag getEndTag(); // unsupported DOM level 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public String getAttributeNS(String namespaceURI, String localName) { diff --git a/xml.text/src/org/netbeans/modules/xml/text/dom/Text.java b/xml.text/src/org/netbeans/modules/xml/text/dom/TextImpl.java rename from xml.text/src/org/netbeans/modules/xml/text/dom/Text.java rename to xml.text/src/org/netbeans/modules/xml/text/dom/TextImpl.java --- a/xml.text/src/org/netbeans/modules/xml/text/dom/Text.java +++ b/xml.text/src/org/netbeans/modules/xml/text/dom/TextImpl.java @@ -44,10 +44,10 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.api.lexer.Token; import org.w3c.dom.*; import org.netbeans.modules.xml.spi.dom.*; -import org.netbeans.editor.*; /** * DOM Text implementation. Note that it is automatically @@ -58,22 +58,22 @@ * * @author Petr Kuzel */ -public class Text extends SyntaxNode implements org.w3c.dom.Text { +public class TextImpl extends SyntaxNode implements org.w3c.dom.Text { // if attribute text node then parent otherwise null - private Attr parent; + private AttrImpl parent; /** * Create content text node. */ - Text(XMLSyntaxSupport support, Token from, int start, int end) { + public TextImpl(XMLSyntaxSupport support, Token from, int start, int end) { super( support, from, start, end); } /** * Create attribute text node. */ - Text(XMLSyntaxSupport syntax, Token from, int start, int end, Attr parent) { + public TextImpl(XMLSyntaxSupport syntax, Token from, int start, int end, AttrImpl parent) { super( syntax, from, start, end); if (parent == null) throw new IllegalArgumentException(); this.parent = parent; @@ -108,7 +108,7 @@ return getData(); } - public Text splitText(int offset) { + public TextImpl splitText(int offset) { throw new ROException(); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/folding/XmlFoldManager.java b/xml.text/src/org/netbeans/modules/xml/text/folding/XmlFoldManager.java --- a/xml.text/src/org/netbeans/modules/xml/text/folding/XmlFoldManager.java +++ b/xml.text/src/org/netbeans/modules/xml/text/folding/XmlFoldManager.java @@ -68,9 +68,9 @@ import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.Utilities; +import org.netbeans.modules.xml.text.api.XMLTextUtils; import org.netbeans.modules.xml.text.folding.TokenElement.Token; import org.netbeans.modules.xml.text.folding.TokenElement.TokenType; -import org.netbeans.modules.xml.text.syntax.XMLKit; /** * This class is an implementation of @see org.netbeans.spi.editor.fold.FoldManager @@ -93,7 +93,7 @@ private Preferences prefs; public XmlFoldManager() { - prefs = MimeLookup.getLookup(XMLKit.MIME_TYPE).lookup(Preferences.class); + prefs = MimeLookup.getLookup(XMLTextUtils.XML_MIME).lookup(Preferences.class); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatter.java b/xml.text/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatter.java --- a/xml.text/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatter.java +++ b/xml.text/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatter.java @@ -45,12 +45,12 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.Stack; import java.util.logging.Logger; import javax.swing.text.BadLocationException; -import javax.swing.text.Element; +import org.netbeans.api.editor.document.LineDocument; +import org.netbeans.api.editor.document.LineDocumentUtils; import org.netbeans.api.lexer.LanguagePath; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; @@ -104,7 +104,7 @@ }); } - public BaseDocument doReformat(BaseDocument doc, int startOffset, int endOffset) { + public LineDocument doReformat(LineDocument doc, int startOffset, int endOffset) { spacesPerTab = IndentUtils.indentLevelSize(doc); try { List tags = getTags(doc, startOffset, endOffset); @@ -125,7 +125,7 @@ return doc; } - private void changePrettyText(BaseDocument doc, TokenIndent tag) throws BadLocationException { + private void changePrettyText(LineDocument doc, TokenIndent tag) throws BadLocationException { //i expected the call IndentUtils.createIndentString() to return //the correct string for the indent level, but it doesn't. //so this is just a workaround. @@ -137,11 +137,11 @@ noNewline = tag.isNoNewline(); String newIndentText = IndentUtils.createIndentString(doc, spaces); //String newIndentText = formatter.getIndentString(doc, tag.getIndentLevel()); - int previousEndOffset = Utilities.getFirstNonWhiteBwd(doc, so) + 1; + int previousEndOffset = LineDocumentUtils.getPreviousNonWhitespace(doc, so) + 1; CharSequence temp = org.netbeans.lib.editor.util.swing.DocumentUtilities.getText(doc, previousEndOffset, so - previousEndOffset); if(noNewline || so == 0 || CharSequences.indexOf(temp, "\n") != -1){ // NOI18N - int i = Utilities.getRowFirstNonWhite(doc, so); - int rowStart = Utilities.getRowStart(doc, so); + int i = LineDocumentUtils.getLineFirstNonWhitespace(doc, so); + int rowStart = LineDocumentUtils.getLineStart(doc, so); String currentIndent = doc.getText(rowStart, i - rowStart); if (!currentIndent.equals(newIndentText)) { @@ -202,7 +202,7 @@ /** * The processed document */ - private BaseDocument basedoc; + private LineDocument basedoc; private void outsideAttributes() { firstAttributeIndent = -1; @@ -258,9 +258,9 @@ } else { try { // align with the actual tag: - indentLevel = Utilities.getVisualColumn(basedoc, - Utilities.getFirstNonWhiteFwd(basedoc, - Utilities.getRowStart(basedoc, tokenSequence.offset()))); + indentLevel = Utilities.getVisualColumn((BaseDocument)basedoc, + LineDocumentUtils.getNextNonWhitespace(basedoc, + LineDocumentUtils.getLineStart(basedoc, tokenSequence.offset()))); if (!increase) { indentLevel = Math.max(- spacesPerTab, indentLevel - spacesPerTab); } @@ -322,7 +322,7 @@ if (!indent) { if (!selfClosed && onlyTags) { indent = true; - int start = Utilities.getRowStart(basedoc, tokenSequence.offset()); + int start = LineDocumentUtils.getLineStart(basedoc, tokenSequence.offset()); // do not indent closing tags, if the start & end tag will end up on the same line: if (myIndent != null) { int openStart = myIndent.getStartOffset(); @@ -370,7 +370,7 @@ } else { // align one space after the tagname: TokenIndent tagIndent = stack.peek(); - int current = Utilities.getVisualColumn(basedoc, tokenSequence.offset()); + int current = Utilities.getVisualColumn((BaseDocument)basedoc, tokenSequence.offset()); if (tagIndent == null) { // fallback firstAttributeIndent = current; @@ -438,7 +438,7 @@ if (lastNewline == -1 || preserveWhitespace || !intersectsWithRange) { // even if outside selection range, we do not update indent; text will not affect following tags // we have to set the 'newLine' flag, if the last text line only contains whitespaces. - int nonWhitePos = Utilities.getFirstNonWhiteFwd(basedoc, currentOffset + Math.max(0, lastNewline), currentOffset + image.length()); + int nonWhitePos = LineDocumentUtils.getNextNonWhitespace(basedoc, currentOffset + Math.max(0, lastNewline), currentOffset + image.length()); contentPresent |= nonWhitePos > -1; wasNewline &= nonWhitePos == -1; onlyTags &= nonWhitePos == -1; @@ -451,7 +451,7 @@ while (lno < lineCount) { currentOffset += lno == 0 ? 0 : lineSizes[lno - 1] + 1; // add 1 for newline int lineEnd = currentOffset + lineSizes[lno]; - nonWhiteStart = Utilities.getFirstNonWhiteFwd(basedoc, currentOffset, lineEnd); + nonWhiteStart = LineDocumentUtils.getNextNonWhitespace(basedoc, currentOffset, lineEnd); // implies a check for nonWhitestart > -1 if (nonWhiteStart >= startOffset && nonWhiteStart <= endOffset) { // emit a tag at this position @@ -520,7 +520,7 @@ * XML and the use of the xml:space attribute. Together they are used to * calculate how much each token should be indented by. */ - private List getTags(BaseDocument basedoc, int startOffset, int endOffset) + private List getTags(LineDocument basedoc, int startOffset, int endOffset) throws BadLocationException, IOException { @@ -530,183 +530,201 @@ // this is that 1st PI or tag will increment the level to 0 indentLevel = -spacesPerTab; - basedoc.readLock(); - try { - TokenHierarchy tokenHierarchy = TokenHierarchy.get(basedoc); - tokenSequence = tokenHierarchy.tokenSequence(); + List[] result = new List[1]; + Exception[] ble = new Exception[1]; + basedoc.render(() -> { + try { + result[0] = getTagsLocked(startOffset, endOffset); + } catch (BadLocationException | IOException ex) { + ble[0] = ex; + } + }); + if (ble[0] != null) { + if (ble[0] instanceof BadLocationException) { + throw (BadLocationException)ble[0]; + } + if (ble[0] instanceof IOException) { + throw (IOException)ble[0]; + } else { + throw new IOException(ble[0]); + } + } + return result[0]; + } + + private List getTagsLocked(int startOffset, int endOffset) throws BadLocationException, IOException { + TokenHierarchy tokenHierarchy = TokenHierarchy.get(basedoc); + tokenSequence = tokenHierarchy.tokenSequence(); + token = tokenSequence.token(); + // Add the text token, if any, before xml declaration to document node + if (token != null && token.id() == XMLTokenId.TEXT) { + if (tokenSequence.moveNext()) { + token = tokenSequence.token(); + } + } + currentTokensSize = 0; + + + // will be set to indent of 1st attribute of a tag. Will be reset to -1 by start tag + firstAttributeIndent = -1; + wasNewline = false; + + while (tokenSequence.moveNext()) { + int indentLineStart = 1; token = tokenSequence.token(); - // Add the text token, if any, before xml declaration to document node - if (token != null && token.id() == XMLTokenId.TEXT) { - if (tokenSequence.moveNext()) { - token = tokenSequence.token(); - } + XMLTokenId tokenId = token.id(); + CharSequence image = token.text(); + if (tokenSequence.offset() > endOffset) { + break; } - currentTokensSize = 0; - - - // will be set to indent of 1st attribute of a tag. Will be reset to -1 by start tag - firstAttributeIndent = -1; - wasNewline = false; - - while (tokenSequence.moveNext()) { - int indentLineStart = 1; - token = tokenSequence.token(); - XMLTokenId tokenId = token.id(); - CharSequence image = token.text(); - if (tokenSequence.offset() > endOffset) { + tokenInSelectionRange = tokenSequence.offset() >= startOffset || tokenSequence.offset() + token.length() > endOffset; + switch (tokenId) { + case TAG: { // Tag is encountered and the required level of indenting determined. + // The tokens are only assessed if they are in the selection + // range, which is the whole document if no text is selected. + int len = image.length(); + firstAttributeIndent = -1; + if (image.charAt(len - 1) == '>') {// '/>' // NOI18N + if (len == 2) { + endTag(image, true); + } else { + // end tag name marker + tagClose(image); + } + } else { + if (startsWith(image, "= startOffset || tokenSequence.offset() + token.length() > endOffset; - switch (tokenId) { - case TAG: { // Tag is encountered and the required level of indenting determined. - // The tokens are only assessed if they are in the selection - // range, which is the whole document if no text is selected. - int len = image.length(); - firstAttributeIndent = -1; - if (image.charAt(len - 1) == '>') {// '/>' // NOI18N - if (len == 2) { - endTag(image, true); - } else { - // end tag name marker - tagClose(image); - } - } else { - if (startsWith(image, " -1) { + // we cannot indent comment start, will not touch even the rest of the comment. break; } - /** - * Block comments are aligned as follows: - * - if there is some preceeding non-whitespace, do not format anything. E.g. comments after element. Skip entire comment from formatting - * - align 1st and last line at the appropriate indent level - * - compute "shift" from the last line & indent level - * - shift INTERIOR of the comment by the computed shift - * - * This algorithm tries to preserve internal formatting of the comment - */ - case BLOCK_COMMENT: { - int currentOffset = tokenSequence.offset(); + int lastLineStart = LineDocumentUtils.getLineStart(basedoc, currentOffset + token.length() - 1); + int lastIndent = IndentUtils.lineIndent(basedoc, lastLineStart); - splitLines(image); + // align 1st and last row here: + int baseIndent = indentLevel + spacesPerTab; + // shift the rest of lines by this offset + int indentShift = baseIndent - lastIndent; - int lineStart = Utilities.getRowStart(basedoc, currentOffset); + // how much to shift the interior of the comment - if (lineStart < currentOffset && - Utilities.getFirstNonWhiteBwd(basedoc, currentOffset, lineStart) > -1) { - // we cannot indent comment start, will not touch even the rest of the comment. - break; + for (int lno = 0; lno < lineCount; lno++) { + // indent 1st comment line, as if it was text: + int lineEnd = LineDocumentUtils.getLineEnd(basedoc, currentOffset); + + int desiredIndent; + if (lno == 0 || lno == lineCount -1) { + desiredIndent = baseIndent; + } else { + desiredIndent = IndentUtils.lineIndent(basedoc, currentOffset) + indentShift; } - - int lastLineStart = Utilities.getRowStart(basedoc, currentOffset + token.length() - 1); - int lastIndent = IndentUtils.lineIndent(basedoc, lastLineStart); - // align 1st and last row here: - int baseIndent = indentLevel + spacesPerTab; - // shift the rest of lines by this offset - int indentShift = baseIndent - lastIndent; + if ((currentOffset >= startOffset || currentOffset + lineSizes[lno] > endOffset) && currentOffset < endOffset) { + tags.add(new TokenIndent( + false, + currentOffset, Math.max(0, desiredIndent) + )); + } + currentOffset += lineSizes[lno] + 1; + } + break; + } - // how much to shift the interior of the comment - - for (int lno = 0; lno < lineCount; lno++) { - // indent 1st comment line, as if it was text: - int lineEnd = Utilities.getRowEnd(basedoc, currentOffset); - - int desiredIndent; - if (lno == 0 || lno == lineCount -1) { - desiredIndent = baseIndent; - } else { - desiredIndent = IndentUtils.lineIndent(basedoc, currentOffset) + indentShift; - } - - if ((currentOffset >= startOffset || currentOffset + lineSizes[lno] > endOffset) && currentOffset < endOffset) { - tags.add(new TokenIndent( - false, - currentOffset, Math.max(0, desiredIndent) - )); - } - currentOffset += lineSizes[lno] + 1; - } - break; - } - - case CDATA_SECTION: { - // always form a non-empty content - contentPresent = true; - onlyTags = false; - wasNewline = false; - } - case CHARACTER: - case OPERATOR: - case PI_TARGET: - case DECLARATION: - break; //Do nothing for above case's - case ARGUMENT: //attribute of an element - attributeName(); - break; - case VALUE: - attributeValue(); - break; - - case ERROR: - case EOL: - default: - throw new IOException("Invalid token found in document: " - + "Please use the text editor to resolve the issues..."); - } - currentTokensSize += image.length(); - if (tokenId != XMLTokenId.WS && tokenId != XMLTokenId.TEXT && tokenId != XMLTokenId.PI_CONTENT) { - // clear indicator of the newline + case CDATA_SECTION: { + // always form a non-empty content + contentPresent = true; + onlyTags = false; wasNewline = false; } + case CHARACTER: + case OPERATOR: + case PI_TARGET: + case DECLARATION: + break; //Do nothing for above case's + case ARGUMENT: //attribute of an element + attributeName(); + break; + case VALUE: + attributeValue(); + break; + + case ERROR: + case EOL: + default: + throw new IOException("Invalid token found in document: " + + "Please use the text editor to resolve the issues..."); } - } finally { - basedoc.readUnlock(); + currentTokensSize += image.length(); + if (tokenId != XMLTokenId.WS && tokenId != XMLTokenId.TEXT && tokenId != XMLTokenId.PI_CONTENT) { + // clear indicator of the newline + wasNewline = false; + } } return tags; } diff --git a/xml.text/src/org/netbeans/modules/xml/text/navigator/NavigatorTreeCellRenderer.java b/xml.text/src/org/netbeans/modules/xml/text/navigator/NavigatorTreeCellRenderer.java --- a/xml.text/src/org/netbeans/modules/xml/text/navigator/NavigatorTreeCellRenderer.java +++ b/xml.text/src/org/netbeans/modules/xml/text/navigator/NavigatorTreeCellRenderer.java @@ -52,7 +52,7 @@ import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellRenderer; import org.netbeans.modules.editor.structure.api.DocumentElement; -import org.netbeans.modules.xml.text.structure.XMLDocumentModelProvider; +import static org.netbeans.modules.xml.text.structure.XMLConstants.*; import org.openide.awt.HtmlRenderer; import org.openide.util.ImageUtilities; import org.openide.util.Utilities; @@ -100,14 +100,14 @@ boolean containsError = tna.getChildrenErrorCount() > 0; //normal icons - if(de.getType().equals(XMLDocumentModelProvider.XML_TAG) - || de.getType().equals(XMLDocumentModelProvider.XML_EMPTY_TAG)) { + if(de.getType().equals(XML_TAG) + || de.getType().equals(XML_EMPTY_TAG)) { setIcon(TAG_ICON, containsError); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_PI)) { + } else if(de.getType().equals(XML_PI)) { setIcon(PI_ICON, containsError); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_DOCTYPE)) { + } else if(de.getType().equals(XML_DOCTYPE)) { setIcon(DOCTYPE_ICON, containsError); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_CDATA)) { + } else if(de.getType().equals(XML_CDATA)) { setIcon(CDATA_ICON, containsError); } diff --git a/xml.text/src/org/netbeans/modules/xml/text/navigator/TreeNodeAdapter.java b/xml.text/src/org/netbeans/modules/xml/text/navigator/TreeNodeAdapter.java --- a/xml.text/src/org/netbeans/modules/xml/text/navigator/TreeNodeAdapter.java +++ b/xml.text/src/org/netbeans/modules/xml/text/navigator/TreeNodeAdapter.java @@ -47,21 +47,17 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; import javax.swing.JTree; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; -import javax.swing.text.Document; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; -import org.netbeans.editor.BaseDocument; import org.netbeans.modules.editor.structure.api.DocumentElement; import org.netbeans.modules.editor.structure.api.DocumentElementEvent; import org.netbeans.modules.editor.structure.api.DocumentElementListener; -import org.netbeans.modules.xml.text.folding.XmlFoldTypes; -import org.netbeans.modules.xml.text.structure.XMLDocumentModelProvider; +import static org.netbeans.modules.xml.text.structure.XMLConstants.*; import org.openide.ErrorManager; /** @@ -181,8 +177,8 @@ } public String getText(boolean html) { - if(de.getType().equals(XMLDocumentModelProvider.XML_TAG) - || de.getType().equals(XMLDocumentModelProvider.XML_EMPTY_TAG)) { + if(de.getType().equals(XML_TAG) + || de.getType().equals(XML_EMPTY_TAG)) { //XML TAG text String attribsVisibleText = ""; AttributeSet attribs = getDocumentElement().getAttributes(); @@ -220,17 +216,17 @@ return text.toString(); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_PI)) { + } else if(de.getType().equals(XML_PI)) { //PI text String documentText = getPIText(); documentText = documentText.length() > TEXT_MAX_LEN ? documentText.substring(0,TEXT_MAX_LEN) + "..." : documentText; return documentText; - } else if(de.getType().equals(XMLDocumentModelProvider.XML_DOCTYPE)) { + } else if(de.getType().equals(XML_DOCTYPE)) { //limit the text length String documentText = getDoctypeText(); String visibleText = documentText.length() > TEXT_MAX_LEN ? documentText.substring(0,TEXT_MAX_LEN) + "..." : documentText; return visibleText; - } else if(de.getType().equals(XMLDocumentModelProvider.XML_CDATA)) { + } else if(de.getType().equals(XML_CDATA)) { //limit the text length String documentText = getCDATAText(); String visibleText = documentText.length() > TEXT_MAX_LEN ? documentText.substring(0,TEXT_MAX_LEN) + "..." : documentText; @@ -241,14 +237,14 @@ } public String getToolTipText() { - if(de.getType().equals(XMLDocumentModelProvider.XML_TAG) - || de.getType().equals(XMLDocumentModelProvider.XML_EMPTY_TAG)) { + if(de.getType().equals(XML_TAG) + || de.getType().equals(XML_EMPTY_TAG)) { return getAttribsText() + " " + getDocumentContent(); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_PI)) { + } else if(de.getType().equals(XML_PI)) { return getPIText(); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_DOCTYPE)) { + } else if(de.getType().equals(XML_DOCTYPE)) { return getDoctypeText(); - } else if(de.getType().equals(XMLDocumentModelProvider.XML_CDATA)) { + } else if(de.getType().equals(XML_CDATA)) { return getCDATAText(); } return ""; @@ -323,15 +319,15 @@ DocumentElement ade = e.getChangedChild(); if(debug) System.out.println(">>> +EVENT called on " + hashCode() + " - " + de + ": element " + ade + " is going to be added"); - if(ade.getType().equals(XMLDocumentModelProvider.XML_CONTENT)) { + if(ade.getType().equals(XML_CONTENT)) { //create a text node listener textElements.add(new TextElementWrapper(ade)); //update text text content of the node childTextElementChanged(); - } else if(ade.getType().equals(XMLDocumentModelProvider.XML_ERROR)) { + } else if(ade.getType().equals(XML_ERROR)) { //handle error element markNodeAsError(this); - } else if(ade.getType().equals(XMLDocumentModelProvider.XML_COMMENT)) { + } else if(ade.getType().equals(XML_COMMENT)) { //do nothing for comments } else { TreeNode tn = new TreeNodeAdapter(ade, tm, tree, this); @@ -416,9 +412,9 @@ if(child.equals(de)) return index; //skip text and error tokens - if(!child.getType().equals(XMLDocumentModelProvider.XML_CONTENT) - && !child.getType().equals(XMLDocumentModelProvider.XML_ERROR) - && !child.getType().equals(XMLDocumentModelProvider.XML_COMMENT)) index++; + if(!child.getType().equals(XML_CONTENT) + && !child.getType().equals(XML_ERROR) + && !child.getType().equals(XML_COMMENT)) index++; } return -1; } @@ -428,7 +424,7 @@ if(debug) System.out.println(">>> -EVENT on " + hashCode() + " - " + de + ": element " + rde + " is going to be removed "); - if(rde.getType().equals(XMLDocumentModelProvider.XML_CONTENT)) { + if(rde.getType().equals(XML_CONTENT)) { if(debug) System.out.println(">>> removing CONTENT element"); //remove the text eleemnt listener Iterator i = textElements.iterator(); @@ -440,9 +436,9 @@ textElements.removeAll(toRemove); //update text text content of the node childTextElementChanged(); - } else if(rde.getType().equals(XMLDocumentModelProvider.XML_ERROR)) { + } else if(rde.getType().equals(XML_ERROR)) { unmarkNodeAsError(this); - } else if(rde.getType().equals(XMLDocumentModelProvider.XML_COMMENT)) { + } else if(rde.getType().equals(XML_COMMENT)) { //do nothing for comments } else { if(debug) System.out.println(">>> removing tag element"); @@ -494,13 +490,13 @@ boolean textElementAdded = false; while(i.hasNext()) { DocumentElement chde = (DocumentElement)i.next(); - if(chde.getType().equals(XMLDocumentModelProvider.XML_CONTENT)) { + if(chde.getType().equals(XML_CONTENT)) { //create a text node listener textElements.add(new TextElementWrapper(chde)); textElementAdded = true; - } else if(chde.getType().equals(XMLDocumentModelProvider.XML_ERROR)) { + } else if(chde.getType().equals(XML_ERROR)) { markNodeAsError(this); - } else if(chde.getType().equals(XMLDocumentModelProvider.XML_COMMENT)) { + } else if(chde.getType().equals(XML_COMMENT)) { //do nothing for comments } else { //add the adapter only when there isn't any @@ -529,7 +525,7 @@ //System.out.println("childTextElementChanged(): " + getDocumentElement() + " has these children:"); while(children.hasNext()) { DocumentElement del = (DocumentElement)children.next(); - if(del.getType().equals(XMLDocumentModelProvider.XML_CONTENT)) { + if(del.getType().equals(XML_CONTENT)) { try { //the endoffset if increased by +1 due to still not yet resolved issue with element boundaries //should be removed once it is properly fixed. On the other hand the issue has no user impact now. diff --git a/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml b/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml --- a/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml +++ b/xml.text/src/org/netbeans/modules/xml/text/resources/DTDEditor-preferences.xml @@ -46,7 +46,6 @@ - diff --git a/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml b/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml --- a/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml +++ b/xml.text/src/org/netbeans/modules/xml/text/resources/XMLEditor-preferences.xml @@ -47,7 +47,6 @@ - diff --git a/xml.text/src/org/netbeans/modules/xml/text/structure/XMLConstants.java b/xml.text/src/org/netbeans/modules/xml/text/structure/XMLConstants.java new file mode 100644 --- /dev/null +++ b/xml.text/src/org/netbeans/modules/xml/text/structure/XMLConstants.java @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.structure; + +/** + * + * @author sdedic + */ +public class XMLConstants { + public static final String XML_TAG = "tag"; + public static final String XML_EMPTY_TAG = "empty_tag"; + public static final String XML_CONTENT = "content"; + public static final String XML_PI = "pi"; + public static final String XML_CDATA = "cdata"; + public static final String XML_DOCTYPE = "doctype"; + public static final String XML_COMMENT = "comment"; + + public static final String XML_ERROR = "error"; +} diff --git a/xml.text/src/org/netbeans/modules/xml/text/structure/XMLDocumentModelProvider.java b/xml.text/src/org/netbeans/modules/xml/text/structure/XMLDocumentModelProvider.java --- a/xml.text/src/org/netbeans/modules/xml/text/structure/XMLDocumentModelProvider.java +++ b/xml.text/src/org/netbeans/modules/xml/text/structure/XMLDocumentModelProvider.java @@ -56,8 +56,10 @@ import java.util.TreeSet; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.TokenItem; import org.netbeans.modules.editor.structure.api.DocumentElement; import org.netbeans.modules.editor.structure.api.DocumentModel; import org.netbeans.modules.editor.structure.api.DocumentModel.DocumentChange; @@ -65,20 +67,15 @@ import org.netbeans.modules.editor.structure.api.DocumentModelException; import org.netbeans.modules.editor.structure.api.DocumentModelUtils; import org.netbeans.modules.editor.structure.spi.DocumentModelProvider; -import org.netbeans.modules.xml.text.syntax.SyntaxElement; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; -import org.netbeans.modules.xml.text.syntax.XMLTokenIDs; -import org.netbeans.modules.xml.text.syntax.dom.AttrImpl; -import org.netbeans.modules.xml.text.syntax.dom.CDATASectionImpl; -import org.netbeans.modules.xml.text.syntax.dom.CommentImpl; -import org.netbeans.modules.xml.text.syntax.dom.DocumentTypeImpl; -import org.netbeans.modules.xml.text.syntax.dom.EmptyTag; -import org.netbeans.modules.xml.text.syntax.dom.EndTag; -import org.netbeans.modules.xml.text.syntax.dom.ProcessingInstructionImpl; -import org.netbeans.modules.xml.text.syntax.dom.StartTag; -import org.netbeans.modules.xml.text.syntax.dom.Tag; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.openide.ErrorManager; +import static org.netbeans.modules.xml.text.structure.XMLConstants.*; +import org.w3c.dom.Attr; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; /** * @@ -96,169 +93,39 @@ if(debug) System.out.println("\n\n\n\n\n"); if(debug) DocumentModelUtils.dumpElementStructure(model.getRootElement()); + XMLSyntaxSupport sup = XMLSyntaxSupport.getSyntaxSupport(model.getDocument()); + if (sup == null) { + return; + } ArrayList regenerate = new ArrayList(); //used to store elements to be regenerated for(int i = 0; i < changes.length; i++) { DocumentChange dch = changes[i]; + int changeOffset = dch.getChangeStart().getOffset(); + Exception[] thrown = new Exception[1]; - int changeOffset = dch.getChangeStart().getOffset(); - int changeLength = dch.getChangeLength(); - - //find an element in which the change happened - DocumentElement leaf = model.getLeafElementForOffset(changeOffset); - DocumentElement toRegenerate = leaf; - - if(debug) System.out.println(""); - if(debug) System.out.println(dch); try { - if(debug) System.out.println("inserted text:'" + model.getDocument().getText(changeOffset, changeLength) + "'"); - }catch(BadLocationException e) { - ; - } - if(debug) System.out.println("leaf = " + leaf); - - //parse the document context - XMLSyntaxSupport sup = (XMLSyntaxSupport)((BaseDocument)model.getDocument()).getSyntaxSupport(); - - boolean textOnly = false; - boolean attribsOnly = false; - try { - //scan the inserted text - if it contains only text set textOnly flag - TokenItem ti = sup.getTokenChain(changeOffset, changeOffset + 1); - while(ti != null && ti.getOffset() < (changeOffset + changeLength)) { - if(ti.getTokenID() == XMLTokenIDs.TEXT - || ti.getTokenID() == XMLTokenIDs.DECLARATION - || ti.getTokenID() == XMLTokenIDs.BLOCK_COMMENT - || ti.getTokenID() == XMLTokenIDs.PI_CONTENT - || ti.getTokenID() == XMLTokenIDs.CDATA_SECTION) { - textOnly = true; - break; + sup.runWithSequence(changeOffset, + (TokenSequence s) -> { + try { + updateModelLocked(sup, regenerate, dtm, model, dch, s); + } catch (DocumentModelException | DocumentModelTransactionCancelledException ex) { + thrown[0] = ex; + } + return null; + } + ); + if (thrown[0] != null) { + if (thrown[0] instanceof DocumentModelException) { + throw (DocumentModelException)thrown[0]; } - if(ti.getTokenID() == XMLTokenIDs.ARGUMENT - || ti.getTokenID() == XMLTokenIDs.OPERATOR - || ti.getTokenID() == XMLTokenIDs.VALUE) { - attribsOnly = true; - break; - } - ti = ti.getNext(); - } - }catch(BadLocationException e) { - ErrorManager.getDefault().notify(ErrorManager.WARNING, e); - } - - if(textOnly && - ( leaf.getType().equals(XML_CONTENT) - || leaf.getType().equals(XML_DOCTYPE) - || leaf.getType().equals(XML_PI) - || leaf.getType().equals(XML_COMMENT) - || leaf.getType().equals(XML_CDATA))){ - //just a text written into a text element simply fire document element change event and do not regenerate anything - //add the element update request into transaction - if(debug) System.out.println("ONLY CONTENT UPDATE!!!"); - dtm.updateDocumentElementText(leaf); - - //do not scan the context tag if the change is only insert or remove of one character into a text (typing text perf. optimalization) - if(dch.getChangeLength() == 1) { - continue; - } - } - - if((attribsOnly || dch.getChangeType() == DocumentChange.REMOVE) - && (leaf.getType().equals(XML_TAG) - || leaf.getType().equals(XML_EMPTY_TAG))) { - if(debug) System.out.println("POSSIBLE ATTRIBS UPDATE!!!"); - //we need to parse the tag element attributes and set them according to the new values - try { - SyntaxElement sel = sup.getElementChain(leaf.getStartOffset() + 1); - if(sel instanceof Tag || sel instanceof EmptyTag) { - //test whether the attributes changed - Map newAttrs = createAttributesMap((Tag)sel); - AttributeSet existing = leaf.getAttributes(); - boolean update = false; - if(existing.getAttributeCount() == newAttrs.size()) { - Iterator itr = newAttrs.keySet().iterator(); - while (itr.hasNext()) { - String attrName = (String) itr.next(); - String attrValue = (String)newAttrs.get(attrName); - if(attrName != null && attrValue != null - && !existing.containsAttribute(attrName, attrValue)) { - update = true; - break; - } - - } - } else update = true; - - if(update) { - dtm.updateDocumentElementAttribs(leaf, newAttrs); - } - } - }catch(BadLocationException ble) { - ErrorManager.getDefault().notify(ErrorManager.WARNING, ble); - } - } - - //if one or more elements are deleted get correct paret to regenerate - if((leaf.getStartOffset() == leaf.getEndOffset()) - || (changeOffset == leaf.getStartOffset()) - || (changeOffset == leaf.getEndOffset())) - toRegenerate = leaf.getParentElement(); - else { - //user written a tag or something what is not a text - //we need to get the element's parent. Simple leaf.getParent() is not enought - //since when an element is deleted then a wrong parent can be choosen - if(leaf.getType().equals(XML_CONTENT)) { - do { - toRegenerate = toRegenerate.getParentElement(); - } while(toRegenerate != null && toRegenerate.getType().equals(XML_CONTENT)); - - if(toRegenerate == null) { - //no suitable parent found - the element is either a root or doesn't have any xml_tag ancestor => use root - toRegenerate = model.getRootElement(); + if (thrown[0] instanceof DocumentModelTransactionCancelledException) { + throw (DocumentModelTransactionCancelledException)thrown[0]; } } + } catch (BadLocationException ex) { } - - if(toRegenerate == null) toRegenerate = model.getRootElement(); //root element is empty - - //now regenerate all sub-elements inside parent of the affected element - - //check if the element is not a descendant a one of the elements - //which are going to be regenerated - Iterator itr = regenerate.iterator(); - boolean hasAncestor = false; - while(itr.hasNext()) { - DocumentElement de = (DocumentElement)itr.next(); - if(de.equals(toRegenerate) || model.isDescendantOf(de, toRegenerate)) { - hasAncestor = true; - break; - } - } - - if(!hasAncestor) { - //check whether the element is not an ancestor of one or more element - //which are going to be regenerated - ArrayList toRemove = new ArrayList(); - Iterator i2 = regenerate.iterator(); - while(i2.hasNext()) { - DocumentElement de = (DocumentElement)i2.next(); - if(model.isDescendantOf(toRegenerate, de)) toRemove.add(de); - } - - //now really remove the elements - regenerate.removeAll(toRemove); - - //add the element - it will be likely regenerated in next model update - regenerate.add(toRegenerate); - - //debug>>> - if(debug) System.out.println("==================================================================="); - if(debug) System.out.println("change happened in " + leaf); - if(debug) System.out.println("we will regenerate its parent " + toRegenerate); - //<< use root + toRegenerate = model.getRootElement(); + } + } + } + + if(toRegenerate == null) toRegenerate = model.getRootElement(); //root element is empty + + //now regenerate all sub-elements inside parent of the affected element + + //check if the element is not a descendant a one of the elements + //which are going to be regenerated + Iterator itr = regenerate.iterator(); + boolean hasAncestor = false; + while(itr.hasNext()) { + DocumentElement de = (DocumentElement)itr.next(); + if(de.equals(toRegenerate) || model.isDescendantOf(de, toRegenerate)) { + hasAncestor = true; + break; + } + } + + if(!hasAncestor) { + //check whether the element is not an ancestor of one or more element + //which are going to be regenerated + ArrayList toRemove = new ArrayList(); + Iterator i2 = regenerate.iterator(); + while(i2.hasNext()) { + DocumentElement de = (DocumentElement)i2.next(); + if(model.isDescendantOf(toRegenerate, de)) toRemove.add(de); + } + + //now really remove the elements + regenerate.removeAll(toRemove); + + //add the element - it will be likely regenerated in next model update + regenerate.add(toRegenerate); + + //debug>>> + if(debug) System.out.println("==================================================================="); + if(debug) System.out.println("change happened in " + leaf); + if(debug) System.out.println("we will regenerate its parent " + toRegenerate); + //<< elementsStack = new Stack<>(); //we need this to determine tags nesting //the syntax element is created for token on offset - 1 //so I need to add 1 to the startOffset @@ -294,7 +316,7 @@ //scan the document for syntax elements - from startOffset to endOffset while(sel != null && getSyntaxElementEndOffset(sel) <= endOffset) { - if(sel instanceof SyntaxElement.Error) { + if(sel.getType() == SyntaxElement.NODE_ERROR) { //add error element into the structure if(debug) System.out.println("Error found! => adding error element."); String errorText = doc.getText(sel.getElementOffset(), sel.getElementLength()); @@ -313,16 +335,16 @@ from, to)); } - if(sel instanceof StartTag) { + if(sup.isStartTag(sel)) { //test if there is already an existing documet element in the model - StartTag stag = (StartTag)sel; - DocumentElement tagDE = DocumentModelUtils.findElement(model, sel.getElementOffset(), stag.getTagName(), XML_TAG); + String nn = sel.getNode().getNodeName(); + DocumentElement tagDE = DocumentModelUtils.findElement(model, sel.getElementOffset(), nn, XML_TAG); //do not skip the 'de' element which is to be regenerated if(tagDE != null && !tagDE.equals(de)) { //test if the element has also correct end tag SyntaxElement endTagCheck = sup.getElementChain(Math.min(doc.getLength(), tagDE.getEndOffset() + 1)); - if(endTagCheck instanceof EndTag && ((EndTag)endTagCheck).getTagName().equals(stag.getTagName())) { + if(sup.isEndTag(endTagCheck) && endTagCheck.getNode().getNodeName().equals(nn)) { //there is an element - skip it - analyze an element after the end of the //existing element if(debug) System.out.println("found existing element " + tagDE + " => skipping"); @@ -336,13 +358,14 @@ //add the tag syntax element into stack elementsStack.push(sel); - } else if(sel instanceof EndTag) { + } else if (sup.isEndTag(sel)) { if(!elementsStack.isEmpty()) { - StartTag latest = (StartTag)elementsStack.peek(); - if(((EndTag)sel).getTagName().equals(latest.getTagName())) { + SyntaxElement latest = elementsStack.peek(); + String nn = latest.getNode().getNodeName(); + if((sel.getNode().getNodeName().equals(nn))) { //we have encountered a pair end tag to open tag on the peek of the stack - Map attribs = createAttributesMap(latest); - addedElements.add(dtm.addDocumentElement(latest.getTagName(), XML_TAG, attribs, + Map attribs = createAttributesMap(latest.getNode()); + addedElements.add(dtm.addDocumentElement(nn, XML_TAG, attribs, latest.getElementOffset(), getSyntaxElementEndOffset(sel))); //remove the open tag syntax element from the stack elementsStack.pop(); @@ -352,7 +375,7 @@ //I need to save the pop-ed elements for the case that there isn't //any matching start tag found - ArrayList savedElements = new ArrayList(); + ArrayList savedElements = new ArrayList<>(); //this semaphore is used behind the loop to detect whether a //matching start has been found boolean foundStartTag = false; @@ -361,15 +384,16 @@ SyntaxElement s = (SyntaxElement)elementsStack.pop(); savedElements.add(s); - Tag start = (Tag)s; - Tag end = (Tag)sel; + int soff = s.getElementOffset(); + String sn = s.getNode().getNodeName(); + String en = s.getNode().getNodeName(); - if(s instanceof StartTag && start.getTagName().equals(end.getTagName())) { + if(sup.isStartTag(s) && sn.equals(en)) { //found a matching start tag //XXX I am not sure whether this algorith is correct - Map attribs = createAttributesMap((StartTag)s); - addedElements.add(dtm.addDocumentElement(start.getTagName(), XML_TAG, attribs, - start.getElementOffset(), getSyntaxElementEndOffset(end))); + Map attribs = createAttributesMap(s.getNode()); + addedElements.add(dtm.addDocumentElement(sn, XML_TAG, attribs, + soff, getSyntaxElementEndOffset(sel))); foundStartTag = true; break; //break the while loop @@ -385,49 +409,57 @@ } } } - } else if(sel instanceof EmptyTag) { - Map attribs = createAttributesMap((Tag)sel); - addedElements.add(dtm.addDocumentElement(((EmptyTag)sel).getTagName(), XML_EMPTY_TAG, attribs, - sel.getElementOffset(), getSyntaxElementEndOffset(sel))); - } else if (sel instanceof CDATASectionImpl) { - //CDATA section - addedElements.add(dtm.addDocumentElement("cdata", XML_CDATA, Collections.EMPTY_MAP, - sel.getElementOffset(), getSyntaxElementEndOffset(sel))); - } else if (sel instanceof ProcessingInstructionImpl) { - //PI section - String nodeName = ((ProcessingInstructionImpl)sel).getNodeName(); - //if the nodename is not parsed, then the element is somehow broken => do not show it. - if(nodeName != null) { - addedElements.add(dtm.addDocumentElement(nodeName, XML_PI, Collections.EMPTY_MAP, - sel.getElementOffset(), getSyntaxElementEndOffset(sel))); - } - } else if (sel instanceof DocumentTypeImpl) { - //document type - String nodeName = ((DocumentTypeImpl)sel).getName(); - //if the nodename is not parsed, then the element is somehow broken => do not show it. - if(nodeName != null) { - addedElements.add(dtm.addDocumentElement(nodeName, XML_DOCTYPE, Collections.EMPTY_MAP, - sel.getElementOffset(), getSyntaxElementEndOffset(sel))); - } - } else if (sel instanceof CommentImpl) { - //comment element - //DO NOT CREATE ELEMENT FOR COMMENTS - addedElements.add(dtm.addDocumentElement("comment", XML_COMMENT, Collections.EMPTY_MAP, + } else if(sup.isEmptyTag(sel)) { + Map attribs = createAttributesMap(sel.getNode()); + addedElements.add(dtm.addDocumentElement(sel.getNode().getNodeName(), XML_EMPTY_TAG, attribs, sel.getElementOffset(), getSyntaxElementEndOffset(sel))); } else { - //everything else is content - int from = sel.getElementOffset(); - // because of changeset #1d6a31161c70, all elements report end at the last char, but that is not - // what is expected from the DocumentElement. - int to = getSyntaxElementEndOffset(sel) + 1; - if(from < to) { - //Do not allow empty elements to be added: - //Otherwise it causes problems in DocumentModel.ELEMENTS_COMPARATOR - //(idential elements are considered as unequal (the reason why this - //required is distinguishing elements after text deletion) and subsequently - //the empty elements are added and removed all over again after each model - //update which causes performance problems. - addedElements.add(dtm.addDocumentElement("...", XML_CONTENT, Collections.EMPTY_MAP, from, to)); + switch (sel.getType()) { + case Node.CDATA_SECTION_NODE: + addedElements.add(dtm.addDocumentElement("cdata", XML_CDATA, Collections.EMPTY_MAP, + sel.getElementOffset(), getSyntaxElementEndOffset(sel))); + break; + case Node.PROCESSING_INSTRUCTION_NODE: { + //PI section + String nodeName = ((ProcessingInstruction)sel.getNode()).getNodeName(); + //if the nodename is not parsed, then the element is somehow broken => do not show it. + if(nodeName != null) { + addedElements.add(dtm.addDocumentElement(nodeName, XML_PI, Collections.EMPTY_MAP, + sel.getElementOffset(), getSyntaxElementEndOffset(sel))); + } + break; + } + case Node.DOCUMENT_TYPE_NODE: { + //document type + String nodeName = ((DocumentType)sel.getNode()).getName(); + //if the nodename is not parsed, then the element is somehow broken => do not show it. + if(nodeName != null) { + addedElements.add(dtm.addDocumentElement(nodeName, XML_DOCTYPE, Collections.EMPTY_MAP, + sel.getElementOffset(), getSyntaxElementEndOffset(sel))); + } + break; + } + case Node.COMMENT_NODE: + //comment element + //DO NOT CREATE ELEMENT FOR COMMENTS + addedElements.add(dtm.addDocumentElement("comment", XML_COMMENT, Collections.EMPTY_MAP, + sel.getElementOffset(), getSyntaxElementEndOffset(sel))); + break; + default: + //everything else is content + int from = sel.getElementOffset(); + // because of changeset #1d6a31161c70, all elements report end at the last char, but that is not + // what is expected from the DocumentElement. + int to = getSyntaxElementEndOffset(sel) + 1; + if(from < to) { + //Do not allow empty elements to be added: + //Otherwise it causes problems in DocumentModel.ELEMENTS_COMPARATOR + //(idential elements are considered as unequal (the reason why this + //required is distinguishing elements after text deletion) and subsequently + //the empty elements are added and removed all over again after each model + //update which causes performance problems. + addedElements.add(dtm.addDocumentElement("...", XML_CONTENT, Collections.EMPTY_MAP, from, to)); + } } } //find next syntax element @@ -499,29 +531,19 @@ return sel.getElementOffset() + sel.getElementLength() -1; } - private Map createAttributesMap(Tag tag) { + private Map createAttributesMap(Node tag) { if(tag.getAttributes().getLength() == 0) { return Collections.EMPTY_MAP; } else { HashMap map = new LinkedHashMap(tag.getAttributes().getLength()); for(int i = 0; i < tag.getAttributes().getLength(); i++) { - AttrImpl attr = (AttrImpl)tag.getAttributes().item(i); + Attr attr = (Attr)tag.getAttributes().item(i); map.put(attr.getName(), attr.getValue()); } return map; } } - public static final String XML_TAG = "tag"; - public static final String XML_EMPTY_TAG = "empty_tag"; - public static final String XML_CONTENT = "content"; - public static final String XML_PI = "pi"; - public static final String XML_CDATA = "cdata"; - public static final String XML_DOCTYPE = "doctype"; - public static final String XML_COMMENT = "comment"; - - public static final String XML_ERROR = "error"; - private static final boolean debug = Boolean.getBoolean("org.netbeans.modules.xml.text.structure.debug"); private static final boolean measure = Boolean.getBoolean("org.netbeans.modules.xml.text.structure.measure"); diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDKit.java b/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDKit.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDKit.java +++ b/xml.text/src/org/netbeans/modules/xml/text/syntax/DTDKit.java @@ -44,7 +44,10 @@ package org.netbeans.modules.xml.text.syntax; import javax.swing.text.Document; +import org.netbeans.api.editor.mimelookup.MimeLookup; +import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.editor.Syntax; +import org.netbeans.modules.xml.text.syntax.bridge.LegacySyntaxBridge; import org.netbeans.modules.xml.text.syntax.javacc.lib.*; import org.netbeans.modules.xml.text.syntax.javacc.*; @@ -70,19 +73,8 @@ */ public static final String MIME_TYPE = "application/xml-dtd"; // NOI18N - /** Create new instance of syntax coloring parser */ - @Override - public Syntax createSyntax(Document doc) { - return new JJEditorSyntax( - new DTDSyntaxTokenManager(null).new Bridge(), - new DTDSyntaxTokenMapper(), - DTDTokenContext.contextPath - ); - } - @Override public String getContentType() { return MIME_TYPE; } - } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/ENTKit.java b/xml.text/src/org/netbeans/modules/xml/text/syntax/ENTKit.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/ENTKit.java +++ b/xml.text/src/org/netbeans/modules/xml/text/syntax/ENTKit.java @@ -42,11 +42,6 @@ package org.netbeans.modules.xml.text.syntax; -import javax.swing.text.Document; -import org.netbeans.editor.BaseDocument; -import org.netbeans.editor.Syntax; -import org.netbeans.editor.SyntaxSupport; - /** * * @author samaresh @@ -61,21 +56,8 @@ */ public static final String MIME_TYPE = "text/xml-external-parsed-entity"; // NOI18N - /** Create new instance of syntax coloring parser */ - @Override - public Syntax createSyntax(Document doc) { - return new XMLDefaultSyntax(); - } - @Override public String getContentType() { return MIME_TYPE; } - - /** Create syntax support */ - @Override - public SyntaxSupport createSyntaxSupport(BaseDocument doc) { - return new XMLSyntaxSupport(doc); - } - } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/UniKit.java b/xml.text/src/org/netbeans/modules/xml/text/syntax/UniKit.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/UniKit.java +++ b/xml.text/src/org/netbeans/modules/xml/text/syntax/UniKit.java @@ -47,9 +47,14 @@ import javax.swing.text.Document; import javax.swing.text.BadLocationException; +import org.netbeans.api.editor.mimelookup.MimeLookup; +import org.netbeans.editor.BaseDocument; +import org.netbeans.editor.Syntax; +import org.netbeans.editor.SyntaxSupport; import org.netbeans.modules.editor.NbEditorKit; import org.netbeans.modules.xml.api.EncodingUtil; +import org.netbeans.modules.xml.text.syntax.bridge.LegacySyntaxBridge; /** * Editor kit implementation for xml content type. @@ -112,4 +117,25 @@ super.write(out, doc, pos, len); } + @Override + public Syntax createSyntax(Document doc) { + Syntax syn = null; + LegacySyntaxBridge bridge = MimeLookup.getLookup(getContentType()).lookup(LegacySyntaxBridge.class); + if (bridge != null) { + syn = bridge.createSyntax(this, doc, getContentType()); + } + return syn != null ? syn : super.createSyntax(doc); + } + + /** Create syntax support */ + @Override + public SyntaxSupport createSyntaxSupport(BaseDocument doc) { + SyntaxSupport syn = null; + LegacySyntaxBridge bridge = MimeLookup.getLookup(getContentType()).lookup(LegacySyntaxBridge.class); + if (bridge != null) { + syn = bridge.createSyntaxSupport(this, doc, getContentType()); + } + return syn != null ? syn : super.createSyntaxSupport(doc); + } + } diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLKit.java b/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLKit.java --- a/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLKit.java +++ b/xml.text/src/org/netbeans/modules/xml/text/syntax/XMLKit.java @@ -54,6 +54,7 @@ import javax.swing.text.JTextComponent; import javax.swing.text.BadLocationException; import javax.swing.*; +import org.netbeans.api.editor.mimelookup.MimeLookup; import org.netbeans.api.lexer.Language; import org.netbeans.api.xml.lexer.XMLTokenId; import org.openide.awt.StatusDisplayer; @@ -65,6 +66,8 @@ import org.netbeans.modules.xml.text.XmlCommentHandler; import org.netbeans.modules.xml.text.completion.NodeSelector; +import static org.netbeans.modules.xml.text.syntax.DTDKit.MIME_TYPE; +import org.netbeans.modules.xml.text.syntax.bridge.LegacySyntaxBridge; /** @@ -106,7 +109,12 @@ /** Create new instance of syntax coloring parser */ @Override public Syntax createSyntax(Document doc) { - return new XMLDefaultSyntax(); + Syntax syn = null; + LegacySyntaxBridge bridge = MimeLookup.getLookup(MIME_TYPE).lookup(LegacySyntaxBridge.class); + if (bridge != null) { + syn = bridge.createSyntax(this, doc, MIME_TYPE); + } + return syn != null ? syn : super.createSyntax(doc); } @Override @@ -120,11 +128,15 @@ } } - /** Create syntax support */ @Override public SyntaxSupport createSyntaxSupport(BaseDocument doc) { - return new XMLSyntaxSupport(doc); + SyntaxSupport syn = null; + LegacySyntaxBridge bridge = MimeLookup.getLookup(MIME_TYPE).lookup(LegacySyntaxBridge.class); + if (bridge != null) { + syn = bridge.createSyntaxSupport(this, doc, MIME_TYPE); + } + return syn != null ? syn : super.createSyntaxSupport(doc); } @Override diff --git a/xml.text/src/org/netbeans/modules/xml/text/syntax/bridge/LegacySyntaxBridge.java b/xml.text/src/org/netbeans/modules/xml/text/syntax/bridge/LegacySyntaxBridge.java new file mode 100644 --- /dev/null +++ b/xml.text/src/org/netbeans/modules/xml/text/syntax/bridge/LegacySyntaxBridge.java @@ -0,0 +1,59 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2016 Sun Microsystems, Inc. + */ +package org.netbeans.modules.xml.text.syntax.bridge; + +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import org.netbeans.editor.Syntax; +import org.netbeans.editor.SyntaxSupport; + +/** + * Transitional interface, which keeps old Syntax-related classes in a + * obsolete/deprecated module. Not intended to be implemented by regular clients. + * Implementations should be registered in MIME Lookup for the particular MIME type. + * + * @author sdedic + */ +public interface LegacySyntaxBridge { + public Syntax createSyntax(EditorKit host, Document doc, String mimeType); + public SyntaxSupport createSyntaxSupport(EditorKit host, Document doc, String mimeType); +} diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java b/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java +++ b/xml.text/test/unit/src/org/netbeans/modules/xml/text/AbstractTestCase.java @@ -52,13 +52,13 @@ import org.netbeans.api.lexer.Language; import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.BaseDocument; -import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import org.netbeans.modules.xml.xam.ModelSource; import org.netbeans.modules.xml.xdm.XDMModel; import org.netbeans.modules.xml.xdm.diff.DefaultElementIdentity; import org.netbeans.modules.xml.xdm.diff.DiffFinder; import org.netbeans.modules.xml.xdm.diff.Difference; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; @@ -67,7 +67,7 @@ * Various tests include, sanity, regression, performance etc. * @author Samaresh (samaresh.panda@sun.com) */ -public class AbstractTestCase extends TestCase { +public class AbstractTestCase extends NbTestCase { public AbstractTestCase(String testName) { super(testName); @@ -131,7 +131,7 @@ BaseDocument doc = getResourceAsDocument(path); //must set the language inside unit tests doc.putProperty(Language.class, XMLTokenId.language()); - return ((XMLSyntaxSupport)doc.getSyntaxSupport()); + return XMLSyntaxSupport.getSyntaxSupport(doc); } /** diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupportTest.java b/xml.text/test/unit/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupportTest.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupportTest.java +++ b/xml.text/test/unit/src/org/netbeans/modules/xml/text/dom/XMLSyntaxSupportTest.java @@ -42,11 +42,13 @@ package org.netbeans.modules.xml.text.dom; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; import junit.framework.Test; import junit.framework.TestSuite; import org.netbeans.api.lexer.Token; import org.netbeans.editor.BaseDocument; import org.netbeans.modules.xml.text.AbstractTestCase; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; /** * diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatterTest.java b/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatterTest.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatterTest.java +++ b/xml.text/test/unit/src/org/netbeans/modules/xml/text/indent/XMLLexerFormatterTest.java @@ -43,6 +43,7 @@ import org.netbeans.modules.xml.text.AbstractTestCase; import junit.framework.*; +import org.netbeans.api.editor.document.LineDocument; import org.netbeans.editor.BaseDocument; /** @@ -81,23 +82,23 @@ * with a document that represents expected outcome. */ public void testFormat() throws Exception { - BaseDocument inputDoc = getDocument("indent/input.xml"); + LineDocument inputDoc = getDocument("indent/input.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatSubsection() throws Exception { BaseDocument inputDoc = getDocument("indent/input_sub.xml"); //format a subsection of the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 72, 97); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 72, 97); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_sub.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_sub.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } // #139160 @@ -105,10 +106,10 @@ BaseDocument inputDoc = getDocument("indent/input2.xsd"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output2.xsd"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output2.xsd"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatPerformance() throws Exception { @@ -134,20 +135,20 @@ BaseDocument inputDoc = getDocument("indent/input_sub1.xml"); //format a subsection of the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 46, 74); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 46, 74); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_sub1.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_sub1.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatSubsection2() throws Exception { BaseDocument inputDoc = getDocument("indent/input_sub2.xml"); //format a subsection of the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 63, 80); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 63, 80); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_sub2.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_sub2.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } // #170343 @@ -155,10 +156,10 @@ BaseDocument inputDoc = getDocument("indent/input_preserve.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_preserve.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_preserve.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } // #170343 @@ -166,10 +167,10 @@ BaseDocument inputDoc = getDocument("indent/input_withpreserve.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_withpreserve.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_withpreserve.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } // #170343 @@ -178,10 +179,10 @@ //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); System.out.println("SECTION:" + inputDoc.getText(91, 87)); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 91, 91 + 87); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 91, 91 + 87); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_preserve.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_preserve.xml"); + assertTrue(compare(formattedDoc, outputDoc)); } @@ -189,30 +190,30 @@ BaseDocument inputDoc = getDocument("indent/input_contentIndent.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_contentIndent.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_contentIndent.xml"); + assertTrue(compare(formattedDoc, outputDoc)); } public void testFormat_AttrsIndent() throws Exception { BaseDocument inputDoc = getDocument("indent/input_attrsIndent.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_attrsIndent.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_attrsIndent.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormat_ProcessingIndent() throws Exception { BaseDocument inputDoc = getDocument("indent/input_processingXml.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_processingXml.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_processingXml.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } @@ -220,49 +221,49 @@ BaseDocument inputDoc = getDocument("indent/input_nestedSame.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_nestedSame.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_nestedSame.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatWithCdataContent217342() throws Exception { BaseDocument inputDoc = getDocument("indent/input_cdataContent.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_cdataContent.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_cdataContent.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatBreaksMixedContent216986() throws Exception { BaseDocument inputDoc = getDocument("indent/input_breaksMixedContent.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_breaksMixedContent.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_breaksMixedContent.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatNewlinesInTags217995() throws Exception { BaseDocument inputDoc = getDocument("indent/input_newlineInTags.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_newlineInTags.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_newlineInTags.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } public void testFormatTagAtLineStartAfterContent238985() throws Exception { BaseDocument inputDoc = getDocument("indent/input_tagAtStatOfLine.xml"); //format the inputDoc XMLLexerFormatter formatter = new XMLLexerFormatter(null); - BaseDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); + LineDocument formattedDoc = formatter.doReformat(inputDoc, 0, inputDoc.getLength()); System.out.println(formattedDoc.getText(0, formattedDoc.getLength())); - BaseDocument outputDoc = getDocument("indent/output_tagAtStatOfLine.xml"); - assert (compare(formattedDoc, outputDoc)); + LineDocument outputDoc = getDocument("indent/output_tagAtStatOfLine.xml"); + assertTrue (compare(formattedDoc, outputDoc)); } } diff --git a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java b/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java --- a/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java +++ b/xml.text/test/unit/src/org/netbeans/modules/xml/text/syntax/XMLSyntaxSupportTest.java @@ -44,8 +44,12 @@ import junit.framework.Test; import junit.framework.TestSuite; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; import org.netbeans.editor.TokenItem; import org.netbeans.modules.xml.text.AbstractTestCase; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; /** * @@ -85,11 +89,11 @@ public void testTokens() throws Exception { XMLSyntaxSupport support = getSyntaxSupport("syntax/test.xml"); - TokenItem token = support.getPreviousToken(30); - System.out.println("Token: " + token.getTokenID().getName() + " Text: " + token.getImage()); + Token token = support.getPreviousToken(30); + System.out.println("Token: " + token.id().name() + " Text: " + token.text()); token = support.getPreviousToken(31); - System.out.println("Token: " + token.getTokenID().getName() + " Text: " + token.getImage()); + System.out.println("Token: " + token.id().name() + " Text: " + token.text()); token = support.getPreviousToken(32); - System.out.println("Token: " + token.getTokenID().getName() + " Text: " + token.getImage()); + System.out.println("Token: " + token.id().name() + " Text: " + token.text()); } } diff --git a/xml/manifest.mf b/xml/manifest.mf --- a/xml/manifest.mf +++ b/xml/manifest.mf @@ -4,4 +4,4 @@ OpenIDE-Module-Install: org/netbeans/modules/xml/CoreModuleInstall.class OpenIDE-Module-Layer: org/netbeans/modules/xml/resources/mf-layer.xml AutoUpdate-Show-In-Client: false -OpenIDE-Module-Specification-Version: 1.32 +OpenIDE-Module-Specification-Version: 1.33 diff --git a/xml/nbproject/project.xml b/xml/nbproject/project.xml --- a/xml/nbproject/project.xml +++ b/xml/nbproject/project.xml @@ -170,7 +170,7 @@ 2 - 1.16 + 1.60 diff --git a/xsl/manifest.mf b/xsl/manifest.mf --- a/xsl/manifest.mf +++ b/xsl/manifest.mf @@ -4,4 +4,4 @@ OpenIDE-Module-Layer: org/netbeans/modules/xsl/resources/mf-layer.xml OpenIDE-Module-Requires: org.openide.util.HttpServer$Impl AutoUpdate-Show-In-Client: false -OpenIDE-Module-Specification-Version: 1.44 +OpenIDE-Module-Specification-Version: 1.45 diff --git a/xsl/nbproject/project.xml b/xsl/nbproject/project.xml --- a/xsl/nbproject/project.xml +++ b/xsl/nbproject/project.xml @@ -142,7 +142,7 @@ 2 - 1.16 + 1.60