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