/** * Copyright (C) 2005 - 2014 Eric Van Dewoestine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.eclim.plugin.core.command.complete; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.lang.StringUtils; import org.eclim.command.CommandLine; import org.eclim.command.Options; import org.eclim.eclipse.jface.text.DummyTextViewer; import org.eclim.plugin.core.command.AbstractCommand; import org.eclim.plugin.core.command.complete.CodeCompleteResult; import org.eclim.plugin.core.util.ProjectUtils; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.source.ISourceViewer; /** * Abstract command for code completion. * * @author Eric Van Dewoestine */ public abstract class AbstractCodeCompleteCommand extends AbstractCommand { private static String COMPACT = "compact"; //private static String STANDARD = "standard"; @Override public Object execute(final CommandLine commandLine) throws Exception { String project = commandLine.getValue(Options.PROJECT_OPTION); String file = commandLine.getValue(Options.FILE_OPTION); int offset = getOffset(commandLine); List<CodeCompleteResult> results = getCompletionResults(commandLine, project, file, offset); String layout = commandLine.getValue(Options.LAYOUT_OPTION); if(COMPACT.equals(layout) && results.size() > 0){ results = compact(results); } Collections.sort(results); return getResponse(results); } protected Object getResponse(List<CodeCompleteResult> results) { return results; } /** * Gets the list of CodeCompletionResult objects. * * @param commandLine The current command line. * @param project The project name. * @param file The project relative file name. * @param offset The offset in the file. * @return The completion results. */ protected List<CodeCompleteResult> getCompletionResults( CommandLine commandLine, String project, String file, int offset) throws Exception { ICompletionProposal[] proposals = getCompletionProposals(commandLine, project, file, offset); ArrayList<CodeCompleteResult> results = new ArrayList<CodeCompleteResult>(); if(proposals != null){ for (ICompletionProposal proposal : proposals){ if(acceptProposal(proposal)){ CodeCompleteResult ccresult = createCodeCompletionResult(proposal); if(ccresult != null && !results.contains(ccresult)){ results.add(ccresult); } } } } return results; } /** * Gets the ICompletionProposal results. * * @param commandLine The current command line. * @param project The project name. * @param file The project relative file name. * @param offset The offset in the file. * @return The completion results. */ protected ICompletionProposal[] getCompletionProposals( CommandLine commandLine, String project, String file, int offset) throws Exception { IContentAssistProcessor processor = getContentAssistProcessor(commandLine, project, file); ITextViewer viewer = getTextViewer(commandLine, project, file); if (processor != null && viewer != null){ return processor.computeCompletionProposals(viewer, offset); } return new ICompletionProposal[0]; } /** * Gets the IContentAssistProcessor to use. * * @param commandLine The current command line. * @param project The project where the file is located. * @param file The file to be processed. * @return The IContentAssistProcessor. */ protected IContentAssistProcessor getContentAssistProcessor( CommandLine commandLine, String project, String file) throws Exception { throw new UnsupportedOperationException(); } /** * Gets the text viewer passed to the content assist processor. * * @param commandLine The current command line. * @param project The project the file is in. * @param file The file. * @return The ISourceViewer. */ protected ISourceViewer getTextViewer( CommandLine commandLine, String project, String file) throws Exception { int offset = getOffset(commandLine); return new DummyTextViewer( ProjectUtils.getDocument(project, file), offset, 1); } /** * Determines if the supplied proposal will be accepted as a result. * * @param proposal The ICompletionProposal. * @return true if the proposal is accepted, false otherwise. */ protected boolean acceptProposal(ICompletionProposal proposal) { return true; } /** * Constructs a new CodeCompleteResult for the supplied proposal. * * @param proposal The ICompletionProposal. * @return The CodeCompleteResult. */ protected CodeCompleteResult createCodeCompletionResult( ICompletionProposal proposal) { return new CodeCompleteResult( getCompletion(proposal), getMenu(proposal), getInfo(proposal)); } /** * Get the completion from the proposal. * * @param proposal The ICompletionProposal. * @return The completion. */ protected String getCompletion(ICompletionProposal proposal) { return proposal.getDisplayString(); } /** * Get the menu text from the proposal. * * @param proposal The ICompletionProposal. * @return The menu text. */ protected String getMenu(ICompletionProposal proposal) { return StringUtils.EMPTY; } /** * Get the info details from the proposal. * * @param proposal The ICompletionProposal. * @return The info. */ protected String getInfo(ICompletionProposal proposal) { String info = proposal.getAdditionalProposalInfo(); if(info != null){ info = info.trim(); }else{ info = StringUtils.EMPTY; } return info; } /** * Compact overloaded methods into one completion result. * * @param results The original completion results. * @return The compacted results. */ protected ArrayList<CodeCompleteResult> compact( List<CodeCompleteResult> results) { ArrayList<CodeCompleteResult> compactResults = new ArrayList<CodeCompleteResult>(); CodeCompleteResult first = results.get(0); String lastWord = first.getCompletion(); String lastType = first.getType(); ArrayList<CodeCompleteResult> overloaded = new ArrayList<CodeCompleteResult>(); for(CodeCompleteResult result : results){ if (!result.getCompletion().equals(lastWord) || !result.getType().equals(lastType)) { compactResults.add(compactOverloaded(overloaded)); overloaded.clear(); } overloaded.add(result); lastWord = result.getCompletion(); lastType = result.getType(); } if (overloaded.size() > 0){ compactResults.add(compactOverloaded(overloaded)); } return compactResults; } private CodeCompleteResult compactOverloaded( ArrayList<CodeCompleteResult> overloaded) { CodeCompleteResult r = overloaded.get(0); if (overloaded.size() == 1){ return r; } StringBuffer info = new StringBuffer(); for (CodeCompleteResult o : overloaded){ if(info.length() > 0){ info.append("<br/>"); } info.append(o.getMenu()); } return new CodeCompleteResult( r.getCompletion(), "Overloaded, see preview...", info.toString(), r.getType()); } }