[115927] First attribute quote is deleted if insert JSP expression through statement completion
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPContentAssistProcessor.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPContentAssistProcessor.java index 77a04bb..39858f5 100644 --- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPContentAssistProcessor.java +++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPContentAssistProcessor.java
@@ -1145,7 +1145,8 @@ } } - addTemplates(request, TemplateContextTypeIdsJSP.ALL); + // bug115927 use original document position for all/any region templates + addTemplates(request, TemplateContextTypeIdsJSP.ALL, documentPosition); return request; } @@ -1163,6 +1164,17 @@ * @param context */ private void addTemplates(ContentAssistRequest contentAssistRequest, String context) { + addTemplates(contentAssistRequest, context, contentAssistRequest.getReplacementBeginPosition()); + } + + /** + * Adds templates to the list of proposals + * + * @param contentAssistRequest + * @param context + * @param startOffset + */ + private void addTemplates(ContentAssistRequest contentAssistRequest, String context, int startOffset) { if (contentAssistRequest == null) return; @@ -1174,7 +1186,7 @@ if (getTemplateCompletionProcessor() != null) { getTemplateCompletionProcessor().setContextType(context); - ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, contentAssistRequest.getReplacementBeginPosition()); + ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, startOffset); for (int i = 0; i < proposals.length; ++i) { if (useProposalList) contentAssistRequest.addProposal(proposals[i]); @@ -1184,8 +1196,7 @@ } } } - - + protected void addEntityProposals(ContentAssistRequest contentAssistRequest, int documentPosition, ITextRegion completionRegion, IDOMNode treeNode) { // ignore }
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPTemplateCompletionProcessor.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPTemplateCompletionProcessor.java index f3214dc..e835787 100644 --- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPTemplateCompletionProcessor.java +++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPTemplateCompletionProcessor.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2006 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,14 +10,24 @@ *******************************************************************************/ package org.eclipse.jst.jsp.ui.internal.contentassist; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.templates.ContextTypeRegistry; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateCompletionProcessor; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; +import org.eclipse.jface.text.templates.TemplateProposal; import org.eclipse.jface.text.templates.persistence.TemplateStore; import org.eclipse.jst.jsp.ui.internal.JSPUIPlugin; import org.eclipse.jst.jsp.ui.internal.editor.JSPEditorPluginImageHelper; @@ -30,12 +40,90 @@ * JSPTemplateCompletionProcessor is asked for content assist proposals, the * jsp content assist processor has already set the context type for * templates. - * - * @plannedfor 1.0 */ class JSPTemplateCompletionProcessor extends TemplateCompletionProcessor { + private static final class ProposalComparator implements Comparator { + public int compare(Object o1, Object o2) { + return ((TemplateProposal) o2).getRelevance() - ((TemplateProposal) o1).getRelevance(); + } + } + + private static final Comparator fgProposalComparator = new ProposalComparator(); private String fContextTypeId = null; + /* + * Copied from super class except instead of calling createContext(viewer, + * region) call createContext(viewer, region, offset) instead + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + + ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection(); + + // adjust offset to end of normalized selection + if (selection.getOffset() == offset) + offset = selection.getOffset() + selection.getLength(); + + String prefix = extractPrefix(viewer, offset); + Region region = new Region(offset - prefix.length(), prefix.length()); + TemplateContext context = createContext(viewer, region, offset); + if (context == null) + return new ICompletionProposal[0]; + + context.setVariable("selection", selection.getText()); // name of the + // selection + // variables + // {line, + // word}_selection + // //$NON-NLS-1$ + + Template[] templates = getTemplates(context.getContextType().getId()); + + List matches = new ArrayList(); + for (int i = 0; i < templates.length; i++) { + Template template = templates[i]; + try { + context.getContextType().validate(template.getPattern()); + } + catch (TemplateException e) { + continue; + } + if (template.matches(prefix, context.getContextType().getId())) + matches.add(createProposal(template, context, (IRegion) region, getRelevance(template, prefix))); + } + + Collections.sort(matches, fgProposalComparator); + + return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]); + } + + /** + * Creates a concrete template context for the given region in the + * document. This involves finding out which context type is valid at the + * given location, and then creating a context of this type. The default + * implementation returns a <code>SmartReplaceTemplateContext</code> for + * the context type at the given location. This takes the offset at which + * content assist was invoked into consideration. + * + * @param viewer + * the viewer for which the context is created + * @param region + * the region into <code>document</code> for which the + * context is created + * @param offset + * the original offset where content assist was invoked + * @return a template context that can handle template insertion at the + * given location, or <code>null</code> + */ + private TemplateContext createContext(ITextViewer viewer, IRegion region, int offset) { + // pretty much same code as super.createContext except create SmartReplaceTemplateContext + TemplateContextType contextType = getContextType(viewer, region); + if (contextType != null) { + IDocument document = viewer.getDocument(); + return new ReplaceNameTemplateContext(contextType, document, region.getOffset(), region.getLength(), offset); + } + return null; + } + protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region, int relevance) { return new CustomTemplateProposal(template, context, region, getImage(template), relevance); }
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/ReplaceNameTemplateContext.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/ReplaceNameTemplateContext.java new file mode 100644 index 0000000..1f4e9d1 --- /dev/null +++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/ReplaceNameTemplateContext.java
@@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2006 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.jst.jsp.ui.internal.contentassist; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.templates.DocumentTemplateContext; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateBuffer; +import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; + +/** + * Just like DocumentTemplateContext except if an insert offset is passed in, + * during evaluation, the "prefix" before the template will be checked to see + * if it matches the template name. If so, overwrite the template name. + * Otherwise, just insert the template at the insert offset location (by not + * overwriting the prefix text) + */ +public class ReplaceNameTemplateContext extends DocumentTemplateContext { + private int fInsertOffset = -1; + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length) { + this(type, document, new Position(offset, length)); + } + + /** + * Creates a document template context. The supplied <code>Position</code> + * will be queried to compute the <code>getStart</code> and + * <code>getEnd</code> methods, which will therefore answer updated + * position data if it is registered with the document. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param position + * the position describing the area of the document which forms + * the template context + * @since 3.1 + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, Position position) { + super(type, document, position); + } + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + * @param insertOffset + * the offset of the document region where insert was + * originally requested + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length, int insertOffset) { + this(type, document, new Position(offset, length)); + fInsertOffset = insertOffset; + } + + /* + * @see org.eclipse.jface.text.templates.TemplateContext#evaluate(org.eclipse.jface.text.templates.Template) + */ + public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException { + TemplateBuffer buffer = super.evaluate(template); + if (buffer != null) { + if (fInsertOffset > -1 && fInsertOffset > getStart()) { + String prefix = getDocument().get(getStart(), fInsertOffset - getStart()); + if (!template.getName().startsWith(prefix)) { + // generate a new buffer that actually contains the + // text that was going to be overwritten + buffer = new TemplateBuffer(prefix + buffer.getString(), buffer.getVariables()); + } + } + } + return buffer; + } +}
diff --git a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLContentAssistProcessor.java b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLContentAssistProcessor.java index ff35669..f605ba6 100644 --- a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLContentAssistProcessor.java +++ b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLContentAssistProcessor.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2006 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 @@ -119,9 +119,20 @@ * @param context */ private void addTemplates(ContentAssistRequest contentAssistRequest, String context) { + addTemplates(contentAssistRequest, context, contentAssistRequest.getReplacementBeginPosition()); + } + + /** + * Adds templates to the list of proposals + * + * @param contentAssistRequest + * @param context + * @param startOffset + */ + private void addTemplates(ContentAssistRequest contentAssistRequest, String context, int startOffset) { if (contentAssistRequest == null) return; - + // if already adding template proposals for a certain context type, do // not add again if (!fTemplateContexts.contains(context)) { @@ -130,7 +141,7 @@ if (getTemplateCompletionProcessor() != null) { getTemplateCompletionProcessor().setContextType(context); - ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, contentAssistRequest.getReplacementBeginPosition()); + ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, startOffset); for (int i = 0; i < proposals.length; ++i) { if (useProposalList) contentAssistRequest.addProposal(proposals[i]); @@ -151,7 +162,8 @@ protected ContentAssistRequest computeCompletionProposals(int documentPosition, String matchString, ITextRegion completionRegion, IDOMNode treeNode, IDOMNode xmlnode) { ContentAssistRequest request = super.computeCompletionProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); - addTemplates(request, TemplateContextTypeIdsHTML.ALL); + // bug115927 use original document position for all/any region templates + addTemplates(request, TemplateContextTypeIdsHTML.ALL, documentPosition); return request; }
diff --git a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLTemplateCompletionProcessor.java b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLTemplateCompletionProcessor.java index cc01530..1013fab 100644 --- a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLTemplateCompletionProcessor.java +++ b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/HTMLTemplateCompletionProcessor.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2006 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,14 +10,24 @@ *******************************************************************************/ package org.eclipse.wst.html.ui.internal.contentassist; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.templates.ContextTypeRegistry; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateCompletionProcessor; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; +import org.eclipse.jface.text.templates.TemplateProposal; import org.eclipse.jface.text.templates.persistence.TemplateStore; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.html.ui.internal.HTMLUIPlugin; @@ -33,8 +43,88 @@ * templates. */ class HTMLTemplateCompletionProcessor extends TemplateCompletionProcessor { + private static final class ProposalComparator implements Comparator { + public int compare(Object o1, Object o2) { + return ((TemplateProposal) o2).getRelevance() - ((TemplateProposal) o1).getRelevance(); + } + } + + private static final Comparator fgProposalComparator = new ProposalComparator(); private String fContextTypeId = null; + /* + * Copied from super class except instead of calling createContext(viewer, + * region) call createContext(viewer, region, offset) instead + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + + ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection(); + + // adjust offset to end of normalized selection + if (selection.getOffset() == offset) + offset = selection.getOffset() + selection.getLength(); + + String prefix = extractPrefix(viewer, offset); + Region region = new Region(offset - prefix.length(), prefix.length()); + TemplateContext context = createContext(viewer, region, offset); + if (context == null) + return new ICompletionProposal[0]; + + context.setVariable("selection", selection.getText()); // name of the + // selection + // variables + // {line, + // word}_selection + // //$NON-NLS-1$ + + Template[] templates = getTemplates(context.getContextType().getId()); + + List matches = new ArrayList(); + for (int i = 0; i < templates.length; i++) { + Template template = templates[i]; + try { + context.getContextType().validate(template.getPattern()); + } + catch (TemplateException e) { + continue; + } + if (template.matches(prefix, context.getContextType().getId())) + matches.add(createProposal(template, context, (IRegion) region, getRelevance(template, prefix))); + } + + Collections.sort(matches, fgProposalComparator); + + return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]); + } + + /** + * Creates a concrete template context for the given region in the + * document. This involves finding out which context type is valid at the + * given location, and then creating a context of this type. The default + * implementation returns a <code>SmartReplaceTemplateContext</code> for + * the context type at the given location. This takes the offset at which + * content assist was invoked into consideration. + * + * @param viewer + * the viewer for which the context is created + * @param region + * the region into <code>document</code> for which the + * context is created + * @param offset + * the original offset where content assist was invoked + * @return a template context that can handle template insertion at the + * given location, or <code>null</code> + */ + private TemplateContext createContext(ITextViewer viewer, IRegion region, int offset) { + // pretty much same code as super.createContext except create SmartReplaceTemplateContext + TemplateContextType contextType = getContextType(viewer, region); + if (contextType != null) { + IDocument document = viewer.getDocument(); + return new ReplaceNameTemplateContext(contextType, document, region.getOffset(), region.getLength(), offset); + } + return null; + } + protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region, int relevance) { return new CustomTemplateProposal(template, context, region, getImage(template), relevance); }
diff --git a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/ReplaceNameTemplateContext.java b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/ReplaceNameTemplateContext.java new file mode 100644 index 0000000..eef8962 --- /dev/null +++ b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/contentassist/ReplaceNameTemplateContext.java
@@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2006 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.html.ui.internal.contentassist; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.templates.DocumentTemplateContext; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateBuffer; +import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; + +/** + * Just like DocumentTemplateContext except if an insert offset is passed in, + * during evaluation, the "prefix" before the template will be checked to see + * if it matches the template name. If so, overwrite the template name. + * Otherwise, just insert the template at the insert offset location (by not + * overwriting the prefix text) + */ +public class ReplaceNameTemplateContext extends DocumentTemplateContext { + private int fInsertOffset = -1; + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length) { + this(type, document, new Position(offset, length)); + } + + /** + * Creates a document template context. The supplied <code>Position</code> + * will be queried to compute the <code>getStart</code> and + * <code>getEnd</code> methods, which will therefore answer updated + * position data if it is registered with the document. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param position + * the position describing the area of the document which forms + * the template context + * @since 3.1 + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, Position position) { + super(type, document, position); + } + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + * @param insertOffset + * the offset of the document region where insert was + * originally requested + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length, int insertOffset) { + this(type, document, new Position(offset, length)); + fInsertOffset = insertOffset; + } + + /* + * @see org.eclipse.jface.text.templates.TemplateContext#evaluate(org.eclipse.jface.text.templates.Template) + */ + public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException { + TemplateBuffer buffer = super.evaluate(template); + if (buffer != null) { + if (fInsertOffset > -1 && fInsertOffset > getStart()) { + String prefix = getDocument().get(getStart(), fInsertOffset - getStart()); + if (!template.getName().startsWith(prefix)) { + // generate a new buffer that actually contains the + // text that was going to be overwritten + buffer = new TemplateBuffer(prefix + buffer.getString(), buffer.getVariables()); + } + } + } + return buffer; + } +}
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/ReplaceNameTemplateContext.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/ReplaceNameTemplateContext.java new file mode 100644 index 0000000..9eb98c4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/ReplaceNameTemplateContext.java
@@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2006 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.Position; +import org.eclipse.jface.text.templates.DocumentTemplateContext; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateBuffer; +import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; + +/** + * Just like DocumentTemplateContext except if an insert offset is passed in, + * during evaluation, the "prefix" before the template will be checked to see + * if it matches the template name. If so, overwrite the template name. + * Otherwise, just insert the template at the insert offset location (by not + * overwriting the prefix text) + */ +public class ReplaceNameTemplateContext extends DocumentTemplateContext { + private int fInsertOffset = -1; + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length) { + this(type, document, new Position(offset, length)); + } + + /** + * Creates a document template context. The supplied <code>Position</code> + * will be queried to compute the <code>getStart</code> and + * <code>getEnd</code> methods, which will therefore answer updated + * position data if it is registered with the document. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param position + * the position describing the area of the document which forms + * the template context + * @since 3.1 + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, Position position) { + super(type, document, position); + } + + /** + * Creates a document template context. + * + * @param type + * the context type + * @param document + * the document this context applies to + * @param offset + * the offset of the document region + * @param length + * the length of the document region + * @param insertOffset + * the offset of the document region where insert was + * originally requested + */ + public ReplaceNameTemplateContext(TemplateContextType type, IDocument document, int offset, int length, int insertOffset) { + this(type, document, new Position(offset, length)); + fInsertOffset = insertOffset; + } + + /* + * @see org.eclipse.jface.text.templates.TemplateContext#evaluate(org.eclipse.jface.text.templates.Template) + */ + public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException { + TemplateBuffer buffer = super.evaluate(template); + if (buffer != null) { + if (fInsertOffset > -1 && fInsertOffset > getStart()) { + String prefix = getDocument().get(getStart(), fInsertOffset - getStart()); + if (!template.getName().startsWith(prefix)) { + // generate a new buffer that actually contains the + // text that was going to be overwritten + buffer = new TemplateBuffer(prefix + buffer.getString(), buffer.getVariables()); + } + } + } + return buffer; + } +}
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLContentAssistProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLContentAssistProcessor.java index 01068ba..32b40df 100644 --- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLContentAssistProcessor.java +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLContentAssistProcessor.java
@@ -65,9 +65,20 @@ * @param context */ private void addTemplates(ContentAssistRequest contentAssistRequest, String context) { + addTemplates(contentAssistRequest, context, contentAssistRequest.getReplacementBeginPosition()); + } + + /** + * Adds templates to the list of proposals + * + * @param contentAssistRequest + * @param context + * @param startOffset + */ + private void addTemplates(ContentAssistRequest contentAssistRequest, String context, int startOffset) { if (contentAssistRequest == null) return; - + // if already adding template proposals for a certain context type, do // not add again if (!fTemplateContexts.contains(context)) { @@ -76,7 +87,7 @@ if (getTemplateCompletionProcessor() != null) { getTemplateCompletionProcessor().setContextType(context); - ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, contentAssistRequest.getReplacementBeginPosition()); + ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, startOffset); for (int i = 0; i < proposals.length; ++i) { if (useProposalList) contentAssistRequest.addProposal(proposals[i]); @@ -89,7 +100,8 @@ protected ContentAssistRequest computeCompletionProposals(int documentPosition, String matchString, ITextRegion completionRegion, IDOMNode treeNode, IDOMNode xmlnode) { ContentAssistRequest request = super.computeCompletionProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); - addTemplates(request, TemplateContextTypeIdsXML.ALL); + // bug115927 use original document position for all/any region templates + addTemplates(request, TemplateContextTypeIdsXML.ALL, documentPosition); return request; }
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLTemplateCompletionProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLTemplateCompletionProcessor.java index a789a47..619bcae 100644 --- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLTemplateCompletionProcessor.java +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/contentassist/XMLTemplateCompletionProcessor.java
@@ -12,14 +12,24 @@ *******************************************************************************/ package org.eclipse.wst.xml.ui.internal.contentassist; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.templates.ContextTypeRegistry; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateCompletionProcessor; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.TemplateException; +import org.eclipse.jface.text.templates.TemplateProposal; import org.eclipse.jface.text.templates.persistence.TemplateStore; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.xml.ui.internal.XMLUIPlugin; @@ -35,8 +45,88 @@ * templates. */ class XMLTemplateCompletionProcessor extends TemplateCompletionProcessor { + private static final class ProposalComparator implements Comparator { + public int compare(Object o1, Object o2) { + return ((TemplateProposal) o2).getRelevance() - ((TemplateProposal) o1).getRelevance(); + } + } + + private static final Comparator fgProposalComparator = new ProposalComparator(); private String fContextTypeId = null; + /* + * Copied from super class except instead of calling createContext(viewer, + * region) call createContext(viewer, region, offset) instead + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + + ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection(); + + // adjust offset to end of normalized selection + if (selection.getOffset() == offset) + offset = selection.getOffset() + selection.getLength(); + + String prefix = extractPrefix(viewer, offset); + Region region = new Region(offset - prefix.length(), prefix.length()); + TemplateContext context = createContext(viewer, region, offset); + if (context == null) + return new ICompletionProposal[0]; + + context.setVariable("selection", selection.getText()); // name of the + // selection + // variables + // {line, + // word}_selection + // //$NON-NLS-1$ + + Template[] templates = getTemplates(context.getContextType().getId()); + + List matches = new ArrayList(); + for (int i = 0; i < templates.length; i++) { + Template template = templates[i]; + try { + context.getContextType().validate(template.getPattern()); + } + catch (TemplateException e) { + continue; + } + if (template.matches(prefix, context.getContextType().getId())) + matches.add(createProposal(template, context, (IRegion) region, getRelevance(template, prefix))); + } + + Collections.sort(matches, fgProposalComparator); + + return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]); + } + + /** + * Creates a concrete template context for the given region in the + * document. This involves finding out which context type is valid at the + * given location, and then creating a context of this type. The default + * implementation returns a <code>SmartReplaceTemplateContext</code> for + * the context type at the given location. This takes the offset at which + * content assist was invoked into consideration. + * + * @param viewer + * the viewer for which the context is created + * @param region + * the region into <code>document</code> for which the + * context is created + * @param offset + * the original offset where content assist was invoked + * @return a template context that can handle template insertion at the + * given location, or <code>null</code> + */ + private TemplateContext createContext(ITextViewer viewer, IRegion region, int offset) { + // pretty much same code as super.createContext except create SmartReplaceTemplateContext + TemplateContextType contextType = getContextType(viewer, region); + if (contextType != null) { + IDocument document = viewer.getDocument(); + return new ReplaceNameTemplateContext(contextType, document, region.getOffset(), region.getLength(), offset); + } + return null; + } + protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region, int relevance) { return new CustomTemplateProposal(template, context, region, getImage(template), relevance); }