PageRenderTime 246ms CodeModel.GetById 73ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/SideKick/sidekick/SideKickParser.java

#
Java | 298 lines | 101 code | 27 blank | 170 comment | 12 complexity | fb4f3021eab64e6367f8d51a45be26b1 MD5 | raw file
  1/*
  2* SideKickParser.java
  3* :tabSize=8:indentSize=8:noTabs=false:
  4* :folding=explicit:collapseFolds=1:
  5*
  6* Copyright 2003 Slava Pestov
  7*           2005 Robert McKinnon
  8*
  9* This program is free software; you can redistribute it and/or
 10* modify it under the terms of the GNU General Public License
 11* as published by the Free Software Foundation; either version 2
 12* of the License, or any later version.
 13*
 14* This program is distributed in the hope that it will be useful,
 15* but WITHOUT ANY WARRANTY; without even the implied warranty of
 16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17* GNU General Public License for more details.
 18*
 19* You should have received a copy of the GNU General Public License
 20* along with this program; if not, write to the Free Software
 21* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 22*/
 23
 24package sidekick;
 25
 26//{{{ Imports
 27import java.util.*;
 28
 29import javax.swing.JPanel;
 30
 31import org.gjt.sp.jedit.*;
 32
 33import errorlist.DefaultErrorSource;
 34import org.gjt.sp.util.Log;
 35
 36//}}}
 37
 38/**
 39 * An abstract base class for plugin-provided parser implementations.<p>
 40 *
 41 * Plugins can provide SideKick parsers by defining entries in their
 42 * <code>services.xml</code> files like so:
 43 *
 44 * <pre>&lt;SERVICE CLASS="sidekick.SideKickParser" NAME="<i>name</i>"&gt;
 45 *    new <i>MyParser<i>();
 46 *&lt;/SERVICE&gt;</pre>
 47 *
 48 * See <code>org.gjt.sp.jedit.ServiceManager</code> for details.<p>
 49 *
 50 * Note that each <code>SideKickParser</code> subclass has a name which is
 51 * used to key a property <code>sidekick.parser.<i>name</i>.label</code>.<p>
 52 *
 53 * To associate a parser with some edit modes, define properties like this:
 54 * <pre>mode.scheme.sidekick.parser=lisp
 55 *mode.lisp.sidekick.parser=lisp</pre>
 56 *
 57 * @version $Id: SideKickParser.java 14895 2009-04-07 17:13:26Z shlomy $
 58 * @author Slava Pestov
 59 */
 60public abstract class SideKickParser {
 61	public static final String SERVICE = "sidekick.SideKickParser";
 62
 63	//{{{ SideKickParser constructor
 64	/**
 65	 * The parser constructor.
 66	 *
 67	 */
 68	public SideKickParser( String serviceName ) {
 69		this.name = serviceName;
 70	} //}}}
 71
 72	//{{{ getName() method
 73	/**
 74	 * Returns the parser's name.
 75	 */
 76	public final String getName() {
 77		return name;
 78	} //}}}
 79
 80	//{{{ stop() method
 81	/**
 82	 * Stops the parse request currently in progress. It is up to the
 83	 * parser to implement this.
 84	 * @since SideKick 0.3
 85	 */
 86	public void stop() {} //}}}
 87
 88	//{{{ activate() method
 89	/**
 90	 * This method is called when a buffer using this parser is selected
 91	 * in the specified view.
 92	 * @param view The view
 93	 * @since SideKick 0.2
 94	 * @deprecated Use the form taking an <code>EditPane</code> instead.
 95	 */
 96	public void activate( View view ) {} //}}}
 97
 98	//{{{ deactivate() method
 99	/**
100	 * This method is called when a buffer using this parser is no longer
101	 * selected in the specified view.
102	 * @param view The view
103	 * @since SideKick 0.2
104	 * @deprecated Use the form taking an <code>EditPane</code> instead.
105	 */
106	public void deactivate( View view ) {} //}}}
107
108	//{{{ activate() method
109	/**
110	 * This method is called when a buffer using this parser is selected
111	 * in the specified view.
112	 * @param editPane The edit pane
113	 * @since SideKick 0.3.1
114	 */
115	public void activate( EditPane editPane ) {
116		activate( editPane.getView() );
117		Log.log( Log.DEBUG, this, getName() + ": activated for " + editPane.getBuffer() );
118	} //}}}
119
120	//{{{ deactivate() method
121	/**
122	 * This method is called when a buffer using this parser is no longer
123	 * selected in the specified view.
124	 * @param editPane The edit pane
125	 * @since SideKick 0.3.1
126	 */
127	public void deactivate( EditPane editPane ) {
128		deactivate( editPane.getView() );
129		Log.log( Log.DEBUG, this, getName() + ": deactivated" );
130	} //}}}
131
132	//{{{ parse() method
133	/**
134	 * Parses the given text and returns a tree model.
135	 *
136	 * @param buffer The buffer to parse.
137	 * @param errorSource An error source to add errors to.
138	 *
139	 * @return A new instance of the <code>SideKickParsedData</code> class.
140	 */
141	public abstract SideKickParsedData parse( Buffer buffer,
142			DefaultErrorSource errorSource );
143	//}}}
144
145	//{{{ supportsCompletion() method
146	/**
147	 * Returns if the parser supports code completion.
148	 *
149	 * Returns false by default.
150	 */
151	public boolean supportsCompletion() {
152		return true;
153	} //}}}
154
155	//{{{ canHandleBackspace() method
156	/**
157	    * <p>
158	 * Returns true if the parser can handle
159	    * the backspace key being typed when
160	    * the completion popup is open,
161	    * else false if not.
162	    * </p><p>
163	    * If false, the completion popup is
164	    * closed when backspace is typed.
165	 * </p><p>
166	    * If true, the
167	    * {@link SideKickCompletion#handleKeystroke(int, char)}
168	    * method must be overidden to handle receiving
169	    * the backspace character, '\b', as a value
170	    * for the keyChar parameter.
171	    * </p><p>
172	 * Returns false by default.
173	    * </p>
174	    * @since SideKick 0.3.4
175	 */
176	public boolean canHandleBackspace() {
177		return false;
178	} //}}}
179
180	//{{{ canCompleteAnywhere() method
181	/**
182	 * Returns if completion popups should be shown after any period of
183	 * inactivity. Otherwise, they are only shown if explicitly requested
184	 * by the user.
185	 *
186	 * Returns true by default.
187	 */
188	public boolean canCompleteAnywhere() {
189		return true;
190	} //}}}
191
192	//{{{ getInstantCompletionTriggers() method
193	/**
194	 * Returns a list of characters which trigger completion immediately.
195	 *
196	 * Returns null by default.
197	 *
198	 */
199	public String getInstantCompletionTriggers() {
200		return null;
201	} //}}}
202
203	//{{{ getParseTriggers() method
204	/**
205	 * Returns a list of characters which trigger a buffer re-parse.
206	 *
207	 * Returns null by default.
208	 * @since SideKick 0.3
209	 *
210	 */
211	public String getParseTriggers() {
212		return null;
213	} //}}}
214
215	//{{{ complete() method
216	/**
217	 * Returns completions suitable for insertion at the specified position.
218	 *
219	 * Returns null by default.
220	 *
221	 * @param editPane The edit pane involved.
222	 * @param caret The caret position.
223	 */
224	public SideKickCompletion complete( EditPane editPane, int caret ) {
225		try {
226			String[] keywords = editPane.getBuffer().getKeywordMapAtOffset(caret).getKeywords();
227			if (keywords.length > 0) {
228				String word = getWordAtCaret( editPane, caret );
229				if (word != null && word.length() > 0) {
230					List possibles = new ArrayList();
231					for (int i = 0; i < keywords.length; i++) {
232						String kw = keywords[i];
233						if (kw.startsWith(word) && !kw.equals(word)) {
234							possibles.add(keywords[i]);
235						}
236					}
237					Collections.sort(possibles);
238					return new ConcreteSideKickCompletion(editPane.getView(), word, possibles);
239				}
240			}
241		}
242		catch ( Exception e ) {
243		}
244		return null;
245	} //}}}
246
247	//{{{ getCompletionPopup() method
248	public SideKickCompletionPopup getCompletionPopup(View view, 
249		int caretPosition, SideKickCompletion complete, boolean active)
250	{
251		return new SideKickCompletionPopup(view, this, caretPosition,
252			complete, active);
253	} //}}}
254
255	//{{{ getPanel() method
256	/**
257	 * Returns a parser-specific panel that will be shown in the SideKick dockable
258	 * window just below the SideKick toolbar. This panel is meant to be a toolbar,
259	 * but can be another UI element if needed.
260	 *
261	 * Returns null by default.
262	 * @since SideKick 0.7.4
263	 */
264	public JPanel getPanel() {
265		return null;
266	} //}}}
267
268	private String getWordAtCaret( EditPane editPane, int caret ) {
269		if ( caret <= 0 ) {
270			return "";
271		}
272		Buffer buffer = editPane.getBuffer();
273		String text = buffer.getText(0, caret);
274		Mode mode = buffer.getMode();
275		String word_break_chars = ( String ) mode.getProperty( "wordBreakChars" );
276		if ( word_break_chars == null ) {
277			word_break_chars = "";
278		}
279		word_break_chars += " \n\r\t";
280		int offset = 0;
281		for (int i = 0; i < word_break_chars.length(); i++) {
282			int maybe = text.lastIndexOf(word_break_chars.charAt(i)) + 1;
283			if (maybe > offset) {
284				offset = maybe;
285			}
286		}
287		return text.substring(offset);
288	}
289
290	class ConcreteSideKickCompletion extends SideKickCompletion {
291		public ConcreteSideKickCompletion(View view, String word, List possibles) {
292			super(view, word, possibles);
293		}
294	}
295
296
297	protected String name;
298}