PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/BeanShell.java

#
Java | 551 lines | 351 code | 69 blank | 131 comment | 55 complexity | bc20eb6a162d63b57615273e066608b4 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. * BeanShell.java - BeanShell scripting support
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2001 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import bsh.*;
  25. import javax.swing.text.Segment;
  26. import javax.swing.JFileChooser;
  27. import java.lang.reflect.InvocationTargetException;
  28. import java.io.*;
  29. import org.gjt.sp.jedit.io.*;
  30. import org.gjt.sp.jedit.gui.BeanShellErrorDialog;
  31. import org.gjt.sp.jedit.textarea.*;
  32. import org.gjt.sp.util.Log;
  33. //}}}
  34. public class BeanShell
  35. {
  36. //{{{ evalSelection() method
  37. /**
  38. * Evaluates the text selected in the specified text area.
  39. * @since jEdit 2.7pre2
  40. */
  41. public static void evalSelection(View view, JEditTextArea textArea)
  42. {
  43. String command = textArea.getSelectedText();
  44. if(command == null)
  45. {
  46. view.getToolkit().beep();
  47. return;
  48. }
  49. Object returnValue = eval(view,command,false);
  50. if(returnValue != null)
  51. textArea.setSelectedText(returnValue.toString());
  52. } //}}}
  53. //{{{ showEvaluateDialog() method
  54. /**
  55. * Prompts for a BeanShell expression to evaluate.
  56. * @since jEdit 2.7pre2
  57. */
  58. public static void showEvaluateDialog(View view)
  59. {
  60. String command = GUIUtilities.input(view,"beanshell-eval-input",null);
  61. if(command != null)
  62. {
  63. if(!command.endsWith(";"))
  64. command = command + ";";
  65. int repeat = view.getInputHandler().getRepeatCount();
  66. if(view.getMacroRecorder() != null)
  67. {
  68. view.getMacroRecorder().record(repeat,command);
  69. }
  70. Object returnValue = null;
  71. try
  72. {
  73. for(int i = 0; i < repeat; i++)
  74. {
  75. returnValue = eval(view,command,true);
  76. }
  77. }
  78. catch(Throwable t)
  79. {
  80. // BeanShell error occurred, abort execution
  81. }
  82. if(returnValue != null)
  83. {
  84. String[] args = { returnValue.toString() };
  85. GUIUtilities.message(view,"beanshell-eval",args);
  86. }
  87. }
  88. } //}}}
  89. //{{{ showEvaluateLinesDialog() method
  90. /**
  91. * Evaluates the specified script for each selected line.
  92. * @since jEdit 4.0pre1
  93. */
  94. public static void showEvaluateLinesDialog(View view)
  95. {
  96. String command = GUIUtilities.input(view,"beanshell-eval-line",null);
  97. if(command != null)
  98. {
  99. if(!command.endsWith(";"))
  100. command = command + ";";
  101. if(view.getMacroRecorder() != null)
  102. view.getMacroRecorder().record(1,command);
  103. JEditTextArea textArea = view.getTextArea();
  104. Buffer buffer = view.getBuffer();
  105. try
  106. {
  107. buffer.beginCompoundEdit();
  108. Selection[] selection = textArea.getSelection();
  109. for(int i = 0; i < selection.length; i++)
  110. {
  111. Selection s = selection[i];
  112. for(int j = s.getStartLine(); j <= s.getEndLine(); j++)
  113. {
  114. // if selection ends on the start of a
  115. // line, don't filter that line
  116. if(s.getEnd() == textArea.getLineStartOffset(j))
  117. break;
  118. global.setVariable("line",new Integer(j));
  119. global.setVariable("index",new Integer(
  120. j - s.getStartLine()));
  121. int start = s.getStart(buffer,j);
  122. int end = s.getEnd(buffer,j);
  123. String text = buffer.getText(start,
  124. end - start);
  125. global.setVariable("text",text);
  126. Object returnValue = eval(view,command,true);
  127. if(returnValue != null)
  128. {
  129. buffer.remove(start,end - start);
  130. buffer.insert(start,
  131. returnValue.toString());
  132. }
  133. }
  134. }
  135. }
  136. catch(Throwable e)
  137. {
  138. // BeanShell error occurred, abort execution
  139. }
  140. finally
  141. {
  142. buffer.endCompoundEdit();
  143. }
  144. textArea.selectNone();
  145. }
  146. } //}}}
  147. //{{{ showRunScriptDialog() method
  148. /**
  149. * Prompts for a BeanShell script to run.
  150. * @since jEdit 2.7pre2
  151. */
  152. public static void showRunScriptDialog(View view)
  153. {
  154. String[] paths = GUIUtilities.showVFSFileDialog(view,
  155. null,JFileChooser.OPEN_DIALOG,true);
  156. if(paths != null)
  157. {
  158. Buffer buffer = view.getBuffer();
  159. try
  160. {
  161. buffer.beginCompoundEdit();
  162. for(int i = 0; i < paths.length; i++)
  163. runScript(view,paths[i],true,false);
  164. }
  165. finally
  166. {
  167. buffer.endCompoundEdit();
  168. }
  169. }
  170. } //}}}
  171. //{{{ runScript() method
  172. /**
  173. * Runs a BeanShell script.
  174. * @param view The view
  175. * @param path The path name of the script. May be a jEdit VFS path
  176. * @param ownNamespace Macros are run in their own namespace, startup
  177. * scripts are run on the global namespace
  178. * @param rethrowBshErrors Rethrow BeanShell errors, in addition to
  179. * showing an error dialog box
  180. * @since jEdit 2.7pre3
  181. */
  182. public static void runScript(View view, String path,
  183. boolean ownNamespace, boolean rethrowBshErrors)
  184. {
  185. Reader in;
  186. Buffer buffer = jEdit.getBuffer(path);
  187. VFS vfs = VFSManager.getVFSForPath(path);
  188. Object session = vfs.createVFSSession(path,view);
  189. if(session == null)
  190. {
  191. // user cancelled???
  192. return;
  193. }
  194. try
  195. {
  196. if(buffer != null)
  197. {
  198. if(!buffer.isLoaded())
  199. VFSManager.waitForRequests();
  200. in = new StringReader(buffer.getText(0,
  201. buffer.getLength()));
  202. }
  203. else
  204. {
  205. in = new BufferedReader(new InputStreamReader(
  206. vfs._createInputStream(session,path,
  207. true,view)));
  208. }
  209. runScript(view,path,in,ownNamespace,rethrowBshErrors);
  210. }
  211. catch(IOException e)
  212. {
  213. Log.log(Log.ERROR,BeanShell.class,e);
  214. GUIUtilities.error(view,"read-error",
  215. new String[] { path, e.toString() });
  216. return;
  217. }
  218. finally
  219. {
  220. try
  221. {
  222. vfs._endVFSSession(session,view);
  223. }
  224. catch(IOException io)
  225. {
  226. Log.log(Log.ERROR,BeanShell.class,io);
  227. GUIUtilities.error(view,"read-error",
  228. new String[] { path, io.toString() });
  229. }
  230. }
  231. } //}}}
  232. //{{{ runScript() method
  233. /**
  234. * Runs a BeanShell script.
  235. * @param view The view
  236. * @param path For error reporting only
  237. * @param in The reader to read the script from
  238. * @param ownNamespace Macros are run in their own namespace, startup
  239. * scripts are run on the global namespace
  240. * @param rethrowBshErrors Rethrow BeanShell errors, in addition to
  241. * showing an error dialog box
  242. * @since jEdit 3.2pre4
  243. */
  244. public static void runScript(View view, String path, Reader in,
  245. boolean ownNamespace, boolean rethrowBshErrors)
  246. {
  247. Log.log(Log.MESSAGE,BeanShell.class,"Running script " + path);
  248. NameSpace namespace;
  249. if(ownNamespace)
  250. namespace = new NameSpace(global,"script namespace");
  251. else
  252. namespace = global;
  253. Interpreter interp = createInterpreter(namespace);
  254. try
  255. {
  256. if(view != null)
  257. {
  258. EditPane editPane = view.getEditPane();
  259. interp.set("view",view);
  260. interp.set("editPane",editPane);
  261. interp.set("buffer",editPane.getBuffer());
  262. interp.set("textArea",editPane.getTextArea());
  263. }
  264. running = true;
  265. interp.eval(in,namespace,path);
  266. }
  267. catch(Throwable e)
  268. {
  269. if(e instanceof TargetError)
  270. e = ((TargetError)e).getTarget();
  271. if(e instanceof InvocationTargetException)
  272. e = ((InvocationTargetException)e).getTargetException();
  273. Log.log(Log.ERROR,BeanShell.class,e);
  274. new BeanShellErrorDialog(view,e.toString());
  275. if(e instanceof Error && rethrowBshErrors)
  276. throw (Error)e;
  277. }
  278. finally
  279. {
  280. running = false;
  281. }
  282. } //}}}
  283. //{{{ eval() method
  284. /**
  285. * Evaluates the specified BeanShell expression.
  286. * @param view The view (may be null)
  287. * @param command The expression
  288. * @param rethrowBshErrors If true, BeanShell errors will
  289. * be re-thrown to the caller
  290. * @since jEdit 2.7pre3
  291. */
  292. public static Object eval(View view, String command,
  293. boolean rethrowBshErrors)
  294. {
  295. return eval(view,global,command,rethrowBshErrors);
  296. } //}}}
  297. //{{{ eval() method
  298. /**
  299. * Evaluates the specified BeanShell expression.
  300. * @param view The view (may be null)
  301. * @param namespace The namespace
  302. * @param command The expression
  303. * @param rethrowBshErrors If true, BeanShell errors will
  304. * be re-thrown to the caller
  305. * @since jEdit 3.2pre7
  306. */
  307. public static Object eval(View view, NameSpace namespace,
  308. String command, boolean rethrowBshErrors)
  309. {
  310. Interpreter interp = createInterpreter(namespace);
  311. try
  312. {
  313. if(view != null)
  314. {
  315. EditPane editPane = view.getEditPane();
  316. interp.set("view",view);
  317. interp.set("editPane",editPane);
  318. interp.set("buffer",editPane.getBuffer());
  319. interp.set("textArea",editPane.getTextArea());
  320. }
  321. return interp.eval(command);
  322. }
  323. catch(Throwable e)
  324. {
  325. if(e instanceof TargetError)
  326. e = ((TargetError)e).getTarget();
  327. if(e instanceof InvocationTargetException)
  328. e = ((InvocationTargetException)e).getTargetException();
  329. Log.log(Log.ERROR,BeanShell.class,e);
  330. new BeanShellErrorDialog(view,e.toString());
  331. if(e instanceof Error && rethrowBshErrors)
  332. throw (Error)e;
  333. }
  334. return null;
  335. } //}}}
  336. //{{{ cacheBlock() method
  337. /**
  338. * Caches a block of code, returning a handle that can be passed to
  339. * runCachedBlock().
  340. * @param id An identifier. If null, a unique identifier is generated
  341. * @param code The code
  342. * @param childNamespace If the method body should be run in a new
  343. * namespace (slightly faster). Note that you must pass a null namespace
  344. * to the runCachedBlock() method if you do this
  345. * @since jEdit 3.2pre5
  346. */
  347. public static String cacheBlock(String id, String code, boolean childNamespace)
  348. {
  349. String name;
  350. if(id == null)
  351. name = "b_" + (cachedBlockCounter++);
  352. else
  353. name = "b_" + id;
  354. code = "setNameSpace(__cruft.namespace);\n"
  355. + name
  356. + "(ns) {\n"
  357. + "setNameSpace(ns);"
  358. + code
  359. + "\n}";
  360. eval(null,code,false);
  361. return name;
  362. } //}}}
  363. //{{{ runCachedBlock() method
  364. /**
  365. * Runs a cached block of code in the specified namespace. Faster than
  366. * evaluating the block each time.
  367. * @param id The identifier returned by cacheBlock()
  368. * @param view The view
  369. * @param namespace The namespace to run the code in. Can only be null if
  370. * childNamespace parameter was true in cacheBlock() call
  371. * @since jEdit 3.2pre5
  372. */
  373. public static Object runCachedBlock(String id, View view, NameSpace namespace)
  374. {
  375. if(namespace == null)
  376. namespace = global;
  377. Object[] args = { namespace };
  378. try
  379. {
  380. if(view != null)
  381. {
  382. namespace.setVariable("view",view);
  383. EditPane editPane = view.getEditPane();
  384. namespace.setVariable("editPane",editPane);
  385. namespace.setVariable("buffer",editPane.getBuffer());
  386. namespace.setVariable("textArea",editPane.getTextArea());
  387. }
  388. Object retVal = internal.invokeMethod(id,args,interpForMethods);
  389. if(retVal instanceof Primitive)
  390. {
  391. if(retVal == Primitive.VOID)
  392. return null;
  393. else
  394. return ((Primitive)retVal).getValue();
  395. }
  396. else
  397. return retVal;
  398. }
  399. catch(Throwable e)
  400. {
  401. if(e instanceof TargetError)
  402. e = ((TargetError)e).getTarget();
  403. if(e instanceof InvocationTargetException)
  404. e = ((InvocationTargetException)e).getTargetException();
  405. Log.log(Log.ERROR,BeanShell.class,e);
  406. new BeanShellErrorDialog(view,e.toString());
  407. }
  408. finally
  409. {
  410. try
  411. {
  412. namespace.setVariable("view",null);
  413. namespace.setVariable("editPane",null);
  414. namespace.setVariable("buffer",null);
  415. namespace.setVariable("textArea",null);
  416. }
  417. catch(EvalError e)
  418. {
  419. // can't do much
  420. }
  421. }
  422. return null;
  423. } //}}}
  424. //{{{ isScriptRunning() method
  425. /**
  426. * Returns if a BeanShell script or macro is currently running.
  427. * @since jEdit 2.7pre2
  428. */
  429. public static boolean isScriptRunning()
  430. {
  431. return running;
  432. } //}}}
  433. //{{{ getNameSpace() method
  434. /**
  435. * Returns the global namespace.
  436. * @since jEdit 3.2pre5
  437. */
  438. public static NameSpace getNameSpace()
  439. {
  440. return global;
  441. } //}}}
  442. //{{{ Package-private members
  443. //{{{ init() method
  444. static void init()
  445. {
  446. Log.log(Log.DEBUG,BeanShell.class,"Initializing BeanShell"
  447. + " interpreter");
  448. BshClassManager.setClassLoader(new JARClassLoader());
  449. global = new NameSpace("jEdit embedded BeanShell Interpreter");
  450. interpForMethods = createInterpreter(global);
  451. try
  452. {
  453. Interpreter interp = createInterpreter(global);
  454. BufferedReader in = new BufferedReader(new InputStreamReader(
  455. BeanShell.class.getResourceAsStream("jedit.bsh")));
  456. interp.eval(in,global,"jedit.bsh");
  457. }
  458. catch(Throwable t)
  459. {
  460. Log.log(Log.ERROR,BeanShell.class,t);
  461. System.exit(1);
  462. }
  463. // jedit object in global namespace is set up by jedit.bsh
  464. internal = (NameSpace)eval(null,"__cruft.namespace;",false);
  465. } //}}}
  466. //}}}
  467. //{{{ Private members
  468. //{{{ Instance variables
  469. private static Interpreter interpForMethods;
  470. private static NameSpace global;
  471. private static NameSpace internal;
  472. private static boolean running;
  473. private static int cachedBlockCounter;
  474. //}}}
  475. //{{{ createInterpreter() method
  476. private static Interpreter createInterpreter(NameSpace nameSpace)
  477. {
  478. return new Interpreter(null,System.out,System.err,
  479. false,nameSpace);
  480. } //}}}
  481. //}}}
  482. }