All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.ui.autocomplete.DefaultCompletionProvider Maven / Gradle / Ivy

Go to download

AutoComplete is a library allowing you to add IDE-like auto-completion (aka "code completion" or "Intellisense") to any Swing JTextComponent. Special integration is added for RSyntaxTextArea, since this feature is commonly needed when editing source code. Features include: Drop-down completion choice list. Optional companion "description" window, complete with full HTML support and navigable with hyperlinks. Optional parameter completion assistance for functions and methods, ala Eclipse and NetBeans. Completion information is typically specified in an XML file, but can even be dynamic.

There is a newer version: 3.3.1
Show newest version
/*
 * 12/21/2008
 *
 * DefaultCompletionProvider.java - A basic completion provider implementation.
 * 
 * This library is distributed under a modified BSD license.  See the included
 * RSyntaxTextArea.License.txt file for details.
 */
package org.fife.ui.autocomplete;

import java.awt.Point;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.Segment;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;


/**
 * A basic completion provider implementation.  This provider has no
 * understanding of language semantics.  It simply checks the text entered up
 * to the caret position for a match against known completions.  This is all
 * that is needed in the majority of cases.
 *
 * @author Robert Futrell
 * @version 1.0
 */
public class DefaultCompletionProvider extends AbstractCompletionProvider {

	protected Segment seg;

	/**
	 * Used to speed up {@link #getCompletionsAt(JTextComponent, Point)}.
	 */
	private String lastCompletionsAtText;

	/**
	 * Used to speed up {@link #getCompletionsAt(JTextComponent, Point)},
	 * since this may be called multiple times in succession (this is usually
	 * called by JTextComponent.getToolTipText(), and if the user
	 * wiggles the mouse while a tool tip is displayed, this method gets
	 * repeatedly called.  It can be costly so we try to speed it up a tad).
	 */
	private List lastParameterizedCompletionsAt;

	/**
	 * Constructor.  The returned provider will not be aware of any completions.
	 *
	 * @see #addCompletion(Completion)
	 */
	public DefaultCompletionProvider() {
		init();
	}


	/**
	 * Creates a completion provider that provides completion for a simple
	 * list of words.
	 *
	 * @param words The words to offer as completion suggestions.  If this is
	 *        null, no completions will be known.
	 * @see BasicCompletion
	 */
	public DefaultCompletionProvider(String[] words) {
		init();
		addWordCompletions(words);
	}


	/**
	 * Returns the text just before the current caret position that could be
	 * the start of something auto-completable.

* * This method returns all characters before the caret that are matched * by {@link #isValidChar(char)}. * * {@inheritDoc} */ public String getAlreadyEnteredText(JTextComponent comp) { Document doc = comp.getDocument(); int dot = comp.getCaretPosition(); Element root = doc.getDefaultRootElement(); int index = root.getElementIndex(dot); Element elem = root.getElement(index); int start = elem.getStartOffset(); int len = dot-start; try { doc.getText(start, len, seg); } catch (BadLocationException ble) { ble.printStackTrace(); return EMPTY_STRING; } int segEnd = seg.offset + len; start = segEnd - 1; while (start>=seg.offset && isValidChar(seg.array[start])) { start--; } start++; len = segEnd - start; return len==0 ? EMPTY_STRING : new String(seg.array, start, len); } /** * {@inheritDoc} */ public List getCompletionsAt(JTextComponent tc, Point p) { int offset = tc.viewToModel(p); if (offset<0 || offset>=tc.getDocument().getLength()) { lastCompletionsAtText = null; return lastParameterizedCompletionsAt = null; } Segment s = new Segment(); Document doc = tc.getDocument(); Element root = doc.getDefaultRootElement(); int line = root.getElementIndex(offset); Element elem = root.getElement(line); int start = elem.getStartOffset(); int end = elem.getEndOffset() - 1; try { doc.getText(start, end-start, s); // Get the valid chars before the specified offset. int startOffs = s.offset + (offset-start) - 1; while (startOffs>=s.offset && isValidChar(s.array[startOffs])) { startOffs--; } // Get the valid chars at and after the specified offset. int endOffs = s.offset + (offset-start); while (endOffs=s.offset && Character.isWhitespace(s.array[offs])) { offs--; } int end = offs; while (offs>=s.offset && isValidChar(s.array[offs])) { offs--; } String text = new String(s.array, offs+1, end-offs); // Get a list of all Completions matching the text, but then // narrow it down to just the ParameterizedCompletions. List l = getCompletionByInputText(text); if (l!=null && !l.isEmpty()) { for (int i=0; iCharacter.isLetterOrDigit(ch) || ch=='_'". Subclasses * can override this method to change what characters are matched. * * @param ch The character. * @return Whether the character is valid. */ protected boolean isValidChar(char ch) { return Character.isLetterOrDigit(ch) || ch=='_'; } /** * Loads completions from an XML file. The XML should validate against * CompletionXml.dtd. * * @param file An XML file to load from. * @throws IOException If an IO error occurs. */ public void loadFromXML(File file) throws IOException { BufferedInputStream bin = new BufferedInputStream( new FileInputStream(file)); try { loadFromXML(bin); } finally { bin.close(); } } /** * Loads completions from an XML input stream. The XML should validate * against CompletionXml.dtd. * * @param in The input stream to read from. * @throws IOException If an IO error occurs. */ public void loadFromXML(InputStream in) throws IOException { loadFromXML(in, null); } /** * Loads completions from an XML input stream. The XML should validate * against CompletionXml.dtd. * * @param in The input stream to read from. * @param cl The class loader to use when loading any extra classes defined * in the XML, such as custom {@link FunctionCompletion}s. This * may be null if the default is to be used, or if no * custom completions are defined in the XML. * @throws IOException If an IO error occurs. */ public void loadFromXML(InputStream in, ClassLoader cl) throws IOException { //long start = System.currentTimeMillis(); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); CompletionXMLParser handler = new CompletionXMLParser(this, cl); BufferedInputStream bin = new BufferedInputStream(in); try { SAXParser saxParser = factory.newSAXParser(); saxParser.parse(bin, handler); List completions = handler.getCompletions(); addCompletions(completions); char startChar = handler.getParamStartChar(); if (startChar!=0) { char endChar = handler.getParamEndChar(); String sep = handler.getParamSeparator(); if (endChar!=0 && sep!=null && sep.length()>0) { // Sanity setParameterizedCompletionParams(startChar, sep, endChar); } } } catch (SAXException se) { throw new IOException(se.toString()); } catch (ParserConfigurationException pce) { throw new IOException(pce.toString()); } finally { //long time = System.currentTimeMillis() - start; //System.out.println("XML loaded in: " + time + "ms"); bin.close(); } } /** * Loads completions from an XML file. The XML should validate against * CompletionXml.dtd. * * @param resource A resource the current ClassLoader can get to. * @throws IOException If an IO error occurs. */ public void loadFromXML(String resource) throws IOException { ClassLoader cl = getClass().getClassLoader(); InputStream in = cl.getResourceAsStream(resource); if (in==null) { File file = new File(resource); if (file.isFile()) { in = new FileInputStream(file); } else { throw new IOException("No such resource: " + resource); } } BufferedInputStream bin = new BufferedInputStream(in); try { loadFromXML(bin); } finally { bin.close(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy