/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * 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: * Andreas Sewe - initial API and implementation. */ package org.eclipse.recommenders.internal.snipmatch.rcp.completion; import static java.text.MessageFormat.format; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.SystemUtils.LINE_SEPARATOR; import static org.eclipse.recommenders.internal.snipmatch.rcp.l10n.LogMessages.ERROR_SNIPPET_COULD_NOT_BE_EVALUATED; import static org.eclipse.recommenders.utils.Logs.log; import org.eclipse.jdt.internal.corext.template.java.JavaContext; import org.eclipse.jdt.internal.ui.javaeditor.IndentUtil; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6; import org.eclipse.jface.text.source.LineRange; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateException; import org.eclipse.jface.text.templates.TemplateProposal; import org.eclipse.jface.viewers.StyledString; import org.eclipse.recommenders.internal.snipmatch.rcp.SnippetProposals; import org.eclipse.recommenders.internal.snipmatch.rcp.l10n.Messages; import org.eclipse.recommenders.snipmatch.ISnippet; import org.eclipse.recommenders.utils.Recommendation; import org.eclipse.swt.graphics.Image; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.collect.Ordering; @SuppressWarnings("restriction") public final class SnippetProposal extends TemplateProposal implements ICompletionProposalExtension6 { private final ISnippet snippet; private final int repositoryRelevance; private TemplateContext context; private Boolean valid = null; public static SnippetProposal newSnippetProposal(Recommendation<ISnippet> recommendation, int repositoryRelevance, Template template, TemplateContext context, IRegion region, Image image) throws BadLocationException, TemplateException { int relevance = (int) (recommendation.getRelevance() * 100); return new SnippetProposal(recommendation.getProposal(), relevance, repositoryRelevance, template, context, region, image); } private SnippetProposal(ISnippet snippet, int relevance, int repositoryRelevance, Template template, TemplateContext context, IRegion region, Image image) { super(template, context, region, image, relevance); this.repositoryRelevance = repositoryRelevance; this.context = context; this.snippet = snippet; } @Override public boolean isValidFor(IDocument document, int offset) { return isValid(); } private boolean isValid() { if (valid != null) { return valid; } valid = false; try { context.evaluate(getTemplate()); valid = true; } catch (Exception e) { context = new JavaContext(context.getContextType(), new Document(), new Position(0), null); try { context.evaluate(getTemplate()); } catch (Exception e1) { log(ERROR_SNIPPET_COULD_NOT_BE_EVALUATED, e, snippet.getName(), snippet.getUuid()); return false; } } return valid; } @Override public String getAdditionalProposalInfo() { StringBuilder header = new StringBuilder(); if (!isValid()) { header.append(format(Messages.WARNING_CANNOT_APPLY_SNIPPET, "// XXX")); //$NON-NLS-1$ header.append(LINE_SEPARATOR); header.append(format(Messages.WARNING_REPOSITION_CURSOR, "// TODO")); //$NON-NLS-1$ header.append(LINE_SEPARATOR); header.append(LINE_SEPARATOR); } if (!isEmpty(snippet.getDescription())) { header.append("// "); //$NON-NLS-1$ header.append(snippet.getDescription()); header.append(LINE_SEPARATOR); } try { // Header comments *must* not be included in fixIndentation due to Bug 436490. return header + fixIndentation(super.getAdditionalProposalInfo()); } catch (BadLocationException e) { return null; } } private String fixIndentation(String additionalProposalInfo) throws BadLocationException { IDocument document = new Document(additionalProposalInfo); IndentUtil.indentLines(document, new LineRange(0, document.getNumberOfLines()), null, null); return document.get(); } @Override public StyledString getStyledDisplayString() { StyledString styledString = new StyledString(); styledString.append(SnippetProposals.createDisplayString(snippet)); if (!snippet.getTags().isEmpty()) { styledString.append(" - ", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ styledString.append(Joiner.on(", ").join(Ordering.natural().sortedCopy(snippet.getTags())), //$NON-NLS-1$ StyledString.COUNTER_STYLER); } return styledString; } @Override public String getDisplayString() { return getStyledDisplayString().getString(); } public ISnippet getSnippet() { return snippet; } public int getRepositoryRelevance() { return repositoryRelevance; } @VisibleForTesting public TemplateContext getTemplateContext() { return context; } }