Author: vrubezhny
Date: 2009-07-30 16:07:37 -0400 (Thu, 30 Jul 2009)
New Revision: 16917
Modified:
trunk/common/plugins/org.jboss.tools.common/src/org/jboss/tools/common/text/TextProposal.java
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/AbstractXMLContentAssistProcessor.java
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/FaceletPageContectAssistProcessor.java
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/JspContentAssistProcessor.java
Log:
JBIDE-4687: Wrong CA when there is incomplete tag (a tag with no closing
'>'-char)
Issue is fixed
Modified:
trunk/common/plugins/org.jboss.tools.common/src/org/jboss/tools/common/text/TextProposal.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common/src/org/jboss/tools/common/text/TextProposal.java 2009-07-30
20:06:55 UTC (rev 16916)
+++
trunk/common/plugins/org.jboss.tools.common/src/org/jboss/tools/common/text/TextProposal.java 2009-07-30
20:07:37 UTC (rev 16917)
@@ -31,6 +31,7 @@
public static final int R_XML_ATTRIBUTE_NAME = 910;
public static final int R_TAG_INSERTION = 500;
public static final int R_XML_ATTRIBUTE_VALUE_TEMPLATE = 91;
+ public static final int R_CLOSE_TAG = 1550;
private static final long serialVersionUID = 3257007635692926512L;
Modified:
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/AbstractXMLContentAssistProcessor.java
===================================================================
---
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/AbstractXMLContentAssistProcessor.java 2009-07-30
20:06:55 UTC (rev 16916)
+++
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/AbstractXMLContentAssistProcessor.java 2009-07-30
20:07:37 UTC (rev 16917)
@@ -23,18 +23,29 @@
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils;
+import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMText;
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
+import org.eclipse.wst.xml.ui.internal.XMLUIMessages;
import org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor;
import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
+import org.eclipse.wst.xml.ui.internal.contentassist.XMLRelevanceConstants;
+import org.eclipse.wst.xml.ui.internal.editor.CMImageUtil;
+import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper;
+import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages;
import org.jboss.tools.common.el.core.model.ELInstance;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.model.ELModel;
@@ -44,6 +55,7 @@
import org.jboss.tools.common.el.core.resolver.ELContext;
import org.jboss.tools.common.el.core.resolver.ELResolver;
import org.jboss.tools.common.el.core.resolver.ELResolverFactoryManager;
+import org.jboss.tools.common.text.TextProposal;
import org.jboss.tools.jst.web.kb.KbQuery;
import org.jboss.tools.jst.web.kb.KbQuery.Type;
import org.w3c.dom.Attr;
@@ -77,7 +89,150 @@
return super.computeCompletionProposals(viewer, offset);
}
+
/**
+ * The reason of overriding is that the method returns wrong region in case of
incomplete tag (a tag with no '>'-closing char)
+ * In this case we have to return that previous incomplete tag instead of the current
tag)
+ */
+ public IStructuredDocumentRegion getStructuredDocumentRegion(int pos) {
+ IStructuredDocumentRegion sdRegion = null;
+ if (fDocument == null)
+ return null;
+
+ int lastOffset = pos;
+ IStructuredDocument doc = (IStructuredDocument) fDocument;
+
+ do {
+ sdRegion = doc.getRegionAtCharacterOffset(lastOffset);
+ if (sdRegion != null) {
+ ITextRegion region = sdRegion.getRegionAtCharacterOffset(lastOffset);
+ if (region != null && region.getType() == DOMRegionContext.XML_TAG_OPEN
&&
+ sdRegion.getStartOffset(region) == lastOffset) {
+ // The offset is at the beginning of the region
+ if ((sdRegion.getStartOffset(region) == sdRegion.getStartOffset()) &&
(sdRegion.getPrevious() != null) && (!sdRegion.getPrevious().isEnded())) {
+ // Is the region also the start of the node? If so, the
+ // previous IStructuredDocumentRegion is
+ // where to look for a useful region.
+// sdRegion = sdRegion.getPrevious();
+ sdRegion = null;
+ }
+ else {
+ // Is there no separating whitespace from the previous region?
+ // If not,
+ // then that region is the important one
+ ITextRegion previousRegion = sdRegion.getRegionAtCharacterOffset(lastOffset - 1);
+ if ((previousRegion != null) && (previousRegion != region) &&
(previousRegion.getTextLength() == previousRegion.getLength())) {
+// sdRegion = sdRegion.getPrevious();
+ sdRegion = null;
+ }
+ }
+ }
+ }
+ lastOffset--;
+ } while (sdRegion == null && lastOffset >= 0);
+ return sdRegion;
+ }
+
+ /**
+ * The reason of overriding is that the method returns wrong region in case of
incomplete tag (a tag with no '>'-closing char)
+ * In this case we have to return that previous incomplete tag instead of the current
tag)
+ */
+ protected ITextRegion getCompletionRegion(int documentPosition, Node domnode) {
+ if (domnode == null) {
+ return null;
+ }
+ // Get the original WTP Structured Document Region
+ IStructuredDocumentRegion sdNormalRegion =
super.getStructuredDocumentRegion(documentPosition);
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(documentPosition);
+
+ // If original and fixed regions are different we have to replace domnode with its
parent node
+ if (sdFixedRegion != null && !sdFixedRegion.equals(sdNormalRegion)) {
+ Node prevnode = domnode.getParentNode();
+ if (prevnode != null) {
+ domnode = prevnode;
+ }
+ }
+ return super.getCompletionRegion(documentPosition, domnode);
+ }
+ /*
+ * (non-Javadoc)
+ * @see
org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor#computeTagNameProposals(int,
java.lang.String, org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion,
org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode,
org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode)
+ */
+ protected ContentAssistRequest computeTagNameProposals(int documentPosition, String
matchString, ITextRegion completionRegion, IDOMNode nodeAtOffset, IDOMNode node) {
+ ContentAssistRequest contentAssistRequest = null;
+ IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition);
+
+ if (sdRegion != nodeAtOffset.getFirstStructuredDocumentRegion()) {
+ // completing the *first* tag in "<tagname1 |<tagname2"
+ IDOMNode actualNode = (IDOMNode)
node.getModel().getIndexedRegion(sdRegion.getStartOffset(completionRegion));
+ if (actualNode != null) {
+ if (actualNode.getFirstStructuredDocumentRegion() == sdRegion) {
+ // start tag
+ if ((documentPosition >= sdRegion.getStartOffset(completionRegion) +
completionRegion.getLength()) &&
+ (documentPosition > sdRegion.getStartOffset(completionRegion) +
completionRegion.getTextLength())){
+ // it's attributes
+ contentAssistRequest = newContentAssistRequest(actualNode, actualNode, sdRegion,
completionRegion, documentPosition - matchString.length(), matchString.length(),
matchString);
+ if
(node.getStructuredDocument().getRegionAtCharacterOffset(sdRegion.getStartOffset(completionRegion)
- 1).getRegionAtCharacterOffset(sdRegion.getStartOffset(completionRegion) - 1).getType()
== DOMRegionContext.XML_TAG_OPEN) {
+ addAttributeNameProposals(contentAssistRequest);
+ }
+ addTagCloseProposals(contentAssistRequest);
+ }
+ else {
+ // it's name
+ contentAssistRequest = newContentAssistRequest(actualNode,
actualNode.getParentNode(), sdRegion, completionRegion, documentPosition -
matchString.length(), matchString.length(), matchString);
+ addTagNameProposals(contentAssistRequest,
getElementPositionForModelQuery(actualNode));
+ }
+ }
+ else {
+ if (documentPosition >= sdRegion.getStartOffset(completionRegion) +
completionRegion.getLength()) {
+ // insert name
+ contentAssistRequest = newContentAssistRequest(actualNode,
actualNode.getParentNode(), sdRegion, completionRegion, documentPosition, 0,
matchString);
+ }
+ else {
+ // replace name
+ contentAssistRequest = newContentAssistRequest(actualNode,
actualNode.getParentNode(), sdRegion, completionRegion,
sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(),
matchString);
+ }
+ addEndTagNameProposals(contentAssistRequest);
+ }
+ }
+ }
+ else {
+ if (documentPosition > sdRegion.getStartOffset(completionRegion) +
completionRegion.getTextLength()) {
+ // unclosed tag with only a name; should prompt for attributes
+ // and a close instead
+ contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion,
completionRegion, documentPosition - matchString.length(), matchString.length(),
matchString);
+ addAttributeNameProposals(contentAssistRequest);
+ addTagCloseProposals(contentAssistRequest);
+ }
+ else {
+ if (sdRegion.getRegions().get(0).getType() != DOMRegionContext.XML_END_TAG_OPEN) {
+ int replaceLength = documentPosition - sdRegion.getStartOffset(completionRegion);
+ contentAssistRequest = newContentAssistRequest(node, node.getParentNode(), sdRegion,
completionRegion, sdRegion.getStartOffset(completionRegion), replaceLength, matchString);
+ addTagNameProposals(contentAssistRequest,
getElementPositionForModelQuery(nodeAtOffset));
+ }
+ else {
+ IDOMNode actualNode = (IDOMNode)
node.getModel().getIndexedRegion(documentPosition);
+ if (actualNode != null) {
+ if (documentPosition >= sdRegion.getStartOffset(completionRegion) +
completionRegion.getTextLength()) {
+ contentAssistRequest = newContentAssistRequest(actualNode,
actualNode.getParentNode(), sdRegion, completionRegion, documentPosition, 0,
matchString);
+ }
+ else {
+ contentAssistRequest = newContentAssistRequest(actualNode,
actualNode.getParentNode(), sdRegion, completionRegion,
sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(),
matchString);
+ }
+ addEndTagNameProposals(contentAssistRequest);
+ }
+ }
+ }
+ }
+ return contentAssistRequest;
+ }
+
+ private int getElementPositionForModelQuery(Node child) {
+ return getElementPosition(child);
+ // return -1;
+ }
+ /**
* Helper method to reuse functionality for getting context when no proposals are
needed.
* @param viewer
* @param offset
@@ -270,8 +425,65 @@
/*
* Calculates and adds the tag close proposals to the Content Assist Request object
+ *
*/
protected void addTagCloseProposals(ContentAssistRequest contentAssistRequest) {
+ IDOMNode node = (IDOMNode) contentAssistRequest.getParent();
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ int contentType = CMElementDeclaration.ANY;
+ // if it's XML and content doesn't HAVE to be element, add "/>"
+ // proposal.
+ boolean endWithSlashBracket = (getXML(node) && (contentType !=
CMElementDeclaration.ELEMENT));
+
+ Image image =
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC);
+
+ // is the start tag ended properly?
+ if ((contentAssistRequest.getDocumentRegion() ==
node.getFirstStructuredDocumentRegion()) &&
!(node.getFirstStructuredDocumentRegion()).isEnded()) {
+ setErrorMessage(null);
+ // prompt with a close for the start tag
+ AutoContentAssistantProposal proposal = new AutoContentAssistantProposal(true,
">", //$NON-NLS-1$
+ getOffset(),
+ 0, 2, image, NLS.bind(XMLUIMessages.Close_with__, (new Object[]{"
'>'"})), //$NON-NLS-1$
+ null, null, TextProposal.R_CLOSE_TAG);
+ contentAssistRequest.addProposal(proposal);
+
+ // prompt with the closer for the start tag and an end tag
+ // if one is not present
+ if (node.getEndStructuredDocumentRegion() == null) {
+ // make sure tag name is actually what it thinks it
+ // is...(eg. <%@ vs. <jsp:directive)
+ IStructuredDocumentRegion sdr = contentAssistRequest.getDocumentRegion();
+ String openingTagText = (sdr != null) ? sdr.getFullText() : "";
//$NON-NLS-1$
+ if ((openingTagText != null) && (openingTagText.indexOf(node.getNodeName())
!= -1)) {
+ proposal = new AutoContentAssistantProposal(true, "></" +
node.getNodeName() + ">", //$NON-NLS-2$//$NON-NLS-1$
+ getOffset(),
+ 0, 1, image, NLS.bind(XMLUIMessages.Close_with____, (new
Object[]{node.getNodeName()})), null, null, TextProposal.R_CLOSE_TAG);
+ contentAssistRequest.addProposal(proposal);
+ }
+ }
+ // prompt with slash bracket "/>" incase if it's a self
+ // ending tag
+ if (endWithSlashBracket) {
+ proposal = new AutoContentAssistantProposal(true, "/>", //$NON-NLS-1$
+ getOffset(),
+ 0, 1, image, NLS.bind(XMLUIMessages.Close_with__, (new Object[]{"
\"/>\""})), //$NON-NLS-1$
+ null, null, TextProposal.R_CLOSE_TAG + 1); // +1 to bring to top of list
+ contentAssistRequest.addProposal(proposal);
+ }
+ }
+ else if ((contentAssistRequest.getDocumentRegion() ==
node.getLastStructuredDocumentRegion()) &&
!node.getLastStructuredDocumentRegion().isEnded()) {
+ setErrorMessage(null);
+ // prompt with a closing end character for the end tag
+ AutoContentAssistantProposal proposal = new AutoContentAssistantProposal(true,
">", //$NON-NLS-1$
+ getOffset(),
+ 0, 1, image, NLS.bind(XMLUIMessages.Close_with__, (new Object[]{"
'>'"})), //$NON-NLS-1$
+ null, null, TextProposal.R_CLOSE_TAG);
+ contentAssistRequest.addProposal(proposal);
+ }
+ }
+ else if (node.getNodeType() == Node.DOCUMENT_NODE) {
+ setErrorMessage(UNKNOWN_CONTEXT);
+ }
}
/*
@@ -453,7 +665,12 @@
if (xmlDocument == null)
return EMPTY_TAGS;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return EMPTY_TAGS;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
if (n == null)
return EMPTY_TAGS;
@@ -507,7 +724,12 @@
if (xmlDocument == null)
return null;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return null;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
if (n == null)
return null;
@@ -556,7 +778,12 @@
if (xmlDocument == null)
return null;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return null;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
if (n == null)
return null;
@@ -673,7 +900,12 @@
if (xmlDocument == null)
return null;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return null;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
if (n == null)
return null;
Modified:
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/FaceletPageContectAssistProcessor.java
===================================================================
---
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/FaceletPageContectAssistProcessor.java 2009-07-30
20:06:55 UTC (rev 16916)
+++
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/FaceletPageContectAssistProcessor.java 2009-07-30
20:07:37 UTC (rev 16917)
@@ -19,6 +19,7 @@
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
@@ -95,7 +96,12 @@
if (xmlDocument == null)
return;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
while (n != null) {
if (!(n instanceof Element)) {
if (n instanceof Attr) {
Modified:
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/JspContentAssistProcessor.java
===================================================================
---
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/JspContentAssistProcessor.java 2009-07-30
20:06:55 UTC (rev 16916)
+++
trunk/jst/plugins/org.jboss.tools.jst.jsp/src/org/jboss/tools/jst/jsp/contentassist/JspContentAssistProcessor.java 2009-07-30
20:07:37 UTC (rev 16917)
@@ -24,11 +24,11 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.xml.core.internal.document.NodeContainer;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
-import org.eclipse.wst.xml.ui.internal.editor.CMImageUtil;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages;
import org.jboss.tools.common.el.core.resolver.ELContext;
@@ -145,7 +145,7 @@
* @param context The context object instance
* @return
*/
- public ITagLibrary[] getTagLibraries(IPageContext context) {
+ protected ITagLibrary[] getTagLibraries(IPageContext context) {
Map<String, INameSpace> nameSpaces = context.getNameSpaces(getOffset());
if (nameSpaces == null || nameSpaces.isEmpty())
return EMPTY_LIBRARIES;
@@ -288,10 +288,15 @@
if (xmlDocument == null)
return false;
- Node n = findNodeForOffset(xmlDocument, getOffset());
+ // Get Fixed Structured Document Region
+ IStructuredDocumentRegion sdFixedRegion =
this.getStructuredDocumentRegion(getOffset());
+ if (sdFixedRegion == null)
+ return false;
+
+ Node n = findNodeForOffset(xmlDocument, sdFixedRegion.getStartOffset());
if (n == null)
return false;
-
+
// Find the first parent tag
if (!(n instanceof Element)) {
if (n instanceof Attr) {
@@ -362,7 +367,7 @@
if (image == null) {
image =
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC);
}
- String displayString = closingTag;
+ String displayString = closingTag; //$NON-NLS-1$
IContextInformation contextInformation = null;
String additionalProposalInfo = textProposal.getContextInfo();
int relevance = textProposal.getRelevance();
@@ -427,7 +432,7 @@
image =
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC);
}
- String displayString = closingTag;
+ String displayString = closingTag; //$NON-NLS-1$
IContextInformation contextInformation = null;
String additionalProposalInfo = textProposal.getContextInfo();
int relevance = textProposal.getRelevance();