1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 IBM Corporation - Initial implementation
10 Klaus Hartlage - www.eclipseproject.de
11 **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.List;
18 import net.sourceforge.phpdt.internal.corext.template.ContextType;
19 import net.sourceforge.phpdt.internal.corext.template.ContextTypeRegistry;
20 import net.sourceforge.phpdt.internal.ui.text.java.IPHPCompletionProposal;
21 import net.sourceforge.phpdt.internal.ui.text.java.PHPCompletionProposalComparator;
22 import net.sourceforge.phpdt.internal.ui.text.template.BuiltInEngine;
23 import net.sourceforge.phpdt.internal.ui.text.template.IdentifierEngine;
24 import net.sourceforge.phpdt.internal.ui.text.template.TemplateEngine;
25 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
26 import net.sourceforge.phpeclipse.phpeditor.PHPContentOutlinePage;
27 import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
28 import org.eclipse.jface.text.IDocument;
29 import org.eclipse.jface.text.ITextViewer;
30 import org.eclipse.jface.text.TextPresentation;
31 import org.eclipse.jface.text.contentassist.ICompletionProposal;
32 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
33 import org.eclipse.jface.text.contentassist.IContextInformation;
34 import org.eclipse.jface.text.contentassist.IContextInformationExtension;
35 import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
36 import org.eclipse.jface.text.contentassist.IContextInformationValidator;
37 import org.eclipse.swt.graphics.Image;
38 import org.eclipse.ui.IEditorPart;
41 * Example PHP completion processor.
43 public class PHPCompletionProcessor implements IContentAssistProcessor {
46 * Simple content assist tip closer. The tip is valid in a range
47 * of 5 characters around its popup location.
49 protected static class Validator implements IContextInformationValidator, IContextInformationPresenter {
51 protected int fInstallOffset;
54 * @see IContextInformationValidator#isContextInformationValid(int)
56 public boolean isContextInformationValid(int offset) {
57 return Math.abs(fInstallOffset - offset) < 5;
61 * @see IContextInformationValidator#install(IContextInformation, ITextViewer, int)
63 public void install(IContextInformation info, ITextViewer viewer, int offset) {
64 fInstallOffset = offset;
68 * @see org.eclipse.jface.text.contentassist.IContextInformationPresenter#updatePresentation(int, TextPresentation)
70 public boolean updatePresentation(int documentPosition, TextPresentation presentation) {
75 private static class ContextInformationWrapper implements IContextInformation, IContextInformationExtension {
77 private final IContextInformation fContextInformation;
78 private int fPosition;
80 public ContextInformationWrapper(IContextInformation contextInformation) {
81 fContextInformation = contextInformation;
85 * @see IContextInformation#getContextDisplayString()
87 public String getContextDisplayString() {
88 return fContextInformation.getContextDisplayString();
92 * @see IContextInformation#getImage()
94 public Image getImage() {
95 return fContextInformation.getImage();
99 * @see IContextInformation#getInformationDisplayString()
101 public String getInformationDisplayString() {
102 return fContextInformation.getInformationDisplayString();
106 * @see IContextInformationExtension#getContextInformationPosition()
108 public int getContextInformationPosition() {
112 public void setContextInformationPosition(int position) {
113 fPosition = position;
117 // public final class VariablesCompletionProposal implements IJavaCompletionProposal {
118 // private String fDisplayString;
119 // private String fReplacementString;
120 // private int fReplacementOffset;
121 // private int fReplacementLength;
122 // private int fCursorPosition;
123 // private Image fImage;
124 // private IContextInformation fContextInformation;
125 // private String fAdditionalProposalInfo;
128 // * Creates a new completion proposal based on the provided information. The replacement string is
129 // * considered being the display string too. All remaining fields are set to <code>null</code>.
131 // * @param replacementString the actual string to be inserted into the document
132 // * @param replacementOffset the offset of the text to be replaced
133 // * @param replacementLength the length of the text to be replaced
134 // * @param cursorPosition the position of the cursor following the insert relative to replacementOffset
136 // public VariablesCompletionProposal(
137 // String replacementString,
138 // int replacementOffset,
139 // int replacementLength,
140 // int cursorPosition) {
141 // this(replacementString, replacementOffset, replacementLength, cursorPosition, null, null, null, null);
145 // * Creates a new completion proposal. All fields are initialized based on the provided information.
147 // * @param replacementString the actual string to be inserted into the document
148 // * @param replacementOffset the offset of the text to be replaced
149 // * @param replacementLength the length of the text to be replaced
150 // * @param cursorPosition the position of the cursor following the insert relative to replacementOffset
151 // * @param image the image to display for this proposal
152 // * @param displayString the string to be displayed for the proposal
153 // * @param contentInformation the context information associated with this proposal
154 // * @param additionalProposalInfo the additional information associated with this proposal
156 // public VariablesCompletionProposal(
157 // String replacementString,
158 // int replacementOffset,
159 // int replacementLength,
160 // int cursorPosition,
162 // String displayString,
163 // IContextInformation contextInformation,
164 // String additionalProposalInfo) {
165 // // Assert.isNotNull(replacementString);
166 // // Assert.isTrue(replacementOffset >= 0);
167 // // Assert.isTrue(replacementLength >= 0);
168 // // Assert.isTrue(cursorPosition >= 0);
170 // fReplacementString = replacementString;
171 // fReplacementOffset = replacementOffset;
172 // fReplacementLength = replacementLength;
173 // fCursorPosition = cursorPosition;
175 // fDisplayString = displayString;
176 // fContextInformation = contextInformation;
177 // fAdditionalProposalInfo = additionalProposalInfo;
181 // * @see ICompletionProposal#apply
183 // public void apply(IDocument document) {
185 // document.replace(fReplacementOffset, fReplacementLength, fReplacementString);
186 // } catch (BadLocationException x) {
192 // * @see ICompletionProposal#getSelection
194 // public Point getSelection(IDocument document) {
195 // return new Point(fReplacementOffset + fCursorPosition, 0);
199 // * @see ICompletionProposal#getContextInformation()
201 // public IContextInformation getContextInformation() {
202 // return fContextInformation;
206 // * @see ICompletionProposal#getImage()
208 // public Image getImage() {
213 // * @see ICompletionProposal#getDisplayString()
215 // public String getDisplayString() {
216 // if (fDisplayString != null)
217 // return fDisplayString;
218 // return fReplacementString;
222 // * @see ICompletionProposal#getAdditionalProposalInfo()
224 // public String getAdditionalProposalInfo() {
225 // return fAdditionalProposalInfo;
228 // * Returns the relevance of the proposal.
230 // public int getRelevance() {
235 protected final static String[] fgProposals = PHPFunctionNames.FUNCTION_NAMES;
237 protected IContextInformationValidator fValidator = new Validator();
238 private TemplateEngine fTemplateEngine;
239 private PHPCompletionProposalComparator fComparator;
240 private int fNumberOfComputedResults = 0;
242 public PHPCompletionProcessor() {
244 ContextType contextType = ContextTypeRegistry.getInstance().getContextType("php"); //$NON-NLS-1$
245 if (contextType != null)
246 fTemplateEngine = new TemplateEngine(contextType);
248 fComparator = new PHPCompletionProposalComparator();
251 * Method declared on IContentAssistProcessor
253 public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
254 // IDocument document = viewer.getDocument();
255 // if (documentOffset > 0) {
257 // ICompletionProposal[] result;
258 // char character = document.getChar(documentOffset - 1);
259 // if (character == '$') {
260 ////viewer. .getActivePage().getActiveEditor();
261 // result = new ICompletionProposal[fgProposals.length];
262 // for (int i = 0; i < fgProposals.length; i++) {
263 // IContextInformation info = new ContextInformation(fgProposals[i], MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.ContextInfo.pattern"), new Object[] { fgProposals[i] })); //$NON-NLS-1$
264 // result[i] = new CompletionProposal(fgProposals[i], documentOffset, 0, fgProposals[i].length(), null, fgProposals[i], info, MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.hoverinfo.pattern"), new Object[] { fgProposals[i] })); //$NON-NLS-1$
268 // } catch (BadLocationException e) {
269 // return new ICompletionProposal[0];
273 // ICompletionProposal[] result = new ICompletionProposal[fgProposals.length];
274 // for (int i = 0; i < fgProposals.length; i++) {
275 // IContextInformation info = new ContextInformation(fgProposals[i], MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.ContextInfo.pattern"), new Object[] { fgProposals[i] })); //$NON-NLS-1$
276 // result[i] = new CompletionProposal(fgProposals[i], documentOffset, 0, fgProposals[i].length(), null, fgProposals[i], info, MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.hoverinfo.pattern"), new Object[] { fgProposals[i] })); //$NON-NLS-1$
279 int contextInformationPosition = guessContextInformationPosition(viewer, documentOffset);
280 return internalComputeCompletionProposals(viewer, documentOffset, contextInformationPosition);
284 private ICompletionProposal[] internalComputeCompletionProposals(ITextViewer viewer, int offset, int contextOffset) {
285 IDocument document = viewer.getDocument();
286 Object[] identifiers = null;
289 PHPEditor editor = null;
290 PHPContentOutlinePage outlinePage = null;
292 IEditorPart targetEditor = PHPeclipsePlugin.getActiveWorkbenchWindow().getActivePage().getActiveEditor();
293 if (targetEditor != null && (targetEditor instanceof PHPEditor)) {
294 editor = (PHPEditor) targetEditor;
295 outlinePage = editor.getfOutlinePage();
296 identifiers = outlinePage.getVariables();
300 if (fTemplateEngine != null) {
301 ICompletionProposal[] results;
303 fTemplateEngine.reset();
304 fTemplateEngine.complete(viewer, offset); //, unit);
305 // } catch (JavaModelException x) {
306 // Shell shell= viewer.getTextWidget().getShell();
307 // ErrorDialog.openError(shell, JavaTextMessages.getString("CompletionProcessor.error.accessing.title"), JavaTextMessages.getString("CompletionProcessor.error.accessing.message"), x.getStatus()); //$NON-NLS-2$ //$NON-NLS-1$
310 IPHPCompletionProposal[] templateResults = fTemplateEngine.getResults();
312 IPHPCompletionProposal[] identifierResults = new IPHPCompletionProposal[0];
313 if (identifiers != null) {
314 IdentifierEngine identifierEngine;
317 // for (int i = templateResults.length; i < templateResults.length + variables.length; i++) {
318 // proposal = (String) variables[j++];
319 // IContextInformation info = new ContextInformation(proposal, MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.ContextInfo.pattern"), new Object[] { proposal })); //$NON-NLS-1$
320 // results[i] = new VariablesCompletionProposal(proposal, offset, 0, proposal.length(), null, proposal, info, MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.Proposal.hoverinfo.pattern"), new Object[] { proposal })); //$NON-NLS-1$
323 ContextType contextType = ContextTypeRegistry.getInstance().getContextType("php"); //$NON-NLS-1$
324 if (contextType != null) {
325 identifierEngine = new IdentifierEngine(contextType);
326 identifierEngine.complete(viewer, offset, identifiers);
327 identifierResults = identifierEngine.getResults();
331 IPHPCompletionProposal[] builtinResults = new IPHPCompletionProposal[0];
332 if (PHPFunctionNames.FUNCTION_NAMES != null) {
333 BuiltInEngine builtinEngine;
336 ContextType contextType = ContextTypeRegistry.getInstance().getContextType("php"); //$NON-NLS-1$
337 if (contextType != null) {
338 builtinEngine = new BuiltInEngine(contextType);
339 builtinEngine.complete(viewer, offset, PHPFunctionNames.FUNCTION_NAMES);
340 builtinResults = builtinEngine.getResults();
344 // concatenate arrays
345 IPHPCompletionProposal[] total;
346 total = new IPHPCompletionProposal[templateResults.length + identifierResults.length + builtinResults.length];
347 System.arraycopy(templateResults, 0, total, 0, templateResults.length);
348 System.arraycopy(identifierResults, 0, total, templateResults.length, identifierResults.length);
349 System.arraycopy(builtinResults, 0, total, templateResults.length + identifierResults.length, builtinResults.length);
352 fNumberOfComputedResults = (results == null ? 0 : results.length);
354 * Order here and not in result collector to make sure that the order
355 * applies to all proposals and not just those of the compilation unit.
357 return order(results);
359 return new IPHPCompletionProposal[0];
362 private int guessContextInformationPosition(ITextViewer viewer, int offset) {
363 int contextPosition = offset;
365 IDocument document = viewer.getDocument();
369 // JavaCodeReader reader= new JavaCodeReader();
370 // reader.configureBackwardReader(document, offset, true, true);
372 // int nestingLevel= 0;
374 // int curr= reader.read();
375 // while (curr != JavaCodeReader.EOF) {
377 // if (')' == (char) curr)
380 // else if ('(' == (char) curr) {
383 // if (nestingLevel < 0) {
384 // int start= reader.getOffset();
385 // if (looksLikeMethod(reader))
390 // curr= reader.read();
392 // } catch (IOException e) {
395 return contextPosition;
399 * Method declared on IContentAssistProcessor
401 // public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
402 // IContextInformation[] result = new IContextInformation[5];
403 // for (int i = 0; i < result.length; i++)
404 // result[i] = new ContextInformation(MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.ContextInfo.display.pattern"), new Object[] { new Integer(i), new Integer(documentOffset)}), //$NON-NLS-1$
405 // MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.ContextInfo.value.pattern"), new Object[] { new Integer(i), new Integer(documentOffset - 5), new Integer(documentOffset + 5)})); //$NON-NLS-1$
409 * @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
411 public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
412 int contextInformationPosition = guessContextInformationPosition(viewer, offset);
413 List result = addContextInformations(viewer, contextInformationPosition);
414 return (IContextInformation[]) result.toArray(new IContextInformation[result.size()]);
417 private List addContextInformations(ITextViewer viewer, int offset) {
418 ICompletionProposal[] proposals = internalComputeCompletionProposals(viewer, offset, -1);
420 List result = new ArrayList();
421 for (int i = 0; i < proposals.length; i++) {
422 IContextInformation contextInformation = proposals[i].getContextInformation();
423 if (contextInformation != null) {
424 ContextInformationWrapper wrapper = new ContextInformationWrapper(contextInformation);
425 wrapper.setContextInformationPosition(offset);
433 * Order the given proposals.
435 private ICompletionProposal[] order(ICompletionProposal[] proposals) {
436 Arrays.sort(proposals, fComparator);
441 * Method declared on IContentAssistProcessor
443 public char[] getCompletionProposalAutoActivationCharacters() {
444 return null; // new char[] { '$' };
448 * Method declared on IContentAssistProcessor
450 public char[] getContextInformationAutoActivationCharacters() {
456 * Method declared on IContentAssistProcessor
458 public IContextInformationValidator getContextInformationValidator() {
463 * Method declared on IContentAssistProcessor
465 public String getErrorMessage() {