| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.ui.text.completion; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.PreferenceConstants; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jface.text.contentassist.IContextInformationExtension; |
| import org.eclipse.jface.text.templates.TemplateCompletionProcessor; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| |
| /** |
| * Computes Script completion proposals and context infos. |
| */ |
| public abstract class ScriptCompletionProposalComputer extends AbstractScriptCompletionProposalComputer |
| implements IScriptCompletionProposalComputer { |
| |
| private static final class ContextInformationWrapper implements IContextInformation, IContextInformationExtension { |
| |
| private final IContextInformation fContextInformation; |
| private int fPosition; |
| |
| public ContextInformationWrapper(IContextInformation contextInformation) { |
| fContextInformation = contextInformation; |
| } |
| |
| @Override |
| public String getContextDisplayString() { |
| return fContextInformation.getContextDisplayString(); |
| } |
| |
| @Override |
| public Image getImage() { |
| return fContextInformation.getImage(); |
| } |
| |
| @Override |
| public String getInformationDisplayString() { |
| return fContextInformation.getInformationDisplayString(); |
| } |
| |
| @Override |
| public int getContextInformationPosition() { |
| return fPosition; |
| } |
| |
| public void setContextInformationPosition(int position) { |
| fPosition = position; |
| } |
| |
| @Override |
| public boolean equals(Object object) { |
| if (object instanceof ContextInformationWrapper) { |
| return fContextInformation.equals(((ContextInformationWrapper) object).fContextInformation); |
| } |
| return fContextInformation.equals(object); |
| } |
| } |
| |
| private String fErrorMessage; |
| |
| private List<IContextInformation> addContextInformations(ScriptContentAssistInvocationContext context, int offset, |
| IProgressMonitor monitor) { |
| List<ICompletionProposal> proposals = computeScriptCompletionProposals(offset, context, monitor); |
| List<IContextInformation> result = new ArrayList<>(proposals.size()); |
| |
| for (ICompletionProposal proposal : proposals) { |
| IContextInformation contextInformation = proposal.getContextInformation(); |
| if (contextInformation != null) { |
| ContextInformationWrapper wrapper = new ContextInformationWrapper(contextInformation); |
| wrapper.setContextInformationPosition(offset); |
| result.add(wrapper); |
| } |
| } |
| return result; |
| } |
| |
| private void handleCodeCompletionException(ModelException e, ScriptContentAssistInvocationContext context) { |
| ISourceModule module = context.getSourceModule(); |
| Runnable openDialog = () -> { |
| Shell shell = context.getViewer().getTextWidget().getShell(); |
| if (e.isDoesNotExist() && !module.getScriptProject().isOnBuildpath(module)) { |
| IPreferenceStore store = DLTKUIPlugin.getDefault().getPreferenceStore(); |
| boolean value = store.getBoolean(PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE); |
| if (!value) { |
| MessageDialog.openInformation(shell, |
| ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_title, |
| ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_message); |
| } |
| store.setValue(PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE, true); |
| } else { |
| ErrorDialog.openError(shell, ScriptTextMessages.CompletionProcessor_error_accessing_title, |
| ScriptTextMessages.CompletionProcessor_error_accessing_message, e.getStatus()); |
| } |
| }; |
| if (Display.getCurrent() != null) { |
| openDialog.run(); |
| } else { |
| Display.getDefault().asyncExec(openDialog); |
| } |
| } |
| |
| // Code template completion proposals for script language |
| protected List<ICompletionProposal> computeTemplateCompletionProposals(int offset, |
| ScriptContentAssistInvocationContext context, IProgressMonitor monitor) { |
| TemplateCompletionProcessor templateProcessor = createTemplateProposalComputer(context); |
| if (templateProcessor != null) { |
| ICompletionProposal[] proposals = templateProcessor.computeCompletionProposals(context.getViewer(), offset); |
| if (proposals != null && proposals.length != 0) { |
| updateTemplateProposalRelevance(context, proposals); |
| } |
| return Arrays.asList(proposals); |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| // Script language specific completion proposals like types or keywords |
| protected List<ICompletionProposal> computeScriptCompletionProposals(int offset, |
| ScriptContentAssistInvocationContext context, IProgressMonitor monitor) { |
| |
| // Source module getting |
| ISourceModule sourceModule = context.getSourceModule(); |
| if (sourceModule == null) { |
| return Collections.emptyList(); |
| } |
| |
| // Create and configure collector |
| ScriptCompletionProposalCollector collector = createCollector(context); |
| if (collector == null) { |
| return Collections.emptyList(); |
| } |
| |
| collector.setInvocationContext(context); |
| Runnable collectLength = () -> { |
| Point selection = context.getViewer().getSelectedRange(); |
| if (selection.y > 0) { |
| collector.setReplacementLength(selection.y); |
| } |
| }; |
| if (Display.getCurrent() != null) { |
| collectLength.run(); |
| } else { |
| Display.getDefault().syncExec(collectLength); |
| } |
| |
| // Filling collector with proposals |
| try { |
| if (DLTKCore.DEBUG_COMPLETION) { |
| IModelElement element = sourceModule.getElementAt(offset); |
| if (element != null) { |
| System.out.println("========= Model element: " //$NON-NLS-1$ |
| + element.getClass()); |
| } |
| } |
| int timeout = DLTKUIPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.CODEASSIST_TIMEOUT); |
| collector.startCompletion(); |
| sourceModule.codeComplete(offset, collector, timeout); |
| collector.endCompletion(); |
| } catch (ModelException e) { |
| handleCodeCompletionException(e, context); |
| } |
| |
| ICompletionProposal[] proposals = collector.getScriptCompletionProposals(); |
| |
| // Checking proposals |
| if (proposals.length == 0) { |
| String error = collector.getErrorMessage(); |
| if (error != null && error.length() > 0) { |
| fErrorMessage = error; |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| return Arrays.asList(proposals); |
| } |
| |
| public ScriptCompletionProposalComputer() { |
| } |
| |
| /* |
| * @seeorg.eclipse.jface.text.contentassist.ICompletionProposalComputer# |
| * computeContextInformation |
| * (org.eclipse.jface.text.contentassist.TextContentAssistInvocationContext, |
| * org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| /* |
| * public List computeContextInformation(ContentAssistInvocationContext context, |
| * IProgressMonitor monitor) { if (context instanceof |
| * ScriptContentAssistInvocationContext) { ScriptContentAssistInvocationContext |
| * scriptContext= (ScriptContentAssistInvocationContext) context; |
| * |
| * int contextInformationPosition= |
| * guessContextInformationPosition(scriptContext); List result= |
| * addContextInformations(scriptContext, contextInformationPosition, monitor); |
| * return result; } return Collections.EMPTY_LIST; } |
| */ |
| |
| // Completion proposals |
| @Override |
| public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context, |
| IProgressMonitor monitor) { |
| |
| if (context instanceof ScriptContentAssistInvocationContext) { |
| ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context; |
| |
| List<ICompletionProposal> proposals = new ArrayList<>(); |
| |
| // Language specific proposals (already sorted and etc.) |
| proposals.addAll(computeScriptCompletionProposals(context.getInvocationOffset(), scriptContext, monitor)); |
| |
| // Template proposals (already sorted and etc.) |
| proposals.addAll(computeTemplateCompletionProposals(context.getInvocationOffset(), scriptContext, monitor)); |
| |
| return proposals; |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| protected int guessContextInformationPosition(ContentAssistInvocationContext context) { |
| return context.getInvocationOffset(); |
| } |
| |
| @Override |
| public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context, |
| IProgressMonitor monitor) {// |
| |
| if (context instanceof ScriptContentAssistInvocationContext) { |
| ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context; |
| |
| int contextInformationPosition = guessContextInformationPosition(scriptContext); |
| List<IContextInformation> result = addContextInformations(scriptContext, contextInformationPosition, |
| monitor); |
| return result; |
| } |
| return Collections.emptyList(); |
| |
| // List types = computeCompletionProposals(context, monitor); |
| // Iterator iter = types.iterator(); |
| |
| // List list = new ArrayList(); |
| // while (iter.hasNext()) { |
| // Object o = iter |
| // .next(); |
| // if( !( o instanceof IScriptCompletionProposal ) ) { |
| // continue; |
| // } |
| // IScriptCompletionProposal proposal = (IScriptCompletionProposal) o; |
| // // System.out.println("Proposal: " + proposal + ", info: " |
| // // + proposal.getContextInformation()); |
| // // System.out.println(proposal.getClass()); |
| // list.add(proposal.getContextInformation()); |
| // } |
| // return list; |
| } |
| |
| @Override |
| public String getErrorMessage() { |
| return fErrorMessage; |
| } |
| |
| @Override |
| public void sessionStarted() { |
| } |
| |
| @Override |
| public void sessionEnded() { |
| fErrorMessage = null; |
| } |
| |
| /** |
| * Creates the template completion processor |
| * |
| * <p> |
| * Subclasses may return <code>null</code> if they do not wish to provide |
| * template support. |
| * </p> |
| */ |
| protected TemplateCompletionProcessor createTemplateProposalComputer(ScriptContentAssistInvocationContext context) { |
| return null; |
| } |
| |
| protected abstract ScriptCompletionProposalCollector createCollector(ScriptContentAssistInvocationContext context); |
| } |