Archive for September, 2013

Search API Updates

Sunday, September 22nd, 2013

The next release of RSyntaxTextArea and RSTAUI will feature some enhancements to the Search API.

Find and Replace operations were always done through the SearchEngine class.  This class contained the following static methods:


   public static boolean find(JTextArea textArea, SearchContext context)
   public static boolean replace(RTextArea textArea, SearchContext context)
   public static int replaceAll(RTextArea textArea, SearchContext context)

The find() and replace() methods returned whether a match was found/replaced, and the replaceAll() method returned the number of replacements performed.

In order to do a “mark all”, you had to call a method on an RTextArea instance:


   public int markAll(String toMark, boolean matchCase, boolean wholeWord, boolean regex)
   public void clearMarkAllHighlights()

In the next release of RSTA, the “mark all” API will be moved into SearchEngine, so that it is a one-stop shop for everything related to search. Further, these methods will return a new SearchResult object, containing more uniform, detailed information on the result of the operation.

The find() and replace() methods will now check context.getMarkAll(), and if it returns true, they will automatically perform a “mark all” operation along with the find/replace requested. This is very useful because often, people want to visually see what other matches are nearby the one actually found and selected.

The search-related components in RSTAUI have been updated as well. Besides the existing Find and Replace dialogs, there are now two new components – FindToolBar and ReplaceToolBar. When wrapped in a CollapsibleSectionPanel, these tool bars can provide a search UI integrated into an application’s main window, as opposed to the standard approach of modal dialogs. This is the trendy new way of doing things. In addition, these components use an animation to “slide” in and out of the UI, breathing a little bit of life into a Swing application.

Below is an example of setting up a window where Ctrl+F and Ctrl+H will bring up a FindToolBar and ReplaceToolBar, respectively:

   JPanel contentPane = new JPanel(new BorderLayout());
   frame.setContentPane(contentPane);
   JMenuBar mb = new JMenuBar();
   frame.setJMenuBar(mb);
   JMenu menu = new JMenu("Search");
   mb.add(menu);
   // Create our search tool bars and tie their search contexts together.
   findToolBar = new FindToolBar(this);
   replaceToolBar = new ReplaceToolBar(this);
   replaceToolBar.setSearchContext(findToolBar.getSearchContext());
   // Add our search tool bars to the "collapsible section panel."
   // Ctrl+F and Ctrl+H will display these tool bars. Use the returned actions to
   // create menu items for our application menu bar.
   CollapsibleSectionPanel csp = new CollapsibleSectionPanel();
   contentPane.add(csp);
   int ctrl = getToolkit().getMenuShortcutKeyMask();
   KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F, ctrl);
   Action a = csp.addBottomComponent(ks, findToolBar);
   a.putValue(Action.NAME, "Find...");
   menu.add(new JMenuItem(a));
   ks = KeyStroke.getKeyStroke(KeyEvent.VK_H, ctrl);
   a = csp.addBottomComponent(ks, replaceToolBar);
   a.putValue(Action.NAME, "Replace...");
   menu.add(new JMenuItem(a));

Here’s an example of what the tool bars look like:

 

Find Tool Bar

Find Tool Bar

Replace Tool Bar

Replace Tool Bar

Ctrl+F/Ctrl+H toggles between them, and Escape hides the currently visible one, if any.  If “Mark All” is enabled, all matches are selected in the editor as you type, which is a very nice feature.  The “mark all” event waits for a short time after you stop typing before it fires (defaulting to 200 ms).  That way, it doesn’t perform a mark-all operation for each letter you type if you type really quickly.

Just like the older Find and Replace dialogs, the Find and Replace tool bars will offer code completion for regular expressions:

 

Regex assistance

Regex assistance

This code is already pushed to GitHub; all I have left to do is some more testing.  I also plan on improving the performance of “mark all;” it’s slower than the “mark occurrences” support in RSTA and there’s no reason for that.  And since these new components make it so easy and handy to have “mark all” enabled all the time, I figured I’d go ahead and knock that out sooner rather than later.