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