PageRenderTime 150ms CodeModel.GetById 40ms app.highlight 63ms RepoModel.GetById 38ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/Macros.java

#
Java | 927 lines | 534 code | 106 blank | 287 comment | 70 complexity | da8b944241c77de83dc35cdd2eacadc7 MD5 | raw file
  1/*
  2 * Macros.java - Macro manager
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 2003 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 gnu.regexp.RE;
 28import javax.swing.*;
 29import java.awt.*;
 30import java.io.*;
 31import java.util.*;
 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 4743 2003-05-29 19:52:42Z spestov $
 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		if(jEdit.getJEditHome() != null)
254		{
255			systemMacroPath = MiscUtilities.constructPath(
256				jEdit.getJEditHome(),"macros");
257			loadMacros(macroHierarchy,"",new File(systemMacroPath));
258		}
259
260		String settings = jEdit.getSettingsDirectory();
261
262		if(settings != null)
263		{
264			userMacroPath = MiscUtilities.constructPath(
265				settings,"macros");
266			loadMacros(macroHierarchy,"",new File(userMacroPath));
267		}
268
269		EditBus.send(new DynamicMenuChanged("macros"));
270	} //}}}
271
272	//{{{ registerHandler() method
273	/**
274	 * Adds a macro handler to the handlers list
275	 * @since jEdit 4.0pre6
276	 */
277	public static void registerHandler(Handler handler)
278	{
279		if (getHandler(handler.getName()) != null)
280		{
281			Log.log(Log.ERROR, Macros.class, "Cannot register more than one macro handler with the same name");
282			return;
283		}
284
285		Log.log(Log.DEBUG,Macros.class,"Registered " + handler.getName()
286			+ " macro handler");
287		macroHandlers.add(handler);
288	} //}}}
289
290	//{{{ getHandlers() method
291	/**
292	 * Returns an array containing the list of registered macro handlers
293	 * @since jEdit 4.0pre6
294	 */
295	public static Handler[] getHandlers()
296	{
297		Handler[] handlers = new Handler[macroHandlers.size()];
298		return (Handler[])macroHandlers.toArray(handlers);
299	} //}}}
300
301	//{{{ getHandlerForFileName() method
302	/**
303	 * Returns the macro handler suitable for running the specified file
304	 * name, or null if there is no suitable handler.
305	 * @since jEdit 4.1pre3
306	 */
307	public static Handler getHandlerForPathName(String pathName)
308	{
309		for (int i = 0; i < macroHandlers.size(); i++)
310		{
311			Handler handler = (Handler)macroHandlers.get(i);
312			if (handler.accept(pathName))
313				return handler;
314		}
315
316		return null;
317	} //}}}
318
319	//{{{ getHandler() method
320	/**
321	 * Returns the macro handler with the specified name, or null if
322	 * there is no registered handler with that name.
323	 * @since jEdit 4.0pre6
324	 */
325	public static Handler getHandler(String name)
326	{
327		Handler handler = null;
328		for (int i = 0; i < macroHandlers.size(); i++)
329		{
330			handler = (Handler)macroHandlers.get(i);
331			if (handler.getName().equals(name)) return handler;
332		}
333
334		return null;
335	}
336	//}}}
337
338	//{{{ getMacroHierarchy() method
339	/**
340	 * Returns a vector hierarchy with all known macros in it.
341	 * Each element of this vector is either a macro name string,
342	 * or another vector. If it is a vector, the first element is a
343	 * string label, the rest are again, either macro name strings
344	 * or vectors.
345	 * @since jEdit 2.6pre1
346	 */
347	public static Vector getMacroHierarchy()
348	{
349		return macroHierarchy;
350	} //}}}
351
352	//{{{ getMacroActionSet() method
353	/**
354	 * Returns an action set with all known macros in it.
355	 * @since jEdit 4.0pre1
356	 */
357	public static ActionSet getMacroActionSet()
358	{
359		return macroActionSet;
360	} //}}}
361
362	//{{{ getMacro() method
363	/**
364	 * Returns the macro with the specified name.
365	 * @param macro The macro's name
366	 * @since jEdit 2.6pre1
367	 */
368	public static Macro getMacro(String macro)
369	{
370		return (Macro)macroHash.get(macro);
371	} //}}}
372
373	//{{{ Macro class
374	/**
375	 * Encapsulates the macro's label, name and path.
376	 * @since jEdit 2.2pre4
377	 */
378	public static class Macro extends EditAction
379	{
380		//{{{ Macro constructor
381		public Macro(Handler handler, String name, String label, String path)
382		{
383			// in case macro file name has a space in it.
384			// spaces break the view.toolBar property, for instance,
385			// since it uses spaces to delimit action names.
386			super(name.replace(' ','_'));
387			this.handler = handler;
388			this.label = label;
389			this.path = path;
390
391			jEdit.setTemporaryProperty(getName() + ".label",label);
392			jEdit.setTemporaryProperty(getName() + ".mouse-over",
393				handler.getLabel() + " - " + path);
394		} //}}}
395
396		//{{{ getHandler() method
397		public Handler getHandler()
398		{
399			return handler;
400		}
401		//}}}
402
403		//{{{ getPath() method
404		public String getPath()
405		{
406			return path;
407		} //}}}
408
409		//{{{ invoke() method
410		public void invoke(View view)
411		{
412			if(view == null)
413				handler.runMacro(null,this);
414			else
415			{
416				Buffer buffer = view.getBuffer();
417
418				try
419				{
420					buffer.beginCompoundEdit();
421					handler.runMacro(view,this);
422				}
423				finally
424				{
425					buffer.endCompoundEdit();
426				}
427			}
428		} //}}}
429
430		//{{{ getCode() method
431		public String getCode()
432		{
433			return "Macros.getMacro(\"" + getName() + "\").invoke(view);";
434		} //}}}
435
436		//{{{ macroNameToLabel() method
437		public static String macroNameToLabel(String macroName)
438		{
439			int index = macroName.lastIndexOf('/');
440			return macroName.substring(index + 1).replace('_', ' ');
441		}
442		//}}}
443
444		//{{{ Private members
445		private Handler handler;
446		private String path;
447		private String label;
448		//}}}
449	} //}}}
450
451	//{{{ recordTemporaryMacro() method
452	/**
453	 * Starts recording a temporary macro.
454	 * @param view The view
455	 * @since jEdit 2.7pre2
456	 */
457	public static void recordTemporaryMacro(View view)
458	{
459		String settings = jEdit.getSettingsDirectory();
460
461		if(settings == null)
462		{
463			GUIUtilities.error(view,"no-settings",new String[0]);
464			return;
465		}
466		if(view.getMacroRecorder() != null)
467		{
468			GUIUtilities.error(view,"already-recording",new String[0]);
469			return;
470		}
471
472		Buffer buffer = jEdit.openFile(null,settings + File.separator
473			+ "macros","Temporary_Macro.bsh",true,null);
474
475		if(buffer == null)
476			return;
477
478		buffer.remove(0,buffer.getLength());
479		buffer.insert(0,jEdit.getProperty("macro.temp.header"));
480
481		recordMacro(view,buffer,true);
482	} //}}}
483
484	//{{{ recordMacro() method
485	/**
486	 * Starts recording a macro.
487	 * @param view The view
488	 * @since jEdit 2.7pre2
489	 */
490	public static void recordMacro(View view)
491	{
492		String settings = jEdit.getSettingsDirectory();
493
494		if(settings == null)
495		{
496			GUIUtilities.error(view,"no-settings",new String[0]);
497			return;
498		}
499
500		if(view.getMacroRecorder() != null)
501		{
502			GUIUtilities.error(view,"already-recording",new String[0]);
503			return;
504		}
505
506		String name = GUIUtilities.input(view,"record",null);
507		if(name == null)
508			return;
509
510		name = name.replace(' ','_');
511
512		Buffer buffer = jEdit.openFile(null,null,
513			MiscUtilities.constructPath(settings,"macros",
514			name + ".bsh"),true,null);
515
516		if(buffer == null)
517			return;
518
519		buffer.remove(0,buffer.getLength());
520		buffer.insert(0,jEdit.getProperty("macro.header"));
521
522		recordMacro(view,buffer,false);
523	} //}}}
524
525	//{{{ stopRecording() method
526	/**
527	 * Stops a recording currently in progress.
528	 * @param view The view
529	 * @since jEdit 2.7pre2
530	 */
531	public static void stopRecording(View view)
532	{
533		Recorder recorder = view.getMacroRecorder();
534
535		if(recorder == null)
536			GUIUtilities.error(view,"macro-not-recording",null);
537		else
538		{
539			view.setMacroRecorder(null);
540			if(!recorder.temporary)
541				view.setBuffer(recorder.buffer);
542			recorder.dispose();
543		}
544	} //}}}
545
546	//{{{ runTemporaryMacro() method
547	/**
548	 * Runs the temporary macro.
549	 * @param view The view
550	 * @since jEdit 2.7pre2
551	 */
552	public static void runTemporaryMacro(View view)
553	{
554		String settings = jEdit.getSettingsDirectory();
555
556		if(settings == null)
557		{
558			GUIUtilities.error(view,"no-settings",new String[0]);
559			return;
560		}
561
562		String path = MiscUtilities.constructPath(
563			jEdit.getSettingsDirectory(),"macros",
564			"Temporary_Macro.bsh");
565
566		Handler handler = getHandler("beanshell");
567		Macro temp = handler.createMacro(path,path);
568
569		Buffer buffer = view.getBuffer();
570
571		try
572		{
573			buffer.beginCompoundEdit();
574			temp.invoke(view);
575		}
576		finally
577		{
578			/* I already wrote a comment expaining this in
579			 * Macro.invoke(). */
580			if(buffer.insideCompoundEdit())
581				buffer.endCompoundEdit();
582		}
583	} //}}}
584
585	//{{{ Private members
586
587	//{{{ Static variables
588	private static String systemMacroPath;
589	private static String userMacroPath;
590
591	private static ArrayList macroHandlers;
592
593	private static ActionSet macroActionSet;
594	private static Vector macroHierarchy;
595	private static Hashtable macroHash;
596	//}}}
597
598	//{{{ Class initializer
599	static
600	{
601		macroHandlers = new ArrayList();
602		registerHandler(new BeanShellHandler());
603		macroActionSet = new ActionSet(jEdit.getProperty("action-set.macros"));
604		jEdit.addActionSet(macroActionSet);
605		macroHierarchy = new Vector();
606		macroHash = new Hashtable();
607	} //}}}
608
609	//{{{ loadMacros() method
610	private static void loadMacros(Vector vector, String path, File directory)
611	{
612		File[] macroFiles = directory.listFiles();
613		if(macroFiles == null || macroFiles.length == 0)
614			return;
615
616		for(int i = 0; i < macroFiles.length; i++)
617		{
618			File file = macroFiles[i];
619			String fileName = file.getName();
620			if(file.isHidden())
621			{
622				/* do nothing! */
623				continue;
624			}
625			else if(file.isDirectory())
626			{
627				String submenuName = fileName.replace('_',' ');
628				Vector submenu = null;
629				//{{{ try to merge with an existing menu first
630				for(int j = 0; j < vector.size(); j++)
631				{
632					Object obj = vector.get(j);
633					if(obj instanceof Vector)
634					{
635						Vector vec = (Vector)obj;
636						if(((String)vec.get(0)).equals(submenuName))
637						{
638							submenu = vec;
639							break;
640						}
641					}
642				} //}}}
643				if(submenu == null)
644				{
645					submenu = new Vector();
646					submenu.addElement(submenuName);
647					vector.addElement(submenu);
648				}
649
650				loadMacros(submenu,path + fileName + '/',file);
651			}
652			else
653			{
654				Handler handler = getHandlerForPathName(file.getPath());
655
656				if(handler == null)
657					continue;
658
659				try
660				{
661					Macro newMacro = handler.createMacro(
662						path + fileName, file.getPath());
663					vector.addElement(newMacro.getName());
664					macroActionSet.addAction(newMacro);
665					macroHash.put(newMacro.getName(),newMacro);
666				}
667				catch (Exception e)
668				{
669					Log.log(Log.ERROR, Macros.class, e);
670					macroHandlers.remove(handler);
671				}
672			}
673		}
674	} //}}}
675
676	//{{{ recordMacro() method
677	/**
678	 * Starts recording a macro.
679	 * @param view The view
680	 * @param buffer The buffer to record to
681	 * @param temporary True if this is a temporary macro
682	 * @since jEdit 3.0pre5
683	 */
684	private static void recordMacro(View view, Buffer buffer, boolean temporary)
685	{
686		Handler handler = getHandler("beanshell");
687		String path = buffer.getPath();
688
689		view.setMacroRecorder(new Recorder(view,buffer,temporary));
690
691		// setting the message to 'null' causes the status bar to check
692		// if a recording is in progress
693		view.getStatus().setMessage(null);
694	} //}}}
695
696	//}}}
697
698	//{{{ Recorder class
699	/**
700	 * Handles macro recording.
701	 */
702	public static class Recorder implements EBComponent
703	{
704		View view;
705		Buffer buffer;
706		boolean temporary;
707
708		boolean lastWasInput;
709
710		//{{{ Recorder constructor
711		public Recorder(View view, Buffer buffer, boolean temporary)
712		{
713			this.view = view;
714			this.buffer = buffer;
715			this.temporary = temporary;
716			EditBus.addToBus(this);
717		} //}}}
718
719		//{{{ record() method
720		public void record(String code)
721		{
722			if(lastWasInput)
723			{
724				lastWasInput = false;
725				append("\");");
726			}
727
728			append("\n");
729			append(code);
730		} //}}}
731
732		//{{{ record() method
733		public void record(int repeat, String code)
734		{
735			if(repeat == 1)
736				record(code);
737			else
738			{
739				record("for(int i = 1; i <= " + repeat + "; i++)\n"
740					+ "{\n"
741					+ code + "\n"
742					+ "}");
743			}
744		} //}}}
745
746		//{{{ record() method
747		public void record(int repeat, char ch)
748		{
749			// record \n and \t on lines specially so that auto indent
750			// can take place
751			if(ch == '\n')
752				record(repeat,"textArea.userInput(\'\\n\');");
753			else if(ch == '\t')
754				record(repeat,"textArea.userInput(\'\\t\');");
755			else
756			{
757				StringBuffer buf = new StringBuffer();
758				for(int i = 0; i < repeat; i++)
759					buf.append(ch);
760				String charStr = MiscUtilities.charsToEscapes(buf.toString());
761
762				if(lastWasInput)
763					append(charStr);
764				else
765				{
766					append("\ntextArea.setSelectedText(\"" + charStr);
767					lastWasInput = true;
768				}
769			}
770		} //}}}
771
772		//{{{ handleMessage() method
773		public void handleMessage(EBMessage msg)
774		{
775			if(msg instanceof BufferUpdate)
776			{
777				BufferUpdate bmsg = (BufferUpdate)msg;
778				if(bmsg.getWhat() == BufferUpdate.CLOSED)
779				{
780					if(bmsg.getBuffer() == buffer)
781						stopRecording(view);
782				}
783			}
784		} //}}}
785
786		//{{{ append() method
787		private void append(String str)
788		{
789			buffer.insert(buffer.getLength(),str);
790		} //}}}
791
792		//{{{ dispose() method
793		private void dispose()
794		{
795			if(lastWasInput)
796			{
797				lastWasInput = false;
798				append("\");");
799			}
800
801			for(int i = 0; i < buffer.getLineCount(); i++)
802			{
803				buffer.indentLine(i,true);
804			}
805
806			EditBus.removeFromBus(this);
807
808			// setting the message to 'null' causes the status bar to
809			// check if a recording is in progress
810			view.getStatus().setMessage(null);
811		} //}}}
812	} //}}}
813
814	//{{{ Handler class
815	/**
816	 * Encapsulates creating and invoking macros in arbitrary scripting languages
817	 * @since jEdit 4.0pre6
818	 */
819	public static abstract class Handler
820	{
821		//{{{ getName() method
822		public String getName()
823		{
824			return name;
825		} //}}}
826
827		//{{{ getLabel() method
828		public String getLabel()
829		{
830			return label;
831		} //}}}
832
833		//{{{ accept() method
834		public boolean accept(String path)
835		{
836			return filter.isMatch(MiscUtilities.getFileName(path));
837		} //}}}
838
839		//{{{ createMacro() method
840		public abstract Macro createMacro(String macroName, String path);
841		//}}}
842
843		//{{{ runMacro() method
844		/**
845		 * Runs the specified macro.
846		 * @param view The view - may be null.
847		 * @param macro The macro.
848		 */
849		public abstract void runMacro(View view, Macro macro);
850		//}}}
851
852		//{{{ runMacro() method
853		/**
854		 * Runs the specified macro. This method is optional; it is
855		 * called if the specified macro is a startup script. The
856		 * default behavior is to simply call {@link #runMacro(View,Macros.Macro)}.
857		 *
858		 * @param view The view - may be null.
859		 * @param macro The macro.
860		 * @param ownNamespace  A hint indicating whenever functions and
861		 * variables defined in the script are to be self-contained, or
862		 * made available to other scripts. The macro handler may ignore
863		 * this parameter.
864		 * @since jEdit 4.1pre3
865		 */
866		public void runMacro(View view, Macro macro, boolean ownNamespace)
867		{
868			runMacro(view,macro);
869		} //}}}
870
871		//{{{ Handler constructor
872		protected Handler(String name)
873		{
874			this.name = name;
875			label = jEdit.getProperty("macro-handler."
876				+ name + ".label", name);
877			try
878			{
879				filter = new RE(MiscUtilities.globToRE(
880					jEdit.getProperty(
881					"macro-handler." + name + ".glob")));
882			}
883			catch (Exception e)
884			{
885				throw new InternalError("Missing or invalid glob for handler " + name);
886			}
887		} //}}}
888
889		//{{{ Private members
890		private String name;
891		private String label;
892		private RE filter;
893		//}}}
894	} //}}}
895
896	//{{{ BeanShellHandler class
897	static class BeanShellHandler extends Handler
898	{
899		//{{{ BeanShellHandler constructor
900		BeanShellHandler()
901		{
902			super("beanshell");
903		} //}}}
904
905		//{{{ createMacro() method
906		public Macro createMacro(String macroName, String path)
907		{
908			// Remove '.bsh'
909			macroName = macroName.substring(0, macroName.length() - 4);
910
911			return new Macro(this, macroName,
912				Macro.macroNameToLabel(macroName), path);
913		} //}}}
914
915		//{{{ runMacro() method
916		public void runMacro(View view, Macro macro)
917		{
918			BeanShell.runScript(view,macro.getPath(),null,true);
919		} //}}}
920
921		//{{{ runMacro() method
922		public void runMacro(View view, Macro macro, boolean ownNamespace)
923		{
924			BeanShell.runScript(view,macro.getPath(),null,ownNamespace);
925		} //}}}
926	} //}}}
927}