| // Groovy Regex Coach - Copyright 2007 Jeremy Rayner |
| // inspired by http://weitz.de/regex-coach/ |
| import java.awt.* |
| import java.awt.event.* |
| import java.util.regex.* |
| import javax.swing.* |
| import javax.swing.text.DefaultHighlighter |
| import groovy.swing.SwingBuilder |
| |
| // define the view |
| def swing = new SwingBuilder() |
| def gui = swing.frame(title:'The Groovy Regex Coach', location:[20,40], size:[600,500], defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) { |
| panel(layout:new BorderLayout()) { |
| splitPane(orientation:JSplitPane.VERTICAL_SPLIT, dividerLocation:150) { |
| panel(layout:new BorderLayout()) { |
| label(constraints:BorderLayout.NORTH, text:'Regular expression:') |
| scrollPane(constraints:BorderLayout.CENTER) {textPane(id:'regexPane')} |
| label(constraints:BorderLayout.SOUTH, id:'regexStatus', text:' ') |
| } |
| panel(layout:new BorderLayout()) { |
| label(constraints:BorderLayout.NORTH, text:'Target string:') |
| scrollPane(constraints:BorderLayout.CENTER) {textPane(id:'targetPane')} |
| panel(constraints:BorderLayout.SOUTH, layout:new BorderLayout()) { |
| label(constraints:BorderLayout.NORTH, id:'targetStatus', text:' ') |
| panel(constraints:BorderLayout.SOUTH, layout:new FlowLayout()) { |
| button('<<-', id:'scanLeft') |
| button('->>', id:'scanRight') |
| } |
| } |
| } |
| } |
| } |
| } |
| def highlighter = new RegexHighlighter(swing:swing) |
| swing.regexPane.addKeyListener(highlighter) |
| swing.targetPane.addKeyListener(highlighter) |
| swing.scanLeft.addActionListener(highlighter) |
| swing.scanRight.addActionListener(highlighter) |
| gui.show() |
| |
| class RegexHighlighter extends KeyAdapter implements ActionListener { |
| def swing // reference to the view |
| int scanIndex // how many times to execute matcher.find() |
| def orange = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE) |
| def yellow = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW) |
| def red = new DefaultHighlighter.DefaultHighlightPainter(Color.RED) |
| |
| // react to user actions |
| public void actionPerformed(ActionEvent event) { |
| if (event.actionCommand == '<<-') {scanIndex = Math.max(scanIndex - 1, 0)} |
| if (event.actionCommand == '->>') {scanIndex++} |
| doHighlights() |
| } |
| public void keyReleased(KeyEvent event) { |
| scanIndex = 0 |
| doHighlights() |
| } |
| |
| private resetView() { |
| swing.regexPane.highlighter.removeAllHighlights() |
| swing.targetPane.highlighter.removeAllHighlights() |
| swing.regexStatus.text = ' ' |
| swing.targetStatus.text = ' ' |
| } |
| |
| // the main regex logic |
| private doHighlights() { |
| try { |
| resetView() |
| // note: get the text from the underlying document, |
| // otherwise carriage return/line feeds different when using the JTextPane text |
| def regex = swing.regexPane.document.getText(0,swing.regexPane.document.length) |
| def target = swing.targetPane.document.getText(0,swing.targetPane.document.length) |
| |
| def matcher = (target =~ regex) |
| |
| // scan past the matches before the match we want |
| int scan = 0 |
| while (scan < scanIndex) { |
| matcher.find() |
| scan++ |
| } |
| if (matcher.find()) { |
| // highlight any captured groups |
| int i = 0 |
| while (i++ < matcher.groupCount()) { |
| swing.targetPane.highlighter.addHighlight(matcher.start(i), matcher.end(i), orange) |
| } |
| // highlight whole match |
| swing.targetPane.highlighter.addHighlight(matcher.start(), matcher.end(), yellow) |
| if (regex.length() != 0) { |
| swing.targetStatus.text = "Match #${scanIndex + 1} from ${matcher.start()} to ${matcher.end()}." |
| } |
| } else { // not found |
| scanIndex = Math.max(scan - 1, 0) |
| if (scanIndex > 0) {doHighlights()} |
| swing.targetStatus.text = "No match." |
| } |
| } catch (PatternSyntaxException e) { |
| swing.regexPane.highlighter.addHighlight(e.index, e.index + 2, red) |
| swing.regexStatus.text = e.description |
| } |
| } |
| } |