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

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