001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Genady Beryozkin, me@genady.org - #getSuggestions implementation copied from HippieCompleteAction
011: *******************************************************************************/package org.eclipse.ui.texteditor;
012:
013: import java.util.ArrayList;
014: import java.util.Iterator;
015: import java.util.List;
016:
017: import org.eclipse.swt.graphics.Image;
018: import org.eclipse.swt.graphics.Point;
019:
020: import org.eclipse.jface.text.BadLocationException;
021: import org.eclipse.jface.text.DocumentEvent;
022: import org.eclipse.jface.text.IDocument;
023: import org.eclipse.jface.text.IInformationControlCreator;
024: import org.eclipse.jface.text.ITextViewer;
025: import org.eclipse.jface.text.contentassist.ICompletionProposal;
026: import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
027: import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
028: import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
029: import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
030: import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
031: import org.eclipse.jface.text.contentassist.IContextInformation;
032: import org.eclipse.jface.text.contentassist.IContextInformationValidator;
033:
034: import org.eclipse.ui.IEditorInput;
035: import org.eclipse.ui.IEditorPart;
036: import org.eclipse.ui.IEditorReference;
037: import org.eclipse.ui.IWorkbenchWindow;
038: import org.eclipse.ui.PlatformUI;
039: import org.eclipse.ui.internal.texteditor.HippieCompletionEngine;
040:
041: /**
042: * A completion proposal computer for hippie word completions.
043: * <p>
044: * Clients may instantiate.
045: * </p>
046: *
047: * @since 3.2
048: */
049: public final class HippieProposalProcessor implements
050: IContentAssistProcessor {
051:
052: private static final ICompletionProposal[] NO_PROPOSALS = new ICompletionProposal[0];
053: private static final IContextInformation[] NO_CONTEXTS = new IContextInformation[0];
054:
055: private static final class Proposal implements ICompletionProposal,
056: ICompletionProposalExtension,
057: ICompletionProposalExtension2,
058: ICompletionProposalExtension3,
059: ICompletionProposalExtension4 {
060:
061: private final String fString;
062: private final String fPrefix;
063: private final int fOffset;
064:
065: public Proposal(String string, String prefix, int offset) {
066: fString = string;
067: fPrefix = prefix;
068: fOffset = offset;
069: }
070:
071: public void apply(IDocument document) {
072: apply(null, '\0', 0, fOffset);
073: }
074:
075: public Point getSelection(IDocument document) {
076: return new Point(fOffset + fString.length(), 0);
077: }
078:
079: public String getAdditionalProposalInfo() {
080: return null;
081: }
082:
083: public String getDisplayString() {
084: return fPrefix + fString;
085: }
086:
087: public Image getImage() {
088: return null;
089: }
090:
091: public IContextInformation getContextInformation() {
092: return null;
093: }
094:
095: public void apply(IDocument document, char trigger, int offset) {
096: try {
097: String replacement = fString
098: .substring(offset - fOffset);
099: document.replace(offset, 0, replacement);
100: } catch (BadLocationException x) {
101: // TODO Auto-generated catch block
102: x.printStackTrace();
103: }
104: }
105:
106: public boolean isValidFor(IDocument document, int offset) {
107: return validate(document, offset, null);
108: }
109:
110: public char[] getTriggerCharacters() {
111: return null;
112: }
113:
114: public int getContextInformationPosition() {
115: return 0;
116: }
117:
118: public void apply(ITextViewer viewer, char trigger,
119: int stateMask, int offset) {
120: apply(viewer.getDocument(), trigger, offset);
121: }
122:
123: public void selected(ITextViewer viewer, boolean smartToggle) {
124: }
125:
126: public void unselected(ITextViewer viewer) {
127: }
128:
129: public boolean validate(IDocument document, int offset,
130: DocumentEvent event) {
131: try {
132: int prefixStart = fOffset - fPrefix.length();
133: return offset >= fOffset
134: && offset < fOffset + fString.length()
135: && document.get(prefixStart,
136: offset - (prefixStart)).equals(
137: (fPrefix + fString).substring(0, offset
138: - prefixStart));
139: } catch (BadLocationException x) {
140: return false;
141: }
142: }
143:
144: public IInformationControlCreator getInformationControlCreator() {
145: return null;
146: }
147:
148: public CharSequence getPrefixCompletionText(IDocument document,
149: int completionOffset) {
150: return fPrefix + fString;
151: }
152:
153: public int getPrefixCompletionStart(IDocument document,
154: int completionOffset) {
155: return fOffset - fPrefix.length();
156: }
157:
158: public boolean isAutoInsertable() {
159: return true;
160: }
161:
162: }
163:
164: private final HippieCompletionEngine fEngine = new HippieCompletionEngine();
165:
166: /**
167: * Creates a new hippie completion proposal computer.
168: */
169: public HippieProposalProcessor() {
170: }
171:
172: /*
173: * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
174: */
175: public ICompletionProposal[] computeCompletionProposals(
176: ITextViewer viewer, int offset) {
177: try {
178: String prefix = getPrefix(viewer, offset);
179: if (prefix == null || prefix.length() == 0)
180: return NO_PROPOSALS;
181:
182: List suggestions = getSuggestions(viewer, offset, prefix);
183:
184: List result = new ArrayList();
185: for (Iterator it = suggestions.iterator(); it.hasNext();) {
186: String string = (String) it.next();
187: if (string.length() > 0)
188: result.add(createProposal(string, prefix, offset));
189: }
190:
191: return (ICompletionProposal[]) result
192: .toArray(new ICompletionProposal[result.size()]);
193:
194: } catch (BadLocationException x) {
195: // ignore and return no proposals
196: return NO_PROPOSALS;
197: }
198: }
199:
200: private String getPrefix(ITextViewer viewer, int offset)
201: throws BadLocationException {
202: IDocument doc = viewer.getDocument();
203: if (doc == null || offset > doc.getLength())
204: return null;
205:
206: int length = 0;
207: while (--offset >= 0
208: && Character.isJavaIdentifierPart(doc.getChar(offset)))
209: length++;
210:
211: return doc.get(offset + 1, length);
212: }
213:
214: private ICompletionProposal createProposal(String string,
215: String prefix, int offset) {
216: return new Proposal(string, prefix, offset);
217: }
218:
219: /*
220: * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
221: */
222: public IContextInformation[] computeContextInformation(
223: ITextViewer viewer, int offset) {
224: // no context informations for hippie completions
225: return NO_CONTEXTS;
226: }
227:
228: /*
229: * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
230: */
231: public char[] getCompletionProposalAutoActivationCharacters() {
232: return null;
233: }
234:
235: /*
236: * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
237: */
238: public char[] getContextInformationAutoActivationCharacters() {
239: return null;
240: }
241:
242: /*
243: * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
244: */
245: public IContextInformationValidator getContextInformationValidator() {
246: return null;
247: }
248:
249: /**
250: * Return the list of suggestions from the current document. First the
251: * document is searched backwards from the caret position and then forwards.
252: *
253: * @param offset
254: * @param viewer
255: * @param prefix the completion prefix
256: * @return all possible completions that were found in the current document
257: * @throws BadLocationException if accessing the document fails
258: */
259: private ArrayList createSuggestionsFromOpenDocument(
260: ITextViewer viewer, int offset, String prefix)
261: throws BadLocationException {
262: IDocument document = viewer.getDocument();
263: ArrayList completions = new ArrayList();
264: completions.addAll(fEngine.getCompletionsBackwards(document,
265: prefix, offset));
266: completions.addAll(fEngine.getCompletionsForward(document,
267: prefix, offset - prefix.length(), true));
268:
269: return completions;
270: }
271:
272: /**
273: * Create the array of suggestions. It scans all open text editors and
274: * prefers suggestions from the currently open editor. It also adds the
275: * empty suggestion at the end.
276: *
277: * @param viewer
278: * @param offset
279: * @param prefix the prefix to search for
280: * @return the list of all possible suggestions in the currently open
281: * editors
282: * @throws BadLocationException if accessing the current document fails
283: */
284: private List getSuggestions(ITextViewer viewer, int offset,
285: String prefix) throws BadLocationException {
286:
287: ArrayList suggestions = createSuggestionsFromOpenDocument(
288: viewer, offset, prefix);
289: IDocument currentDocument = viewer.getDocument();
290:
291: IWorkbenchWindow window = PlatformUI.getWorkbench()
292: .getActiveWorkbenchWindow();
293: IEditorReference editorReferences[] = window.getActivePage()
294: .getEditorReferences();
295:
296: for (int i = 0; i < editorReferences.length; i++) {
297: IEditorPart editor = editorReferences[i].getEditor(false); // don't create!
298: if (editor instanceof ITextEditor) {
299: ITextEditor textEditor = (ITextEditor) editor;
300: IEditorInput input = textEditor.getEditorInput();
301: IDocument doc = textEditor.getDocumentProvider()
302: .getDocument(input);
303: if (!currentDocument.equals(doc))
304: suggestions.addAll(fEngine.getCompletionsForward(
305: doc, prefix, 0, false));
306: }
307: }
308: // add the empty suggestion
309: suggestions.add(""); //$NON-NLS-1$
310:
311: List uniqueSuggestions = fEngine.makeUnique(suggestions);
312:
313: return uniqueSuggestions;
314: }
315:
316: /*
317: * @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#getErrorMessage()
318: */
319: public String getErrorMessage() {
320: return null; // no custom error message
321: }
322: }
|