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