PageRenderTime 46ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

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

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