[264246] [content assist] Use Linked Positions for cursor positioning in applied content assist proposals
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIMessages.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIMessages.java
index aae9149..3b5034e 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIMessages.java
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2011 IBM Corporation and others.
+ * Copyright (c) 2005, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -118,6 +118,7 @@
public static String JSPFContentSettingsPropertyPage_4;
public static String ProjectJSPFContentSettingsPropertyPage_0;
public static String TagPropertyPage_desc;
+ public static String Template_Taglib_URI;
public static String Title_InvalidValue;
public static String Message_InvalidValue;
public static String SyntaxColoringPage_0;
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIPluginResources.properties b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIPluginResources.properties
index 30a19cf..23c103c 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIPluginResources.properties
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/JSPUIPluginResources.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2004, 2011 IBM Corporation and others.
+# Copyright (c) 2004, 2012 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -168,6 +168,7 @@
CustomTagHyperlink_hyperlinkText=Open Declaration
TLDContentOutlineConfiguration_0=Show Content Values
TagPropertyPage_desc=Specify the surrounding language used in this tag file:
+Template_Taglib_URI=Tag Library URI
JSPFilesPreferencePage_Search_group=Search
JSPFilesPreferencePage_Supply_JSP_search_to_Java_search=&Include JSP matches in Java searches
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/LibraryTagsCompletionProposalComputer.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/LibraryTagsCompletionProposalComputer.java
index 99abe9b..3b97e3e 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/LibraryTagsCompletionProposalComputer.java
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/LibraryTagsCompletionProposalComputer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,6 +22,8 @@
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.TLDCMDocumentManager;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDElementDeclaration;
import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
+import org.eclipse.jst.jsp.core.internal.modelquery.JSPModelQueryExtension;
+import org.eclipse.jst.jsp.core.internal.modelquery.TaglibModelQueryExtension;
import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace;
import org.eclipse.jst.jsp.core.internal.provisional.JSP20Namespace;
import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP;
@@ -51,6 +53,7 @@
import org.eclipse.wst.xml.core.internal.ssemodelquery.ModelQueryAdapter;
import org.eclipse.wst.xml.ui.internal.contentassist.AbstractXMLModelQueryCompletionProposalComputer;
import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
+import org.eclipse.wst.xml.ui.internal.contentassist.MarkupCompletionProposal;
import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentModelGenerator;
import org.eclipse.wst.xml.ui.internal.contentassist.XMLRelevanceConstants;
import org.eclipse.wst.xml.ui.internal.editor.CMImageUtil;
@@ -343,7 +346,7 @@
// account for the < and >
int markupAdjustment = getCursorPositionForProposedText(proposedText);
String proposedInfo = getAdditionalInfo(null, ed);
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ MarkupCompletionProposal proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), markupAdjustment, image,
tagname, null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION);
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/templates/TemplateContextTypeJSP.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/templates/TemplateContextTypeJSP.java
index 60e19e7..baf57d2 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/templates/TemplateContextTypeJSP.java
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/templates/TemplateContextTypeJSP.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,8 +10,31 @@
*******************************************************************************/
package org.eclipse.jst.jsp.ui.internal.templates;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.templates.DocumentTemplateContext;
import org.eclipse.jface.text.templates.GlobalTemplateVariables;
+import org.eclipse.jface.text.templates.SimpleTemplateVariableResolver;
+import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
+import org.eclipse.jface.text.templates.TemplateVariable;
+import org.eclipse.jst.jsp.core.internal.util.FacetModuleCoreSupport;
+import org.eclipse.jst.jsp.core.taglib.IJarRecord;
+import org.eclipse.jst.jsp.core.taglib.ITLDRecord;
+import org.eclipse.jst.jsp.core.taglib.ITaglibDescriptor;
+import org.eclipse.jst.jsp.core.taglib.ITaglibRecord;
+import org.eclipse.jst.jsp.core.taglib.TaglibIndex;
+import org.eclipse.jst.jsp.ui.internal.JSPUIMessages;
+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.IStructuredDocument;
/**
* Base class for JSP template context types. Templates of this context type
@@ -29,5 +52,107 @@
addResolver(new GlobalTemplateVariables.WordSelection());
addResolver(new GlobalTemplateVariables.Year());
addResolver(new EncodingTemplateVariableResolverJSP());
+ addResolver(new URITemplateResolver());
+
+ }
+
+ /**
+ * Resolves the ${uri} Template Variable for a taglib directive providing
+ * URIs from the taglib index
+ *
+ */
+ class URITemplateResolver extends SimpleTemplateVariableResolver {
+
+ protected URITemplateResolver() {
+ super("uri", JSPUIMessages.Template_Taglib_URI); //$NON-NLS-1$
+ }
+
+ public void resolve(TemplateVariable variable, TemplateContext context) {
+ if (context instanceof DocumentTemplateContext) {
+ DocumentTemplateContext docContext = (DocumentTemplateContext) context;
+ final IPath path = getPath(docContext.getDocument());
+ if (path != null) {
+ String[] uris = getURIs(TaglibIndex.getAvailableTaglibRecords(path), path);
+ if (uris != null && uris.length > 0) {
+ variable.setValues(uris);
+ }
+ }
+
+ }
+ }
+
+ private String[] getURIs(ITaglibRecord[] records, IPath basePath) {
+ if (records != null) {
+ Set uris = new HashSet(records.length);
+ for (int i = 0; i < records.length; i++) {
+ final ITaglibRecord record = records[i];
+ final ITaglibDescriptor descriptor = record.getDescriptor();
+ String uri = null;
+ switch (record.getRecordType()) {
+ case ITaglibRecord.URL:
+ uris.add(descriptor.getURI());
+ break;
+ case ITaglibRecord.JAR: {
+ IPath location = ((IJarRecord) record).getLocation();
+ IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(location);
+ IPath localContextRoot = FacetModuleCoreSupport.computeWebContentRootPath(basePath);
+ for (int fileNumber = 0; fileNumber < files.length; fileNumber++) {
+ if (localContextRoot.isPrefixOf(files[fileNumber].getFullPath())) {
+ uri = IPath.SEPARATOR +
+ files[fileNumber].getFullPath().removeFirstSegments(localContextRoot.segmentCount()).toString();
+ }
+ else {
+ uri = FacetModuleCoreSupport.getRuntimePath(files[fileNumber].getFullPath()).toString();
+ }
+ uris.add(uri);
+ }
+ break;
+ }
+ case ITaglibRecord.TLD: {
+ uri = descriptor.getURI();
+ if (uri == null || uri.trim().length() == 0) {
+ IPath path = ((ITLDRecord) record).getPath();
+ IPath localContextRoot = FacetModuleCoreSupport.computeWebContentRootPath(basePath);
+ if (localContextRoot.isPrefixOf(path)) {
+ uri = IPath.SEPARATOR + path.removeFirstSegments(localContextRoot.segmentCount()).toString();
+ }
+ else {
+ uri = FacetModuleCoreSupport.getRuntimePath(path).toString();
+ }
+ }
+ uris.add(uri);
+ break;
+ }
+
+ }
+ }
+ String[] urisArray = (String[]) uris.toArray(new String[uris.size()]);
+ Arrays.sort(urisArray);
+ return urisArray;
+ }
+ return null;
+ }
+
+ private IPath getPath(IDocument iDoc) {
+ IPath path = null;
+ if (iDoc instanceof IStructuredDocument) {
+ IStructuredDocument document = (IStructuredDocument) iDoc;
+ IStructuredModel model = null;
+ try {
+ model = StructuredModelManager.getModelManager().getModelForRead(document);
+ if (model != null) {
+ String location = model.getBaseLocation();
+ if (location != null) {
+ path = new Path(location);
+ }
+ }
+ }
+ finally {
+ if (model != null)
+ model.releaseFromRead();
+ }
+ }
+ return path;
+ }
}
}
diff --git a/bundles/org.eclipse.jst.jsp.ui/templates/jspdefault-templates.properties b/bundles/org.eclipse.jst.jsp.ui/templates/jspdefault-templates.properties
index 58d9de8..187c4c5 100644
--- a/bundles/org.eclipse.jst.jsp.ui/templates/jspdefault-templates.properties
+++ b/bundles/org.eclipse.jst.jsp.ui/templates/jspdefault-templates.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2004, 2008 IBM Corporation and others.
+# Copyright (c) 2004, 2012 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -28,7 +28,7 @@
Templates.jsppagedirective.content=<%@ page contentType="text/html; charset=${encoding}" %>
Templates.jsptaglibdirective.name=JSP taglib directive
Templates.jsptaglibdirective.desc=JSP taglib directive
-Templates.jsptaglibdirective.content=<%@ taglib uri="${cursor}" prefix="" %>
+Templates.jsptaglibdirective.content=<%@ taglib uri="${uri}" prefix="${cursor}" %>
Templates.jsphtml.name=New JSP File (html)
Templates.jsphtml.desc=JSP with html markup
Templates.jsphtml.content=<%@ page language="java" contentType="text/html; charset=${encoding}"\n pageEncoding="${encoding}"%>\n<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=${encoding}">\n<title>Insert title here</title>\n</head>\n<body>\n${cursor}\n</body>\n</html>
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/AbstractXMLModelQueryCompletionProposalComputer.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/AbstractXMLModelQueryCompletionProposalComputer.java
index c6c0143..237c524 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/AbstractXMLModelQueryCompletionProposalComputer.java
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/AbstractXMLModelQueryCompletionProposalComputer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -198,7 +198,7 @@
if (attrAtLocationHasValue) {
// only propose the name
proposedText = getRequiredName(node, attrDecl);
- proposal = new CustomCompletionProposal(
+ proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), proposedText.length(),
attrImage, proposedText, null, proposedInfo,
@@ -227,7 +227,7 @@
}
if (proposalNeedsSpace)
proposedText += " "; //$NON-NLS-1$
- proposal = new CustomCompletionProposal(proposedText,
+ proposal = new MarkupCompletionProposal(proposedText,
contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(),
cursorPosition, attrImage,
@@ -367,7 +367,7 @@
if ((matchString.length() == 0) || possibleValue.startsWith(matchString)) {
String rString = "\"" + possibleValue + "\""; //$NON-NLS-1$ //$NON-NLS-2$
alternateMatch = "\"" + alternateMatch; //$NON-NLS-1$
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
rString, rOffset, rLength, possibleValue.length() + 1,
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ENUM),
rString, alternateMatch, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE, true);
@@ -377,7 +377,7 @@
}
if(defaultValue != null && ((matchString.length() == 0) || defaultValue.startsWith(matchString))) {
String rString = "\"" + defaultValue + "\""; //$NON-NLS-1$ //$NON-NLS-2$
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
rString, rOffset, rLength, defaultValue.length() + 1,
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_DEFAULT),
rString, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE);
@@ -392,7 +392,7 @@
String value = attrDecl.getAttrType().getImpliedValue();
if ((value != null) && (value.length() > 0)) {
String rValue = "\"" + value + "\"";//$NON-NLS-2$//$NON-NLS-1$
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
rValue, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), rValue.length() + 1,
image, rValue, null, proposedInfo,
@@ -400,7 +400,7 @@
contentAssistRequest.addProposal(proposal);
if ((currentValue.length() > 0) && !value.equals(currentValue)) {
rValue = "\"" + currentValue + "\""; //$NON-NLS-2$//$NON-NLS-1$
- proposal = new CustomCompletionProposal(rValue, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), rValue.length() + 1, image, rValue, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE);
+ proposal = new MarkupCompletionProposal(rValue, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), rValue.length() + 1, image, rValue, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE);
contentAssistRequest.addProposal(proposal);
}
}
@@ -412,7 +412,7 @@
CustomCompletionProposal proposal = null;
if ((currentValue != null) && (currentValue.length() > 0)) {
String rValue = "\"" + currentValue + "\""; //$NON-NLS-2$//$NON-NLS-1$
- proposal = new CustomCompletionProposal(rValue,
+ proposal = new MarkupCompletionProposal(rValue,
contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), 1, image,
rValue, null, proposedInfo,
@@ -447,7 +447,7 @@
CompletionProposalInvocationContext context) {
if (contentAssistRequest.getStartOffset() + contentAssistRequest.getRegion().getTextLength() < contentAssistRequest.getReplacementBeginPosition()) {
- CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(">", //$NON-NLS-1$
contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), NLS.bind(XMLUIMessages.Close_with__, (new Object[]{" '>'"})), //$NON-NLS-1$
null, null, XMLRelevanceConstants.R_END_TAG_NAME);
contentAssistRequest.addProposal(proposal);
@@ -479,14 +479,14 @@
image = this.getGenericTagImage();
}
if (contentAssistRequest.getRegion().getType() == DOMRegionContext.XML_TAG_NAME) {
- proposal = new CustomCompletionProposal(
+ proposal = new MarkupCompletionProposal(
replacementText, contentAssistRequest.getStartOffset(),
contentAssistRequest.getRegion().getTextLength(),
replacementText.length(), image, displayText, null,
proposedInfo, XMLRelevanceConstants.R_END_TAG_NAME);
}
else {
- proposal = new CustomCompletionProposal(
+ proposal = new MarkupCompletionProposal(
replacementText,
contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(),
@@ -631,7 +631,7 @@
setErrorMessage(XMLUIMessages.Content_Assist_not_availab_UI_);
}
if (addProposal == true) {
- CustomCompletionProposal proposal = new CustomCompletionProposal(replaceText, replaceBegin, replaceLength, cursorOffset, image, displayString, null, proposedInfo, XMLRelevanceConstants.R_END_TAG);
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(replaceText, replaceBegin, replaceLength, cursorOffset, image, displayString, null, proposedInfo, XMLRelevanceConstants.R_END_TAG);
contentAssistRequest.addProposal(proposal);
}
}
@@ -749,7 +749,7 @@
// prompt with a self-closing end character if needed
// this is one of the few times to ignore the length -- always insert
// contentAssistRequest.getReplacementLength()
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
getContentGenerator().getStartTagClose(node, elementDecl),
contentAssistRequest.getReplacementBeginPosition(), 0,
getContentGenerator().getStartTagClose(node, elementDecl).length(), image,
@@ -759,7 +759,7 @@
}
else {
// prompt with a close for the start tag
- CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(">", //$NON-NLS-1$
contentAssistRequest.getReplacementBeginPosition(),
// this is one of the few times to ignore the
// length -- always insert
@@ -775,7 +775,7 @@
IStructuredDocumentRegion sdr = contentAssistRequest.getDocumentRegion();
String openingTagText = (sdr != null) ? sdr.getFullText() : ""; //$NON-NLS-1$
if ((openingTagText != null) && (openingTagText.indexOf(node.getNodeName()) != -1)) {
- proposal = new CustomCompletionProposal("></" + node.getNodeName() + ">", //$NON-NLS-2$//$NON-NLS-1$
+ proposal = new MarkupCompletionProposal("></" + node.getNodeName() + ">", //$NON-NLS-2$//$NON-NLS-1$
contentAssistRequest.getReplacementBeginPosition(),
// this is one of the few times to
// ignore the length -- always insert
@@ -786,7 +786,7 @@
}
// prompt with slash bracket "/>" incase if it's a self ending tag
if (endWithSlashBracket) {
- proposal = new CustomCompletionProposal("/>", //$NON-NLS-1$
+ proposal = new MarkupCompletionProposal("/>", //$NON-NLS-1$
contentAssistRequest.getReplacementBeginPosition(),
// this is one of the few times to ignore
// the length -- always insert
@@ -801,7 +801,7 @@
else if ((contentAssistRequest.getDocumentRegion() == node.getLastStructuredDocumentRegion()) && !node.getLastStructuredDocumentRegion().isEnded()) {
setErrorMessage(null);
// prompt with a closing end character for the end tag
- CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(">", //$NON-NLS-1$
contentAssistRequest.getReplacementBeginPosition(),
// this is one of the few times to ignore the length -- always insert
// contentAssistRequest.getReplacementLength(),
@@ -865,7 +865,7 @@
String proposedInfo = getAdditionalInfo(parentDecl, childType);
for (int i = 0; i < childStrings.length; i++) {
if(!childStrings[i].equals(defaultValue)) {
- CustomCompletionProposal textProposal = new CustomCompletionProposal(
+ CustomCompletionProposal textProposal = new MarkupCompletionProposal(
childStrings[i],begin, length, childStrings[i].length(),
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ENUM),
childStrings[i], null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION);
@@ -873,7 +873,7 @@
}
}
if(defaultValue != null) {
- CustomCompletionProposal textProposal = new CustomCompletionProposal(
+ CustomCompletionProposal textProposal = new MarkupCompletionProposal(
defaultValue, begin, length, defaultValue.length(),
XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_DEFAULT),
defaultValue, null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION);
@@ -940,7 +940,7 @@
String proposedInfo = getAdditionalInfo(parentDecl, elementDecl);
int relevance = isStrictCMNodeSuggestion ? XMLRelevanceConstants.R_STRICTLY_VALID_TAG_INSERTION : XMLRelevanceConstants.R_TAG_INSERTION;
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), markupAdjustment,
image, tagname, null, proposedInfo, relevance);
@@ -1000,7 +1000,7 @@
// account for the < and >
int markupAdjustment = getContentGenerator().getMinimalStartTagLength(parent, ed);
String proposedInfo = getAdditionalInfo(null, ed);
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), markupAdjustment, image,
tagname, null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION);
@@ -1088,7 +1088,7 @@
}
int relevance = isStrictCMNodeSuggestion ? XMLRelevanceConstants.R_STRICTLY_VALID_TAG_NAME : XMLRelevanceConstants.R_TAG_NAME;
String proposedInfo = getAdditionalInfo(getCMElementDeclaration(parent), elementDecl);
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), cursorAdjustment, image,
getRequiredName(parent, elementDecl), null, proposedInfo,
@@ -1144,7 +1144,7 @@
if (image == null) {
image = this.getGenericTagImage();
}
- CustomCompletionProposal proposal = new CustomCompletionProposal(
+ CustomCompletionProposal proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), cursorAdjustment, image,
getRequiredName(parent, ed), null, proposedInfo, XMLRelevanceConstants.R_TAG_NAME);
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/MarkupCompletionProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/MarkupCompletionProposal.java
new file mode 100644
index 0000000..6b675af
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/MarkupCompletionProposal.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.ui.internal.contentassist;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.link.LinkedModeModel;
+import org.eclipse.jface.text.link.LinkedModeUI;
+import org.eclipse.jface.text.link.LinkedPosition;
+import org.eclipse.jface.text.link.LinkedPositionGroup;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
+import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal;
+import org.eclipse.wst.xml.ui.internal.Logger;
+
+/**
+ * A completion proposal that is capable of establishing linked positions within
+ * inserted markup.
+ *
+ */
+public class MarkupCompletionProposal extends CustomCompletionProposal {
+
+ private IRegion fSelectedRegion = null;
+
+ public MarkupCompletionProposal(String replacementString, int replacementOffset, int replacementLength, int cursorPosition, Image image, String displayString, IContextInformation contextInformation, String additionalProposalInfo, int relevance) {
+ super(replacementString, replacementOffset, replacementLength, cursorPosition, image, displayString, contextInformation, additionalProposalInfo, relevance);
+ }
+
+ public MarkupCompletionProposal(String replacementString, int replacementOffset, int replacementLength, int cursorPosition, Image image, String displayString, IContextInformation contextInformation, String additionalProposalInfo, int relevance, boolean updateReplacementLengthOnValidate) {
+ super(replacementString, replacementOffset, replacementLength, cursorPosition, image, displayString, null, contextInformation, additionalProposalInfo, relevance, updateReplacementLengthOnValidate);
+ }
+
+ public MarkupCompletionProposal(String replacementString, int replacementOffset, int replacementLength, int cursorPosition, Image image, String displayString, String alternateMatch, IContextInformation contextInformation, String additionalProposalInfo, int relevance, boolean updateReplacementLengthOnValidate) {
+ super(replacementString, replacementOffset, replacementLength, cursorPosition, image, displayString, alternateMatch, contextInformation, additionalProposalInfo, relevance, updateReplacementLengthOnValidate);
+ }
+
+ public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
+ super.apply(viewer, trigger, stateMask, offset);
+
+ getLinkedPositions(viewer);
+ }
+
+ /**
+ * Sets up linked positions and installs them on the viewer.
+ *
+ */
+ protected void getLinkedPositions(ITextViewer viewer) {
+ final String replacement = getReplacementString();
+ final IDocument document = viewer.getDocument();
+ final int length = replacement.length();
+ boolean inAttribute = false, hasGroup = false, inEndTag = false;
+ int offset = 0;
+ char attType = 0;
+ int exitPosition = -1;
+ LinkedModeModel model = new LinkedModeModel();
+
+ try {
+ for (int i = 0; i < length; i++) {
+ final char c = replacement.charAt(i);
+ switch (c) {
+ case '=':
+ break;
+ case '\'':
+ case '\"':
+ if (!inAttribute) {
+ offset = i;
+ attType = c;
+ inAttribute = true;
+ }
+ else {
+ // Found matching quotes establishing an attribute value region
+ if (attType == c && replacement.charAt(i - 1) != '\\') {
+ inAttribute = false; // Record position length
+ addPosition(model, document, getReplacementOffset() + offset + 1, i - offset - 1);
+ hasGroup = true;
+ }
+ }
+ break;
+ case '/':
+ if (!inAttribute) {
+ inEndTag = i > 0 && replacement.charAt(i - 1) == '<';
+ }
+ break;
+ case '>':
+ if (!inAttribute) {
+ if (i == length - 1) {
+ exitPosition = getReplacementOffset() + i + 1;
+ if (!inEndTag) { // Don't add a position within the end-tag
+ addPosition(model, document, getReplacementOffset() + i, 0); // position within start tag
+ hasGroup = true;
+ }
+ }
+ else {
+ addPosition(model, document, getReplacementOffset() + i, 0); // position within start tag
+ addPosition(model, document, getReplacementOffset() + i + 1, 0); // position after start tag
+ hasGroup = true;
+ }
+ }
+ break;
+ }
+ }
+ if (hasGroup) {
+ model.forceInstall();
+ final LinkedModeUI ui= new EditorLinkedModeUI(model, viewer);
+ ui.setExitPosition(viewer, exitPosition < 0 ? getReplacementOffset() + getReplacementLength() + replacement.length() - 1 : exitPosition, 0, Integer.MAX_VALUE);
+ ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT);
+ ui.setDoContextInfo(true);
+ ui.enter();
+ fSelectedRegion = ui.getSelectedRegion();
+ }
+ }
+ catch (BadLocationException e) {
+ Logger.logException(e);
+ }
+ }
+
+ /**
+ * Adds a {@link LinkedPosition} to its own position group. This group is then added to the model
+ * @param model the linked model for this proposal
+ * @param document the document the content assist is operating upon
+ * @param offset the offset to establish the {@link LinkedPosition}
+ * @param length the length of the {@link LinkedPosition}
+ * @throws BadLocationException
+ */
+ private void addPosition(LinkedModeModel model, IDocument document, int offset, int length) throws BadLocationException {
+ final LinkedPositionGroup group = new LinkedPositionGroup();
+ group.addPosition(new LinkedPosition(document, offset, length, LinkedPositionGroup.NO_STOP));
+ model.addGroup(group);
+ }
+
+ public Point getSelection(IDocument document) {
+ // Attempt to return the selection based on the selected region from the LinkedModeUI
+ if (fSelectedRegion == null)
+ return super.getSelection(document);
+ return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
+ }
+}
\ No newline at end of file