PageRenderTime 31ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

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

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