package com.liferay.ide.velocity.editor;
import com.liferay.ide.velocity.editor.completion.ICompletionProvider;
import com.liferay.ide.velocity.editor.completion.ProviderManager;
import com.liferay.ide.velocity.preferences.GeneralPreferencePage;
import com.liferay.ide.velocity.ui.VeloContextType;
import com.liferay.ide.velocity.ui.editor.xml.IEditorConfiguration;
import com.liferay.ide.velocity.ui.editor.xml.IHTMLConstants;
import com.liferay.ide.velocity.vaulttec.ui.VelocityPlugin;
import com.liferay.ide.velocity.vaulttec.ui.VelocityPluginImages;
import com.liferay.ide.velocity.vaulttec.ui.editor.VelocityConfiguration;
import com.liferay.ide.velocity.vaulttec.ui.editor.VelocityEditorEnvironment;
import com.liferay.ide.velocity.vaulttec.ui.editor.text.VelocityTextGuesser;
import com.liferay.ide.velocity.vaulttec.ui.model.Directive;
import com.wutka.dtd.DTDAttribute;
import com.wutka.dtd.DTDChoice;
import com.wutka.dtd.DTDElement;
import com.wutka.dtd.DTDEnumeration;
import com.wutka.dtd.DTDItem;
import com.wutka.dtd.DTDMixed;
import com.wutka.dtd.DTDName;
import com.wutka.dtd.DTDNotationList;
import com.wutka.dtd.DTDSequence;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.velocity.runtime.directive.Macro;
import org.apache.velocity.runtime.directive.VelocimacroProxy;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
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.ITypedRegion;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.swt.graphics.Image;
/**
* DOCUMENT ME!
*
* @version $Revision: 32 $
* @author <a href="mailto:akmal.sarhan@gmail.com">Akmal Sarhan </a>
* @author Peter Friese
*/
public class VelocityCompletionProcessor extends TemplateCompletionProcessor implements IContentAssistProcessor, IHTMLConstants
{
boolean upperCaseEnabled;
private static final String DEFAULT_IMAGE = "icons/template.gif"; //$NON-NLS-1$
private Collection<String> flatValuesTags;
private Collection<String> emptyTagSet;
private Collection<String> tagSet;
private Comparator<Object> proposalComparator = new Comparator<Object>() {
public int compare(Object aProposal1, Object aProposal2)
{
String text1 = ((CompletionProposal) aProposal1).getDisplayString();
String text2 = ((CompletionProposal) aProposal2).getDisplayString();
return text1.compareTo(text2);
}
public boolean equals(Object aProposal)
{
return false;
}
};
private static final String[] flatValues = new String[] { "compact", "checked", "declare", "readonly", "disabled", "selected", "defer", "ismap", "nohref",
"noshade", "nowrap", "multiple", "noresize" };
public static final String[] tags = new String[] { "AREA", "BASE", "BASEFONT", "BR", "COL", "FRAME", "HR", "IMG", "INPUT", "ISINDEX", "LINK", "META",
"PARAM", "A", "ADDRESS", "APPLET", "B", "BIG", "BLOCKQUOTE", "BODY", "CAPTION", "CENTER", "CITE", "CODE", "COLGROUP", "DD", "DFN", "DIR", "DIV", "DL", "DT", "EM",
"FONT", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HTML", "I", "KBD", "LI", "MAP", "MENU", "NOBR", "NOFRAMES", "OBJECT", "OL", "OPTION", "P",
"PRE", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRIKE", "S", "STRONG", "STYLE", "SUB", "SUP", "TABLE", "TD", "TEXTAREA", "TH", "TITLE", "TR", "TT", "U", "UL",
"VAR" };
public static final String[] jspTags = new String[] { "C:FOREACH", "C:IF", "C:CHOOSE", "C:WHEN","C:OUT", "C:OTHERWISE", "C:URL", "C:PARAM", "C:SET", "C:REMOVE",
"C:FORTOKENS", "FMT:MESSAGE", "FMT:FORMATDATE", "JSP:PARAM", "JSP:OUTPUT", "JSP:SETPROPERTY", "JSP:GETPROPERTY", "C:IMPORT", "C:REDIRECT", "JSP:DIRECTIVE.INCLUDE",
"JSP:INCLUDE", "JSP:USEBEAN", "JSP:ROOT" };
private VelocityEditor fEditor;
private boolean fCompleteDirectives = true;
protected int fTabWidth = 4;
private boolean isJsp = false;
private Map<String, List<String>> jspAttrMap;
private Map<String, List<String>> jspAttrValuesMap;
public VelocityCompletionProcessor(VelocityEditor anEditor, boolean aCompleteDirectives) {
upperCaseEnabled = VelocityPlugin.getDefault().getPreferenceStore().getBoolean(GeneralPreferencePage.P_CASE);
fEditor = anEditor;
isJsp = anEditor.getEditorInput().getName().matches(".*?\\.jsp.*");
fCompleteDirectives = aCompleteDirectives;
tagSet = new ArrayList<String>(Arrays.asList(tags));
if (isJsp) {
tagSet.addAll(Arrays.asList(jspTags));
jspAttrMap = new HashMap<String, List<String>>();
jspAttrMap.put("c:foreach", Arrays.asList(new String[] { "var", "items", "begin", "end", "step", "varStatus" }));
jspAttrMap.put("c:if", Arrays.asList(new String[] { "test", "var", "scope" }));
jspAttrMap.put("c:choose", Arrays.asList(new String[] { "test" }));
jspAttrMap.put("c:when", Arrays.asList(new String[] { "test" }));
jspAttrMap.put("c:otherwise", Arrays.asList(new String[] { "test" }));
jspAttrMap.put("c:url", Arrays.asList(new String[] { "value", "context", "var", "scope" }));
jspAttrMap.put("c:param", Arrays.asList(new String[] { "name", "value" }));
jspAttrMap.put("c:set", Arrays.asList(new String[] { "value", "target", "property", "var", "scope" }));
jspAttrMap.put("c:remove", Arrays.asList(new String[] { "var", "scope" }));
jspAttrMap.put("c:fortokens", Arrays.asList(new String[] { "var", "items", "begin", "end", "step", "varStatus", "delims" }));
jspAttrMap.put("fmt:message", Arrays.asList(new String[] { "key", "bundle", "var", "scope" }));
jspAttrMap.put("c:import", Arrays.asList(new String[] { "url", "context", "var", "scope", "charEncoding", "varReader" }));
jspAttrMap.put("c:redirect", Arrays.asList(new String[] { "url", "context" }));
jspAttrMap.put("jsp:directive.include", Arrays.asList(new String[] { "file" }));
jspAttrMap.put("jsp:include", Arrays.asList(new String[] { "page", "flush" }));
jspAttrMap.put("jsp:usebean", Arrays.asList(new String[] { "beanName", "id", "class", "scope", "type" }));
jspAttrMap.put("jsp:root", Arrays.asList(new String[] { "version", "xmlns", "xmlns:jsp", "xmlns:c", "xmlns:fn", "xmlns:fmt" }));
jspAttrMap.put("jsp:output", Arrays.asList(new String[] { "omit-xml-declaration", "doctype-root-element", "doctype-public", "doctype-system" }));
jspAttrMap.put("jsp:getProperty", Arrays.asList(new String[] { "name", "property" }));
jspAttrMap.put("jsp:param", Arrays.asList(new String[] { "name", "value" }));
jspAttrMap.put("c:out", Arrays.asList(new String[] { "value","escapeXml" ,"default"}));
jspAttrMap.put("jsp:setproperty", Arrays.asList(new String[] { "param", "name", "value", "property" }));
jspAttrMap.put("fmt:formatdate", Arrays.asList(new String[] { "type", "var", "scope", "value", "pattern", "dateStyle", "timeStyle", "timeZone" }));
jspAttrValuesMap = new HashMap<String,List<String>>();
jspAttrValuesMap.put("type", Arrays.asList(new String[] { "date", "time", "both" }));
jspAttrValuesMap.put("test", Arrays.asList(new String[] { "${}" }));
jspAttrValuesMap.put("flush", Arrays.asList(new String[] { "true", "false" }));
jspAttrValuesMap.put("escapeXml", Arrays.asList(new String[] { "true", "false" }));
jspAttrValuesMap.put("required", Arrays.asList(new String[] { "true", "false" }));
jspAttrValuesMap.put("omit-xml-declaration", Arrays.asList(new String[] { "true", "yes", "false", "no" }));
jspAttrValuesMap.put("dateStyle", Arrays.asList(new String[] { "default", "short", "medium", "long", "full" }));
jspAttrValuesMap.put("timeStyle", Arrays.asList(new String[] { "default", "short", "medium", "long", "full" }));
jspAttrValuesMap.put("xmlns", Arrays.asList(new String[] { "http://www.w3c.org/1999/xhtml" }));
jspAttrValuesMap.put("xmlns:jsp", Arrays.asList(new String[] { "http://java.sun.com/JSP/Page" }));
jspAttrValuesMap.put("xmlns:c", Arrays.asList(new String[] { "http://java.sun.com/jsp/jstl/core" }));
jspAttrValuesMap.put("xmlns:fn", Arrays.asList(new String[] { "http://java.sun.com/jsp/jstl/functions" }));
jspAttrValuesMap.put("xmlns:fmt", Arrays.asList(new String[] { "http://java.sun.com/jsp/jstl/fmt" }));
jspAttrValuesMap.put("doctype-public", Arrays.asList(new String[] { "-//W3C//DTD XHTML 1.0 Transitional//EN" }));
jspAttrValuesMap.put("doctype-system", Arrays.asList(new String[] { "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" }));
jspAttrValuesMap.put("scope", Arrays.asList(new String[] { "page", "request", "session", "application" }));
}
emptyTagSet = Arrays.asList(IHTMLConstants.EMPTY_TAGS);
flatValuesTags = Arrays.asList(flatValues);
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer,
* int)
*/
public ICompletionProposal[] computeCompletionProposals(ITextViewer aViewer, int anOffset)
{
ICompletionProposal[] proposals = null;
IDocument doc = aViewer.getDocument();
VelocityTextGuesser prefix = new VelocityTextGuesser(doc, anOffset, false);
if (prefix.getType() == VelocityTextGuesser.TYPE_DIRECTIVE) {
if (fCompleteDirectives) {
proposals = getDirectiveProposals(prefix.getText(), anOffset - prefix.getText().length());
}
}
else if (prefix.getType() == VelocityTextGuesser.TYPE_VARIABLE) {
proposals = getVariableProposals(prefix.getText(), anOffset - prefix.getText().length());
}
else if (prefix.getType() == VelocityTextGuesser.TAG_DIRECTIVE) {
proposals = getTAGProposals(doc, prefix.getText(), anOffset - prefix.getText().length());
}
else if (prefix.getType() == VelocityTextGuesser.TAG_CLOSE) {
proposals = getTAGCloseProposals(doc, prefix.getText(), anOffset - prefix.getText().length());
}
else if (prefix.getType() == VelocityTextGuesser.TYPE_APOSTROPHE) {
proposals = getAttributeValuesProposals(doc, prefix.getText(), anOffset - prefix.getText().length());
}
else if (EditorsUtil.isInsidePartition(anOffset, new String[] { IEditorConfiguration.TAG_PARTITION, IEditorConfiguration.SCRIPT_PARTITION }, true, doc)) {
proposals = getAttributesProposals(doc, prefix.getText(), anOffset - prefix.getText().length());
}
// else
// {
// proposals = getWordsProposals(doc, prefix.getText(), anOffset -
// prefix.getText().length());
// }
if (proposals == null) {
proposals = new ICompletionProposal[0];
proposals = super.computeCompletionProposals(aViewer, anOffset);
}
Collection<?> extraProposals = getExtraProposals(doc, prefix, anOffset - prefix.getText().length());
List defaultProposals = new ArrayList(Arrays.asList(proposals));
defaultProposals.addAll(extraProposals);
ICompletionProposal[] result = (ICompletionProposal[]) defaultProposals.toArray(new ICompletionProposal[defaultProposals.size()]);
return result;
}
/**
* Gives extenders the possibility to add their own completion proposals.
*
* @param doc
* @param prefix
* @param i
* @return
*/
private Collection getExtraProposals(IDocument doc, VelocityTextGuesser prefix, int offset)
{
Collection result = new ArrayList();
IFile file = (IFile) fEditor.getEditorInput().getAdapter(IFile.class);
ICompletionProvider[] completionProviders = ProviderManager.getInstance().getProviders();
for (int i = 0; i < completionProviders.length; i++) {
ICompletionProvider provider = completionProviders[i];
Collection extraProposals;
try {
extraProposals = provider.getExtraProposals(fEditor, file, doc, prefix, offset);
result.addAll(extraProposals);
}
catch (CoreException e) {
e.printStackTrace();
}
}
return result;
}
/**
* @param string
* @param i
* @return
*/
private ICompletionProposal[] getAttributesProposals(IDocument doc, String aPrefix, int anOffset)
{
String string = null;
try {
ITypedRegion partition = doc.getPartition(anOffset);
int i = partition.getOffset();
int b = partition.getLength();
string = doc.get(i, b);
}
catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String s = findMatchingTagIdentifierBefore(anOffset, doc);
List<String> variables = null;
if (s != null) {
DTDElement element = VelocityEditor.getHTMLElement(s.toLowerCase());
variables = new ArrayList<String>();
if (element != null) {
Hashtable table = element.attributes;
Collection collection = table.values();
if (collection.size() > 0) {
for (Iterator iter = collection.iterator(); iter.hasNext();) {
DTDAttribute attrib = (DTDAttribute) iter.next();
if (flatValuesTags.contains(attrib.getName())) {
if ((string != null) && (string.indexOf(attrib.getName() + " ") == -1)) {
variables.add(attrib.getName());
}
}
else {
if ((string != null) && (string.indexOf(attrib.getName() + "=") == -1)) {
variables.add(attrib.getName());
}
}
}
}
}
if (element == null && isJsp) {
for (String attrib : jspAttrMap.get(s)) {
if ((string != null) && (string.indexOf(attrib + "=") == -1)) {
variables.add(attrib);
}
}
// variables=(List) jspAttrMap.get(s);
}
}
ICompletionProposal[] result = null;
CompletionProposal proposal = null;
if (variables != null) {
List proposals = new ArrayList();
Iterator iter = variables.iterator();
while (iter.hasNext()) {
String variable = (String) iter.next();
String append = "=\"\"";
int cur = 2;
if (variable.startsWith(aPrefix.toLowerCase())) {
if (flatValuesTags.contains(variable.toLowerCase())) {
append = " ";
cur = 1;
}
proposal = new CompletionProposal(variable + append, anOffset, aPrefix.length(), variable.length() + cur, null, variable, null, null);
proposals.add(proposal);
}
}
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
return result;
}
private ICompletionProposal[] getAttributeValuesProposals(IDocument doc, String aPrefix, int anOffset)
{
String s = findMatchingTagIdentifierBefore(anOffset - 2, doc);
String attribute = getAttribute(doc, anOffset - 3);
DTDElement element = VelocityEditor.getHTMLElement(s.toLowerCase());
Collection variables = new ArrayList();
if (element != null) {
Hashtable table = element.attributes;
Collection collection = table.values();
if (collection.size() > 0) {
for (Iterator iter = collection.iterator(); iter.hasNext();) {
DTDAttribute attrib = (DTDAttribute) iter.next();
if (attrib.getName().equalsIgnoreCase(attribute)) {
dumpAttribute(attrib, variables);
}
}
}
}
if (element == null && isJsp && jspAttrValuesMap.get(attribute) != null) {
variables = jspAttrValuesMap.get(attribute);
}
ICompletionProposal[] result = null;
CompletionProposal proposal = null;
if (!variables.isEmpty()) {
List proposals = new ArrayList();
Iterator iter = variables.iterator();
while (iter.hasNext()) {
String variable = (String) iter.next();
if (variable.startsWith(aPrefix.toLowerCase())) {
proposal = new CompletionProposal(variable + "\" ", anOffset, aPrefix.length() + 1, variable.length() + 2, null, variable, null, null);
proposals.add(proposal);
}
}
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
return result;
}
private Set extractWords(String input)
{
StringTokenizer stringTokenizer = new StringTokenizer(input, "#=:?\t <>,;()$.'}{][&%!*-/\\\n\"\'");
Set set = new HashSet();
while (stringTokenizer.hasMoreTokens()) {
set.add(stringTokenizer.nextToken());
}
return set;
}
private ICompletionProposal[] getWordsProposals(IDocument doc, String aPrefix, int anOffset)
{
if (aPrefix == null || aPrefix.length() == 0)
return null;
ICompletionProposal[] result = null;
CompletionProposal proposal = null;
Set variables = extractWords(doc.get());
if (!variables.isEmpty()) {
List proposals = new ArrayList();
Iterator iter = variables.iterator();
while (iter.hasNext()) {
String variable = (String) iter.next();
if (variable.startsWith(aPrefix) && !variable.equals(aPrefix)) {
proposal = new CompletionProposal(variable, anOffset, aPrefix.length(), variable.length(), null, variable, null, null);
proposals.add(proposal);
}
}
if (proposals.isEmpty())
return null;
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
return result;
}
protected int findMatchingOpenTagBefore(int end, IDocument doc)
{
int level = 1;
try {
char prev = '\0';
for (end--; end >= 0; end--) {
if (EditorsUtil.isInsidePartition(end, VelocityConfiguration.CDATA_PARTITIONS, true, doc)) {
end = doc.getPartition(end).getOffset() - 1;
}
else if (EditorsUtil.isInsidePartition(end, VelocityConfiguration.ESCAPED_PARTITIONS, doc)) {
end = doc.getPartition(end).getOffset() -1;
}
char c = doc.getChar(end);
if (c == '/' && prev == '>')
level++;
if (c == '<') {
if (prev == '/') {
level++;
}
else if ((prev != '!') && (prev != '?') && (prev != '%') && (prev != '#')) {
String id = getIdentifier(doc, end + 1, doc.getLength());
// if (!fEMPTY_TAG_SET.contains(id.toUpperCase())) {
level--;
// }
if (level == 0) {
return end;
}
}
}
else if ((c == '"') || (c == '\'')) {
end = getStringStart(doc, end, c);
}
// TODO if(c=='/' && prev=='>') level++;
prev = c;
}
}
catch (BadLocationException e) {
}
return -1;
}
private ICompletionProposal[] getTAGCloseProposals(IDocument doc, String aPrefix, int anOffset)
{
String closetag = ">";
String s = findMatchingOpenTagIdentifierBefore(anOffset - 2, doc);
int lasttagOffset = findMatchingOpenTagBefore(anOffset - 2, doc);
int start = 0;
try {
start = doc.getLineOffset(doc.getLineOfOffset(anOffset));
}
catch (BadLocationException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
String ddd = null;
int dlength = 0;
try {
ddd = sameIndentAs(lasttagOffset, doc.getLineOfOffset(anOffset), doc, anOffset, s + closetag);
dlength = ddd.length();
}
catch (BadLocationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// int curPo = start + dlength;
ICompletionProposal[] result = null;
String[] tags = new String[] { "A", "ADDRESS", "APPLET", "B", "BIG", "BLOCKQUOTE", "BODY", "CAPTION", "CENTER", "CITE", "CODE", "COL", "COLGROUP", "DD", "DFN", "DIR",
"DIV", "DL", "DT", "EM", "FONT", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HTML", "I", "KBD", "LI", "MAP", "MENU", "NOBR", "NOFRAMES",
"OBJECT", "OL", "OPTION", "P", "PRE", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRIKE", "S", "STRONG", "STYLE", "SUB", "SUP", "TABLE", "TD", "TEXTAREA", "TH",
"TITLE", "TR", "TT", "U", "UL", "VAR", "C:FOREACH", "C:IF", "C:CHOOSE", "C:WHEN", "C:OTHERWISE", "C:URL", "C:PARAM", "C:SET", "C:REMOVE", "C:FORTOKENS",
"FMT:MESSAGE" };
List variables = Arrays.asList(tags);
List proposals = new ArrayList();
CompletionProposal proposal = null;
if ((s != null) && (s.length() > 0)) {
proposal = new CompletionProposal(ddd, start, aPrefix.length() + (anOffset - start), dlength, null, s, null, "test3");
proposals.add(proposal);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
else if (!variables.isEmpty()) {
Iterator iter = variables.iterator();
String variable = null;
while (iter.hasNext()) {
variable = (String) iter.next();
if (variable.startsWith(aPrefix.toUpperCase())) {
String opentag = variable;
proposal = new CompletionProposal(opentag + closetag, anOffset, aPrefix.length(), variable.length() + 1, null, variable, null, "test3");
proposals.add(proposal);
}
}
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
return result;
}
/**
* @param string
* @param i
* @return
*/
private ICompletionProposal[] getTAGProposals(IDocument doc, String aPrefix, int anOffset)
{
Set list = new HashSet();
if (anOffset > 1) {
String s = findMatchingOpenTagIdentifierBefore(anOffset - 1, doc);
if (s != null) {
DTDElement element = VelocityEditor.getHTMLElement(s.toLowerCase());
if (element != null) {
DTDItem item = element.getContent();
list = new HashSet();
dumpDTDItem(item, list);
}
if (isJsp)
//
list.addAll(Arrays.asList(jspTags));
}
}
if (list.isEmpty()) {
list = null;
}
ICompletionProposal[] result = null;
Collection variables = null;
if (list != null) {
variables = list;
}
else {
variables = tagSet;
}
CompletionProposal proposal = null;
if (!variables.isEmpty()) {
List proposals = new ArrayList();
Iterator iter = variables.iterator();
while (iter.hasNext()) {
String variable = (String) iter.next();
if (variable.startsWith(aPrefix.toUpperCase())) {
String closetag = " />";
if (!emptyTagSet.contains(variable)) {
int lineOfOffset = 0;
try {
lineOfOffset = doc.getLineOfOffset(anOffset);
}
catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
closetag = " >\n" + getIndentString(getIndentOfLine(doc, lineOfOffset)) + "</" + variable + ">";
}
int compromize = 1;
String opentag = variable + closetag;
if (!VelocityPlugin.getDefault().isUppercaseEnabled())
opentag = opentag.toLowerCase();
proposal = new CompletionProposal(opentag, anOffset, aPrefix.length(), variable.length() + compromize, null, variable, null, null);
proposals.add(proposal);
}
}
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
return result;
}
/**
* Returns proposals from all directives with given prefix.
*/
private ICompletionProposal[] getDirectiveProposals(String aPrefix, int anOffset)
{
List proposals = new ArrayList();
// Add system directives
String[] directives = Directive.DIRECTIVES;
for (int i = directives.length - 1; i >= 0; i--) {
String directive = directives[i];
if (directive.substring(1).startsWith(aPrefix)) {
int cursorPos;
if ((i == Directive.TYPE_ELSE) || (i == Directive.TYPE_END) || (i == Directive.TYPE_STOP)) {
cursorPos = directive.length() - 1;
}
else {
directive += "()";
cursorPos = directive.length() - 2;
}
proposals.add(new CompletionProposal(directive.substring(1), anOffset, aPrefix.length(), cursorPos, VelocityPluginImages
.get(VelocityPluginImages.IMG_OBJ_SYSTEM_DIRECTIVE), directive, null, null));
}
}
// Add Velocity library macros
for (VelocimacroProxy vp : VelocityEditorEnvironment.getParser().getLibraryMacros())
{
String name = vp.getName();
if (name.startsWith(aPrefix))
{
String insert = name + "()";
int cursorPos;
StringBuffer buffer = new StringBuffer();
buffer.append('#');
buffer.append(name);
buffer.append('(');
if (vp.getNumArgs() == 0) {
cursorPos = insert.length();
buffer.append(')');
}
else {
cursorPos = insert.length() - 1;
for (Macro.MacroArg arg : vp.getMacroArgs())
{
buffer.append('$');
buffer.append(arg.name);
}
buffer.append(')');
}
buffer.append(" - ");
buffer.append(vp.getTemplateName());
proposals.add(new CompletionProposal(insert, anOffset, aPrefix.length(), cursorPos, VelocityPluginImages.get(VelocityPluginImages.IMG_OBJ_MACRO),
buffer.toString(), null, null));
}
}
// Add user directives
Iterator userDirectives = VelocityEditorEnvironment.getParser().getUserDirectives().iterator();
while (userDirectives.hasNext()) {
String directive = ((String) userDirectives.next());
if (directive.substring(1).startsWith(aPrefix)) {
directive += "()";
int cursorPos = directive.length() - 1;
proposals.add(new CompletionProposal(directive.substring(1), anOffset, aPrefix.length(), cursorPos, VelocityPluginImages
.get(VelocityPluginImages.IMG_OBJ_USER_DIRECTIVE), directive, null, null));
}
}
Collections.sort(proposals, proposalComparator);
return (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
}
/**
* Returns proposals from all variables with given prefix.
*/
private ICompletionProposal[] getVariableProposals(String aPrefix, int anOffset)
{
ICompletionProposal[] result = null;
List variables = fEditor.getVariables(fEditor.getLine(anOffset));
// if (!variables.isEmpty()) {
List proposals = new ArrayList();
Iterator iter = variables.iterator();
while (iter.hasNext()) {
String variable = (String) iter.next();
if (variable.substring(1).startsWith(aPrefix)) {
proposals.add(new CompletionProposal(variable.substring(1), anOffset, aPrefix.length(), variable.length() - 1, null, variable, null, null));
}
}
ICompletionProvider[] completionProviders = ProviderManager.getInstance().getProviders();
for(ICompletionProvider cp : completionProviders)
{
try
{
proposals.addAll( cp.getVariableProposals(aPrefix, anOffset));
}
catch (Exception e)
{
//noerror
}
}
Collections.sort(proposals, proposalComparator);
result = (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
// }
return result;
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer,
* int)
*/
public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset)
{
return null;
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
*/
public char[] getCompletionProposalAutoActivationCharacters()
{
return new char[] { '#', '$', '<', '/', '.' };
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
*/
public char[] getContextInformationAutoActivationCharacters()
{
return (new char[] { '>' });
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
*/
public IContextInformationValidator getContextInformationValidator()
{
return null;
}
/**
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage()
*/
public String getErrorMessage()
{
return null;
}
protected String findMatchingOpenTagIdentifierBefore(int end, IDocument doc)
{
int level = 1;
String identifier = null;
try {
char prev = '\0';
for (end--; end >= 0; end--) {
if (EditorsUtil.isInsidePartition(end, VelocityConfiguration.CDATA_PARTITIONS, true, doc)) {
end = doc.getPartition(end).getOffset() - 1;
}
else if (EditorsUtil.isInsidePartition(end,
VelocityConfiguration.ESCAPED_PARTITIONS, doc))
{
end = doc.getPartition(end).getOffset()-1;
}
char c = doc.getChar(end);
if (c == '/' && prev == '>')
level++;
if (c == '<') {
if (prev == '/') {
level++;
}
else if ((prev != '!') && (prev != '?') && (prev != '%') && (prev != '#')) {
String id = getIdentifier(doc, end + 1, doc.getLength());
// if (!fEMPTY_TAG_SET.contains(id.toUpperCase())) {
level--;
// }
if (level == 0) {
identifier = id;
return identifier;
}
}
}
else if ((c == '"') || (c == '\'')) {
end = getStringStart(doc, end, c);
}
// if(c=='/' && prev=='>') level++;
prev = c;
}
}
catch (BadLocationException e) {
}
return identifier;
}
protected String findMatchingTagIdentifierBefore(int end, IDocument doc)
{
int level = 1;
String identifier = null;
try {
char prev = '\0';
for (end--; end >= 0; end--) {
if (EditorsUtil.isInsidePartition(end, VelocityConfiguration.CDATA_PARTITIONS, true, doc)) {
end = doc.getPartition(end).getOffset() - 1;
}
else if (EditorsUtil.isInsidePartition(end, VelocityConfiguration.ESCAPED_PARTITIONS, doc)) {
end = doc.getPartition(end).getOffset();
}
char c = doc.getChar(end);
if (c == '<') {
if (prev == '/') {
level++;
}
else if ((prev != '!') && (prev != '?') && (prev != '%') && (prev != '#')) {
String id = getIdentifier(doc, end + 1, doc.getLength());
identifier = id;
return identifier;
}
}
else if ((c == '"') || (c == '\'')) {
end = getStringStart(doc, end, c);
}
prev = c;
}
}
catch (BadLocationException e) {
}
return identifier;
}
protected int getStringStart(IDocument document, int end, char quote)
{
try {
for (end--; end >= 0; end--) {
char c = document.getChar(end);
if (c == quote) {
if ((end == 0) || (document.getChar(end - 1) != '\\')) {
return end;
}
end--;
}
}
}
catch (BadLocationException e) {
}
return -1;
}
private String getIdentifier(IDocument document, int start, int end)
{
start = skipWhitespace(document, start, end);
if (start >= end) {
return "";
}
StringBuffer ret = new StringBuffer();
try {
char c = document.getChar(start++);
if (isIdentifierStart(c)) {
while (start < end) {
ret.append(c);
c = document.getChar(start++);
if (!isIdentifierChar(c)) {
break;
}
}
}
}
catch (BadLocationException e) {
}
return ret.toString();
}
private String getAttribute(IDocument document, int offset)
{
StringBuffer ret = new StringBuffer();
try {
char c = document.getChar(offset--);
if (Character.isLetter(c)) {
while ((c != ' ') && isIdentifierChar(c)) {
ret.append(c);
c = document.getChar(offset--);
}
}
}
catch (BadLocationException e) {
}
return ret.reverse().toString();
}
private int skipWhitespace(IDocument document, int start, int end)
{
try {
for (char c = document.getChar(start); (start < end) && Character.isWhitespace(c); c = document.getChar(++start)) {
}
}
catch (BadLocationException e) {
}
return start;
}
private boolean isIdentifierStart(char c)
{
return Character.isLetter(c)|| c == '!';
}
private boolean isIdentifierChar(char c)
{
return Character.isLetterOrDigit(c) || c == ':' || c == '.' || c == '-';
}
protected int getIndentOfLine(IDocument d, int line)
{
try {
if (line >= 0) {
int start = d.getLineOffset(line);
int end = (start + d.getLineLength(line)) - 1;
int whiteend = findEndOfWhiteSpace(d, start, end);
return indentWidthOf(d.get(start, whiteend - start), fTabWidth);
}
else {
return 0;
}
}
catch (Exception e) {
return 0;
}
}
/**
* DOCUMENT ME!
*
* @param str
* DOCUMENT ME!
* @param tabwidth
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static int indentWidthOf(String str, int tabwidth)
{
return indentWidthOf(str, 0, tabwidth);
}
/**
* DOCUMENT ME!
*
* @param str
* DOCUMENT ME!
* @param start
* DOCUMENT ME!
* @param tabwidth
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static int indentWidthOf(String str, int start, int tabwidth)
{
int ret = 0;
for (int len = str.length(); start < len; start++) {
char c = str.charAt(start);
if (c == '\t') {
ret = ((ret / tabwidth) + 1) * tabwidth;
continue;
}
if ((c == ' ') || (c == '\240')) {
ret++;
continue;
}
if ((c != '\n') && (c != '\r')) {
break;
}
ret = 0;
}
return ret;
}
protected int findEndOfWhiteSpace(IDocument document, int offset, int end) throws BadLocationException
{
while (offset < end) {
char c = document.getChar(offset);
if ((c != ' ') && (c != '\t')) {
return offset;
}
offset++;
}
return end;
}
protected StringBuffer getIndentString(int indent)
{
StringBuffer ret = new StringBuffer();
int n = indent / fTabWidth;
for (int i = 0; i < n; i++) {
ret.append(" ");
}
n = indent - (n * fTabWidth);
for (int i = 0; i < n; i++) {
ret.append(' ');
}
return ret;
}
protected String sameIndentAs(int matchoffset, int line, IDocument document, int actualOffset, String variable)
{
try {
int indent = getIndentOfLine(document, document.getLineOfOffset(matchoffset));
StringBuffer buf = getIndentString(indent);
int start = (line < 0) ? 0 : document.getLineOffset(line);
int whiteend = findEndOfWhiteSpace(document, start, actualOffset);
buf.append(document.get(whiteend, actualOffset - whiteend));
buf.append(variable);
return buf.toString();
}
catch (BadLocationException e) {
}
return null;
}
/**
* DOCUMENT ME!
*
* @param item
* DOCUMENT ME!
* @param list
* DOCUMENT ME!
*/
public static void dumpDTDItem(DTDItem item, Set list)
{
if (item == null) {
return;
}
else if (item instanceof DTDName) {
list.add(((DTDName) item).value.toUpperCase());
}
else if (item instanceof DTDChoice) {
DTDItem[] items = ((DTDChoice) item).getItems();
for (int i = 0; i < items.length; i++) {
dumpDTDItem(items[i], list);
}
}
else if (item instanceof DTDSequence) {
DTDItem[] items = ((DTDSequence) item).getItems();
for (int i = 0; i < items.length; i++) {
dumpDTDItem(items[i], list);
}
}
else if (item instanceof DTDMixed) {
DTDItem[] items = ((DTDMixed) item).getItems();
for (int i = 0; i < items.length; i++) {
dumpDTDItem(items[i], list);
}
}
}
/**
* DOCUMENT ME!
*
* @param attr
* DOCUMENT ME!
* @param list
* DOCUMENT ME!
*/
public static void dumpAttribute(DTDAttribute attr, Collection list)
{
if (attr.type instanceof DTDEnumeration) {
String[] items = ((DTDEnumeration) attr.type).getItems();
for (int i = 0; i < items.length; i++) {
list.add(items[i]);
}
}
else if (attr.type instanceof DTDNotationList) {
String[] items = ((DTDNotationList) attr.type).getItems();
for (int i = 0; i < items.length; i++) {
list.add(items[i]);
}
}
}
protected Template[] getTemplates(String contextTypeId)
{
return TemplateEditorUI.getDefault().getTemplateStore().getTemplates(contextTypeId);
}
/**
* Return the XML context type that is supported by this plugin.
*/
// protected ContextType getContextType(ITextViewer viewer, IRegion region)
// {
// return
// TemplateEditorUI.getDefault().getContextTypeRegistry().getContextType(VeloContextType.XML_CONTEXT_TYPE);
// }
/**
* Always return the default image.
*/
protected Image getImage(Template template)
{
ImageRegistry registry = TemplateEditorUI.getDefault().getImageRegistry();
Image image = registry.get(DEFAULT_IMAGE);
if (image == null) {
ImageDescriptor desc =
TemplateEditorUI.imageDescriptorFromPlugin( "com.liferay.ide..velocity", DEFAULT_IMAGE ); //$NON-NLS-1$
registry.put(DEFAULT_IMAGE, desc);
image = registry.get(DEFAULT_IMAGE);
}
return image;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getContextType(org.eclipse.jface.text.ITextViewer,
* org.eclipse.jface.text.IRegion)
*/
protected TemplateContextType getContextType(ITextViewer viewer, IRegion region)
{
return TemplateEditorUI.getDefault().getContextTypeRegistry().getContextType(VeloContextType.XML_CONTEXT_TYPE);
// return null;
}
}