/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/Macros.java
Java | 1021 lines | 594 code | 114 blank | 313 comment | 76 complexity | 256b4131238bbaede747bbb0be71e568 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 * Macros.java - Macro manager
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 1999, 2004 Slava Pestov
7 * Portions copyright (C) 2002 mike dillon
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 org.gjt.sp.jedit;
25
26//{{{ Imports
27import javax.swing.*;
28import java.awt.*;
29import java.io.*;
30import java.util.*;
31import java.util.regex.Pattern;
32import org.gjt.sp.jedit.msg.*;
33import org.gjt.sp.util.Log;
34//}}}
35
36/**
37 * This class records and runs macros.<p>
38 *
39 * It also contains a few methods useful for displaying output messages
40 * or obtaining input from a macro:
41 *
42 * <ul>
43 * <li>{@link #confirm(Component,String,int)}</li>
44 * <li>{@link #confirm(Component,String,int,int)}</li>
45 * <li>{@link #error(Component,String)}</li>
46 * <li>{@link #input(Component,String)}</li>
47 * <li>{@link #input(Component,String,String)}</li>
48 * <li>{@link #message(Component,String)}</li>
49 * </ul>
50 *
51 * Note that plugins should not use the above methods. Call
52 * the methods in the {@link GUIUtilities} class instead.
53 *
54 * @author Slava Pestov
55 * @version $Id: Macros.java 5443 2006-06-18 18:51:40Z vanza $
56 */
57public class Macros
58{
59 //{{{ showRunScriptDialog() method
60 /**
61 * Prompts for one or more files to run as macros
62 * @param view The view
63 * @since jEdit 4.0pre7
64 */
65 public static void showRunScriptDialog(View view)
66 {
67 String[] paths = GUIUtilities.showVFSFileDialog(view,
68 null,JFileChooser.OPEN_DIALOG,true);
69 if(paths != null)
70 {
71 Buffer buffer = view.getBuffer();
72 try
73 {
74 buffer.beginCompoundEdit();
75
76file_loop: for(int i = 0; i < paths.length; i++)
77 runScript(view,paths[i],false);
78 }
79 finally
80 {
81 buffer.endCompoundEdit();
82 }
83 }
84 } //}}}
85
86 //{{{ runScript() method
87 /**
88 * Runs the specified script.
89 * Unlike the {@link BeanShell#runScript(View,String,Reader,boolean)}
90 * method, this method can run scripts supported
91 * by any registered macro handler.
92 * @param view The view
93 * @param path The VFS path of the script
94 * @param ignoreUnknown If true, then unknown file types will be
95 * ignored; otherwise, a warning message will be printed and they will
96 * be evaluated as BeanShell scripts.
97 *
98 * @since jEdit 4.1pre2
99 */
100 public static void runScript(View view, String path, boolean ignoreUnknown)
101 {
102 Handler handler = getHandlerForPathName(path);
103 if(handler != null)
104 {
105 try
106 {
107 Macro newMacro = handler.createMacro(
108 MiscUtilities.getFileName(path), path);
109 newMacro.invoke(view);
110 }
111 catch (Exception e)
112 {
113 Log.log(Log.ERROR, Macros.class, e);
114 return;
115 }
116 return;
117 }
118
119 // only executed if above loop falls
120 // through, ie there is no handler for
121 // this file
122 if(ignoreUnknown)
123 {
124 Log.log(Log.NOTICE,Macros.class,path +
125 ": Cannot find a suitable macro handler");
126 }
127 else
128 {
129 Log.log(Log.ERROR,Macros.class,path +
130 ": Cannot find a suitable macro handler, "
131 + "assuming BeanShell");
132 getHandler("beanshell").createMacro(
133 path,path).invoke(view);
134 }
135 } //}}}
136
137 //{{{ message() method
138 /**
139 * Utility method that can be used to display a message dialog in a macro.
140 * @param comp The component to show the dialog on behalf of, this
141 * will usually be a view instance
142 * @param message The message
143 * @since jEdit 2.7pre2
144 */
145 public static void message(Component comp, String message)
146 {
147 GUIUtilities.hideSplashScreen();
148
149 JOptionPane.showMessageDialog(comp,message,
150 jEdit.getProperty("macro-message.title"),
151 JOptionPane.INFORMATION_MESSAGE);
152 } //}}}
153
154 //{{{ error() method
155 /**
156 * Utility method that can be used to display an error dialog in a macro.
157 * @param comp The component to show the dialog on behalf of, this
158 * will usually be a view instance
159 * @param message The message
160 * @since jEdit 2.7pre2
161 */
162 public static void error(Component comp, String message)
163 {
164 GUIUtilities.hideSplashScreen();
165
166 JOptionPane.showMessageDialog(comp,message,
167 jEdit.getProperty("macro-message.title"),
168 JOptionPane.ERROR_MESSAGE);
169 } //}}}
170
171 //{{{ input() method
172 /**
173 * Utility method that can be used to prompt for input in a macro.
174 * @param comp The component to show the dialog on behalf of, this
175 * will usually be a view instance
176 * @param prompt The prompt string
177 * @since jEdit 2.7pre2
178 */
179 public static String input(Component comp, String prompt)
180 {
181 GUIUtilities.hideSplashScreen();
182
183 return input(comp,prompt,null);
184 } //}}}
185
186 //{{{ input() method
187 /**
188 * Utility method that can be used to prompt for input in a macro.
189 * @param comp The component to show the dialog on behalf of, this
190 * will usually be a view instance
191 * @param prompt The prompt string
192 * @since jEdit 3.1final
193 */
194 public static String input(Component comp, String prompt, String defaultValue)
195 {
196 GUIUtilities.hideSplashScreen();
197
198 return (String)JOptionPane.showInputDialog(comp,prompt,
199 jEdit.getProperty("macro-input.title"),
200 JOptionPane.QUESTION_MESSAGE,null,null,defaultValue);
201 } //}}}
202
203 //{{{ confirm() method
204 /**
205 * Utility method that can be used to ask for confirmation in a macro.
206 * @param comp The component to show the dialog on behalf of, this
207 * will usually be a view instance
208 * @param prompt The prompt string
209 * @param buttons The buttons to display - for example,
210 * JOptionPane.YES_NO_CANCEL_OPTION
211 * @since jEdit 4.0pre2
212 */
213 public static int confirm(Component comp, String prompt, int buttons)
214 {
215 GUIUtilities.hideSplashScreen();
216
217 return JOptionPane.showConfirmDialog(comp,prompt,
218 jEdit.getProperty("macro-confirm.title"),buttons,
219 JOptionPane.QUESTION_MESSAGE);
220 } //}}}
221
222 //{{{ confirm() method
223 /**
224 * Utility method that can be used to ask for confirmation in a macro.
225 * @param comp The component to show the dialog on behalf of, this
226 * will usually be a view instance
227 * @param prompt The prompt string
228 * @param buttons The buttons to display - for example,
229 * JOptionPane.YES_NO_CANCEL_OPTION
230 * @param type The dialog type - for example,
231 * JOptionPane.WARNING_MESSAGE
232 */
233 public static int confirm(Component comp, String prompt, int buttons, int type)
234 {
235 GUIUtilities.hideSplashScreen();
236
237 return JOptionPane.showConfirmDialog(comp,prompt,
238 jEdit.getProperty("macro-confirm.title"),buttons,type);
239 } //}}}
240
241 //{{{ loadMacros() method
242 /**
243 * Rebuilds the macros list, and sends a MacrosChanged message
244 * (views update their Macros menu upon receiving it)
245 * @since jEdit 2.2pre4
246 */
247 public static void loadMacros()
248 {
249 macroActionSet.removeAllActions();
250 macroHierarchy.removeAllElements();
251 macroHash.clear();
252
253 // since subsequent macros with the same name are ignored,
254 // load user macros first so that they override the system
255 // macros.
256 String settings = jEdit.getSettingsDirectory();
257
258 if(settings != null)
259 {
260 userMacroPath = MiscUtilities.constructPath(
261 settings,"macros");
262 loadMacros(macroHierarchy,"",new File(userMacroPath));
263 }
264
265 if(jEdit.getJEditHome() != null)
266 {
267 systemMacroPath = MiscUtilities.constructPath(
268 jEdit.getJEditHome(),"macros");
269 loadMacros(macroHierarchy,"",new File(systemMacroPath));
270 }
271
272 EditBus.send(new DynamicMenuChanged("macros"));
273 } //}}}
274
275 //{{{ registerHandler() method
276 /**
277 * Adds a macro handler to the handlers list
278 * @since jEdit 4.0pre6
279 */
280 public static void registerHandler(Handler handler)
281 {
282 if (getHandler(handler.getName()) != null)
283 {
284 Log.log(Log.ERROR, Macros.class, "Cannot register more than one macro handler with the same name");
285 return;
286 }
287
288 Log.log(Log.DEBUG,Macros.class,"Registered " + handler.getName()
289 + " macro handler");
290 macroHandlers.add(handler);
291 } //}}}
292
293 //{{{ getHandlers() method
294 /**
295 * Returns an array containing the list of registered macro handlers
296 * @since jEdit 4.0pre6
297 */
298 public static Handler[] getHandlers()
299 {
300 Handler[] handlers = new Handler[macroHandlers.size()];
301 return (Handler[])macroHandlers.toArray(handlers);
302 } //}}}
303
304 //{{{ getHandlerForFileName() method
305 /**
306 * Returns the macro handler suitable for running the specified file
307 * name, or null if there is no suitable handler.
308 * @since jEdit 4.1pre3
309 */
310 public static Handler getHandlerForPathName(String pathName)
311 {
312 for (int i = 0; i < macroHandlers.size(); i++)
313 {
314 Handler handler = (Handler)macroHandlers.get(i);
315 if (handler.accept(pathName))
316 return handler;
317 }
318
319 return null;
320 } //}}}
321
322 //{{{ getHandler() method
323 /**
324 * Returns the macro handler with the specified name, or null if
325 * there is no registered handler with that name.
326 * @since jEdit 4.0pre6
327 */
328 public static Handler getHandler(String name)
329 {
330 Handler handler = null;
331 for (int i = 0; i < macroHandlers.size(); i++)
332 {
333 handler = (Handler)macroHandlers.get(i);
334 if (handler.getName().equals(name)) return handler;
335 }
336
337 return null;
338 }
339 //}}}
340
341 //{{{ getMacroHierarchy() method
342 /**
343 * Returns a vector hierarchy with all known macros in it.
344 * Each element of this vector is either a macro name string,
345 * or another vector. If it is a vector, the first element is a
346 * string label, the rest are again, either macro name strings
347 * or vectors.
348 * @since jEdit 2.6pre1
349 */
350 public static Vector getMacroHierarchy()
351 {
352 return macroHierarchy;
353 } //}}}
354
355 //{{{ getMacroActionSet() method
356 /**
357 * Returns an action set with all known macros in it.
358 * @since jEdit 4.0pre1
359 */
360 public static ActionSet getMacroActionSet()
361 {
362 return macroActionSet;
363 } //}}}
364
365 //{{{ getMacro() method
366 /**
367 * Returns the macro with the specified name.
368 * @param macro The macro's name
369 * @since jEdit 2.6pre1
370 */
371 public static Macro getMacro(String macro)
372 {
373 return (Macro)macroHash.get(macro);
374 } //}}}
375
376 //{{{ getLastMacro() method
377 /**
378 * @since jEdit 4.3pre1
379 */
380 public static Macro getLastMacro()
381 {
382 return lastMacro;
383 } //}}}
384
385 //{{{ setLastMacro() method
386 /**
387 * @since jEdit 4.3pre1
388 */
389 public static void setLastMacro(Macro macro)
390 {
391 lastMacro = macro;
392 } //}}}
393
394 //{{{ Macro class
395 /**
396 * Encapsulates the macro's label, name and path.
397 * @since jEdit 2.2pre4
398 */
399 public static class Macro extends EditAction
400 {
401 //{{{ Macro constructor
402 public Macro(Handler handler, String name, String label, String path)
403 {
404 super(name);
405 this.handler = handler;
406 this.label = label;
407 this.path = path;
408 } //}}}
409
410 //{{{ getHandler() method
411 public Handler getHandler()
412 {
413 return handler;
414 }
415 //}}}
416
417 //{{{ getPath() method
418 public String getPath()
419 {
420 return path;
421 } //}}}
422
423 //{{{ invoke() method
424 public void invoke(View view)
425 {
426 setLastMacro(this);
427
428 if(view == null)
429 handler.runMacro(null,this);
430 else
431 {
432 try
433 {
434 view.getBuffer().beginCompoundEdit();
435 handler.runMacro(view,this);
436 }
437 finally
438 {
439 view.getBuffer().endCompoundEdit();
440 }
441 }
442 } //}}}
443
444 //{{{ getCode() method
445 public String getCode()
446 {
447 return "Macros.getMacro(\"" + getName() + "\").invoke(view);";
448 } //}}}
449
450 //{{{ macroNameToLabel() method
451 public static String macroNameToLabel(String macroName)
452 {
453 int index = macroName.lastIndexOf('/');
454 return macroName.substring(index + 1).replace('_', ' ');
455 }
456 //}}}
457
458 //{{{ Private members
459 private Handler handler;
460 private String path;
461 String label;
462 //}}}
463 } //}}}
464
465 //{{{ recordTemporaryMacro() method
466 /**
467 * Starts recording a temporary macro.
468 * @param view The view
469 * @since jEdit 2.7pre2
470 */
471 public static void recordTemporaryMacro(View view)
472 {
473 String settings = jEdit.getSettingsDirectory();
474
475 if(settings == null)
476 {
477 GUIUtilities.error(view,"no-settings",new String[0]);
478 return;
479 }
480 if(view.getMacroRecorder() != null)
481 {
482 GUIUtilities.error(view,"already-recording",new String[0]);
483 return;
484 }
485
486 Buffer buffer = jEdit.openFile(null,settings + File.separator
487 + "macros","Temporary_Macro.bsh",true,null);
488
489 if(buffer == null)
490 return;
491
492 buffer.remove(0,buffer.getLength());
493 buffer.insert(0,jEdit.getProperty("macro.temp.header"));
494
495 recordMacro(view,buffer,true);
496 } //}}}
497
498 //{{{ recordMacro() method
499 /**
500 * Starts recording a macro.
501 * @param view The view
502 * @since jEdit 2.7pre2
503 */
504 public static void recordMacro(View view)
505 {
506 String settings = jEdit.getSettingsDirectory();
507
508 if(settings == null)
509 {
510 GUIUtilities.error(view,"no-settings",new String[0]);
511 return;
512 }
513
514 if(view.getMacroRecorder() != null)
515 {
516 GUIUtilities.error(view,"already-recording",new String[0]);
517 return;
518 }
519
520 String name = GUIUtilities.input(view,"record",null);
521 if(name == null)
522 return;
523
524 name = name.replace(' ','_');
525
526 Buffer buffer = jEdit.openFile(null,null,
527 MiscUtilities.constructPath(settings,"macros",
528 name + ".bsh"),true,null);
529
530 if(buffer == null)
531 return;
532
533 buffer.remove(0,buffer.getLength());
534 buffer.insert(0,jEdit.getProperty("macro.header"));
535
536 recordMacro(view,buffer,false);
537 } //}}}
538
539 //{{{ stopRecording() method
540 /**
541 * Stops a recording currently in progress.
542 * @param view The view
543 * @since jEdit 2.7pre2
544 */
545 public static void stopRecording(View view)
546 {
547 Recorder recorder = view.getMacroRecorder();
548
549 if(recorder == null)
550 GUIUtilities.error(view,"macro-not-recording",null);
551 else
552 {
553 view.setMacroRecorder(null);
554 if(!recorder.temporary)
555 view.setBuffer(recorder.buffer);
556 recorder.dispose();
557 }
558 } //}}}
559
560 //{{{ runTemporaryMacro() method
561 /**
562 * Runs the temporary macro.
563 * @param view The view
564 * @since jEdit 2.7pre2
565 */
566 public static void runTemporaryMacro(View view)
567 {
568 String settings = jEdit.getSettingsDirectory();
569
570 if(settings == null)
571 {
572 GUIUtilities.error(view,"no-settings",null);
573 return;
574 }
575
576 String path = MiscUtilities.constructPath(
577 jEdit.getSettingsDirectory(),"macros",
578 "Temporary_Macro.bsh");
579
580 if(jEdit.getBuffer(path) == null)
581 {
582 GUIUtilities.error(view,"no-temp-macro",null);
583 return;
584 }
585
586 Handler handler = getHandler("beanshell");
587 Macro temp = handler.createMacro(path,path);
588
589 Buffer buffer = view.getBuffer();
590
591 try
592 {
593 buffer.beginCompoundEdit();
594 temp.invoke(view);
595 }
596 finally
597 {
598 /* I already wrote a comment expaining this in
599 * Macro.invoke(). */
600 if(buffer.insideCompoundEdit())
601 buffer.endCompoundEdit();
602 }
603 } //}}}
604
605 //{{{ Private members
606
607 //{{{ Static variables
608 private static String systemMacroPath;
609 private static String userMacroPath;
610
611 private static ArrayList macroHandlers;
612
613 private static ActionSet macroActionSet;
614 private static Vector macroHierarchy;
615 private static Hashtable macroHash;
616
617 private static Macro lastMacro;
618 //}}}
619
620 //{{{ Class initializer
621 static
622 {
623 macroHandlers = new ArrayList();
624 registerHandler(new BeanShellHandler());
625 macroActionSet = new ActionSet(jEdit.getProperty("action-set.macros"));
626 jEdit.addActionSet(macroActionSet);
627 macroHierarchy = new Vector();
628 macroHash = new Hashtable();
629 } //}}}
630
631 //{{{ loadMacros() method
632 private static void loadMacros(Vector vector, String path, File directory)
633 {
634 lastMacro = null;
635
636 File[] macroFiles = directory.listFiles();
637 if(macroFiles == null || macroFiles.length == 0)
638 return;
639
640 for(int i = 0; i < macroFiles.length; i++)
641 {
642 File file = macroFiles[i];
643 String fileName = file.getName();
644 if(file.isHidden())
645 {
646 /* do nothing! */
647 continue;
648 }
649 else if(file.isDirectory())
650 {
651 String submenuName = fileName.replace('_',' ');
652 Vector submenu = null;
653 //{{{ try to merge with an existing menu first
654 for(int j = 0; j < vector.size(); j++)
655 {
656 Object obj = vector.get(j);
657 if(obj instanceof Vector)
658 {
659 Vector vec = (Vector)obj;
660 if(((String)vec.get(0)).equals(submenuName))
661 {
662 submenu = vec;
663 break;
664 }
665 }
666 } //}}}
667 if(submenu == null)
668 {
669 submenu = new Vector();
670 submenu.addElement(submenuName);
671 vector.addElement(submenu);
672 }
673
674 loadMacros(submenu,path + fileName + '/',file);
675 }
676 else
677 {
678 addMacro(file,path,vector);
679 }
680 }
681 } //}}}
682
683 //{{{ addMacro() method
684 private static void addMacro(File file, String path, Vector vector)
685 {
686 String fileName = file.getName();
687 Handler handler = getHandlerForPathName(file.getPath());
688
689 if(handler == null)
690 return;
691
692 try
693 {
694 // in case macro file name has a space in it.
695 // spaces break the view.toolBar property, for instance,
696 // since it uses spaces to delimit action names.
697 String macroName = (path + fileName).replace(' ','_');
698 Macro newMacro = handler.createMacro(macroName,
699 file.getPath());
700 // ignore if already added.
701 // see comment in loadMacros().
702 if(macroHash.get(newMacro.getName()) != null)
703 return;
704
705 vector.addElement(newMacro.getName());
706 jEdit.setTemporaryProperty(newMacro.getName()
707 + ".label",
708 newMacro.label);
709 jEdit.setTemporaryProperty(newMacro.getName()
710 + ".mouse-over",
711 handler.getLabel() + " - " + file.getPath());
712 macroActionSet.addAction(newMacro);
713 macroHash.put(newMacro.getName(),newMacro);
714 }
715 catch (Exception e)
716 {
717 Log.log(Log.ERROR, Macros.class, e);
718 macroHandlers.remove(handler);
719 }
720 } //}}}
721
722 //{{{ recordMacro() method
723 /**
724 * Starts recording a macro.
725 * @param view The view
726 * @param buffer The buffer to record to
727 * @param temporary True if this is a temporary macro
728 * @since jEdit 3.0pre5
729 */
730 private static void recordMacro(View view, Buffer buffer, boolean temporary)
731 {
732 view.setMacroRecorder(new Recorder(view,buffer,temporary));
733
734 // setting the message to 'null' causes the status bar to check
735 // if a recording is in progress
736 view.getStatus().setMessage(null);
737 } //}}}
738
739 //}}}
740
741 //{{{ Recorder class
742 /**
743 * Handles macro recording.
744 */
745 public static class Recorder implements EBComponent
746 {
747 View view;
748 Buffer buffer;
749 boolean temporary;
750
751 boolean lastWasInput;
752 boolean lastWasOverwrite;
753 int overwriteCount;
754
755 //{{{ Recorder constructor
756 public Recorder(View view, Buffer buffer, boolean temporary)
757 {
758 this.view = view;
759 this.buffer = buffer;
760 this.temporary = temporary;
761 EditBus.addToBus(this);
762 } //}}}
763
764 //{{{ record() method
765 public void record(String code)
766 {
767 flushInput();
768
769 append("\n");
770 append(code);
771 } //}}}
772
773 //{{{ record() method
774 public void record(int repeat, String code)
775 {
776 if(repeat == 1)
777 record(code);
778 else
779 {
780 record("for(int i = 1; i <= " + repeat + "; i++)\n"
781 + "{\n"
782 + code + "\n"
783 + "}");
784 }
785 } //}}}
786
787 //{{{ recordInput() method
788 /**
789 * @since jEdit 4.2pre5
790 */
791 public void recordInput(int repeat, char ch, boolean overwrite)
792 {
793 // record \n and \t on lines specially so that auto indent
794 // can take place
795 if(ch == '\n')
796 record(repeat,"textArea.userInput(\'\\n\');");
797 else if(ch == '\t')
798 record(repeat,"textArea.userInput(\'\\t\');");
799 else
800 {
801 StringBuffer buf = new StringBuffer();
802 for(int i = 0; i < repeat; i++)
803 buf.append(ch);
804 recordInput(buf.toString(),overwrite);
805 }
806 } //}}}
807
808 //{{{ recordInput() method
809 /**
810 * @since jEdit 4.2pre5
811 */
812 public void recordInput(String str, boolean overwrite)
813 {
814 String charStr = MiscUtilities.charsToEscapes(str);
815
816 if(overwrite)
817 {
818 if(lastWasOverwrite)
819 {
820 overwriteCount++;
821 append(charStr);
822 }
823 else
824 {
825 flushInput();
826 overwriteCount = 1;
827 lastWasOverwrite = true;
828 append("\ntextArea.setSelectedText(\"" + charStr);
829 }
830 }
831 else
832 {
833 if(lastWasInput)
834 append(charStr);
835 else
836 {
837 flushInput();
838 lastWasInput = true;
839 append("\ntextArea.setSelectedText(\"" + charStr);
840 }
841 }
842 } //}}}
843
844 //{{{ handleMessage() method
845 public void handleMessage(EBMessage msg)
846 {
847 if(msg instanceof BufferUpdate)
848 {
849 BufferUpdate bmsg = (BufferUpdate)msg;
850 if(bmsg.getWhat() == BufferUpdate.CLOSED)
851 {
852 if(bmsg.getBuffer() == buffer)
853 stopRecording(view);
854 }
855 }
856 } //}}}
857
858 //{{{ append() method
859 private void append(String str)
860 {
861 buffer.insert(buffer.getLength(),str);
862 } //}}}
863
864 //{{{ dispose() method
865 private void dispose()
866 {
867 flushInput();
868
869 for(int i = 0; i < buffer.getLineCount(); i++)
870 {
871 buffer.indentLine(i,true);
872 }
873
874 EditBus.removeFromBus(this);
875
876 // setting the message to 'null' causes the status bar to
877 // check if a recording is in progress
878 view.getStatus().setMessage(null);
879 } //}}}
880
881 //{{{ flushInput() method
882 /**
883 * We try to merge consecutive inputs. This helper method is
884 * called when something other than input is to be recorded.
885 */
886 private void flushInput()
887 {
888 if(lastWasInput)
889 {
890 lastWasInput = false;
891 append("\");");
892 }
893
894 if(lastWasOverwrite)
895 {
896 lastWasOverwrite = false;
897 append("\");\n");
898 append("offset = buffer.getLineEndOffset("
899 + "textArea.getCaretLine()) - 1;\n");
900 append("buffer.remove(textArea.getCaretPosition(),"
901 + "Math.min(" + overwriteCount
902 + ",offset - "
903 + "textArea.getCaretPosition()));");
904 }
905 } //}}}
906 } //}}}
907
908 //{{{ Handler class
909 /**
910 * Encapsulates creating and invoking macros in arbitrary scripting languages
911 * @since jEdit 4.0pre6
912 */
913 public static abstract class Handler
914 {
915 //{{{ getName() method
916 public String getName()
917 {
918 return name;
919 } //}}}
920
921 //{{{ getLabel() method
922 public String getLabel()
923 {
924 return label;
925 } //}}}
926
927 //{{{ accept() method
928 public boolean accept(String path)
929 {
930 return filter.matcher(MiscUtilities.getFileName(path)).matches();
931 } //}}}
932
933 //{{{ createMacro() method
934 public abstract Macro createMacro(String macroName, String path);
935 //}}}
936
937 //{{{ runMacro() method
938 /**
939 * Runs the specified macro.
940 * @param view The view - may be null.
941 * @param macro The macro.
942 */
943 public abstract void runMacro(View view, Macro macro);
944 //}}}
945
946 //{{{ runMacro() method
947 /**
948 * Runs the specified macro. This method is optional; it is
949 * called if the specified macro is a startup script. The
950 * default behavior is to simply call {@link #runMacro(View,Macros.Macro)}.
951 *
952 * @param view The view - may be null.
953 * @param macro The macro.
954 * @param ownNamespace A hint indicating whenever functions and
955 * variables defined in the script are to be self-contained, or
956 * made available to other scripts. The macro handler may ignore
957 * this parameter.
958 * @since jEdit 4.1pre3
959 */
960 public void runMacro(View view, Macro macro, boolean ownNamespace)
961 {
962 runMacro(view,macro);
963 } //}}}
964
965 //{{{ Handler constructor
966 protected Handler(String name)
967 {
968 this.name = name;
969 label = jEdit.getProperty("macro-handler."
970 + name + ".label", name);
971 try
972 {
973 filter = Pattern.compile(MiscUtilities.globToRE(
974 jEdit.getProperty(
975 "macro-handler." + name + ".glob")));
976 }
977 catch (Exception e)
978 {
979 throw new InternalError("Missing or invalid glob for handler " + name);
980 }
981 } //}}}
982
983 //{{{ Private members
984 private String name;
985 private String label;
986 private Pattern filter;
987 //}}}
988 } //}}}
989
990 //{{{ BeanShellHandler class
991 static class BeanShellHandler extends Handler
992 {
993 //{{{ BeanShellHandler constructor
994 BeanShellHandler()
995 {
996 super("beanshell");
997 } //}}}
998
999 //{{{ createMacro() method
1000 public Macro createMacro(String macroName, String path)
1001 {
1002 // Remove '.bsh'
1003 macroName = macroName.substring(0, macroName.length() - 4);
1004
1005 return new Macro(this, macroName,
1006 Macro.macroNameToLabel(macroName), path);
1007 } //}}}
1008
1009 //{{{ runMacro() method
1010 public void runMacro(View view, Macro macro)
1011 {
1012 BeanShell.runScript(view,macro.getPath(),null,true);
1013 } //}}}
1014
1015 //{{{ runMacro() method
1016 public void runMacro(View view, Macro macro, boolean ownNamespace)
1017 {
1018 BeanShell.runScript(view,macro.getPath(),null,ownNamespace);
1019 } //}}}
1020 } //}}}
1021}