📄 console.groovy
字号:
package groovy.uiimport groovy.swing.SwingBuilderimport groovy.inspect.swingui.ObjectBrowserimport java.awt.BorderLayoutimport java.awt.EventQueueimport java.awt.Colorimport java.awt.Fontimport java.awt.Insetsimport java.awt.Toolkitimport java.awt.event.KeyEventimport java.io.PrintWriterimport java.io.StringWriterimport java.util.EventObjectimport javax.swing.*import javax.swing.text.*import javax.swing.event.*import org.codehaus.groovy.runtime.InvokerHelper/** * Groovy Swing console. * * Allows user to interactively enter and execute Groovy. * * @author Danno Ferrin * @author Dierk Koenig, changed Layout, included Selection sensitivity, included ObjectBrowser * @author Alan Green more features: history, System.out capture, bind result to _ */class Console implements CaretListener { // Whether or not std output should be captured to the console def captureStdOut = true // Maximum size of history int maxHistory = 10 // Maximum number of characters to show on console at any time int maxOutputChars = 10000 // UI SwingBuilder swing JFrame frame JTextArea inputArea JTextPane outputArea JLabel statusLabel JDialog runWaitDialog // Styles for output area Style promptStyle; Style commandStyle; Style outputStyle; Style resultStyle; // Internal history List history = [] int historyIndex = 1 // valid values are 0..history.length() // Current editor state boolean dirty int textSelectionStart // keep track of selections in inputArea int textSelectionEnd def scriptFile // Running scripts GroovyShell shell int scriptNameCounter = 0 def systemOutInterceptor def runThread = null static void main(args) { def console = new Console() console.run() } Console() { shell = new GroovyShell() } Console(Binding binding) { shell = new GroovyShell(binding) } Console(ClassLoader parent, Binding binding) { shell = new GroovyShell(parent,binding) } void run() { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) // if menu modifier is two keys we are out of luck as the javadocs // indicates it returns "Control+Shift" instead of "Control Shift" def menuModifier = KeyEvent.getKeyModifiersText( Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()).toLowerCase() + ' ' swing = new SwingBuilder() frame = swing.frame( title:'GroovyConsole', location:[100,100], size:[500,400], defaultCloseOperation:javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE) { def newFileAction = action( name:'New File', closure: this.&fileNewFile, mnemonic: 'N', accelerator: menuModifier + 'Q' ) def newWindowAction = action( name:'New Window', closure: this.&fileNewWindow, mnemonic: 'W' ) def openAction = action( name:'Open', closure: this.&fileOpen, mnemonic: 'O', accelerator: menuModifier + 'O' ) def saveAction = action( name:'Save', closure: this.&fileSave, mnemonic: 'S', accelerator: menuModifier + 'S' ) def exitAction = action( name:'Exit', closure: this.&exit, mnemonic: 'x', accelerator: 'alt F4' ) def historyPrevAction = action( name:'Previous', closure: this.&historyPrev, mnemonic: 'P', accelerator: 'ctrl P' ) def historyNextAction = action( name: 'Next', closure: this.&historyNext, mnemonic: 'N', accelerator: 'ctrl N' ) def clearOutputAction = action( name:'Clear Output', closure: this.&clearOutput, mnemonic: 'l', keyStroke: 'ctrl W', accelerator: 'ctrl W' ) def runAction = action( name:'Run', closure: this.&runScript, mnemonic: 'R', keyStroke: 'ctrl ENTER', accelerator: 'ctrl R' ) def inspectLastAction = action( name:'Inspect Last', closure: this.&inspectLast, mnemonic: 'I', keyStroke: 'ctrl I', accelerator: 'ctrl I' ) def inspectVariablesAction = action( name:'Inspect Variables', closure: this.&inspectVariables, mnemonic: 'V', keyStroke: 'ctrl J', accelerator: 'ctrl J' ) def captureStdOutAction = action( name:'Capture Standard Output', closure: this.&captureStdOut, mnemonic: 'C' ) def largerFontAction = action( name:'Larger Font', closure: this.&largerFont, mnemonic: 'L', keyStroke: 'alt shift L', accelerator: 'alt shift L' ) def smallerFontAction = action( name:'Smaller Font', closure: this.&smallerFont, mnemonic: 'S', keyStroke: 'alt shift S', accelerator: 'alt shift S' ) def aboutAction = action(name:'About', closure: this.&showAbout, mnemonic: 'A') menuBar { menu(text:'File', mnemonic: 'F') { menuItem() { action(newFileAction) } menuItem() { action(newWindowAction) } menuItem() { action(openAction) } separator() menuItem() { action(saveAction) } separator() menuItem() { action(exitAction) } } menu(text:'Edit', mnemonic: 'E') { menuItem() { action(historyNextAction) } menuItem() { action(historyPrevAction) } separator() menuItem() { action(clearOutputAction) } } menu(text:'Actions', mnemonic: 'A') { menuItem() { action(runAction) } menuItem() { action(inspectLastAction) } menuItem() { action(inspectVariablesAction) } separator() checkBoxMenuItem(selected: captureStdOut) { action(captureStdOutAction) } separator() menuItem() { action(largerFontAction) } menuItem() { action(smallerFontAction) } } menu(text:'Help', mnemonic: 'H') { menuItem() { action(aboutAction) } } } borderLayout() splitPane(id:'splitPane', resizeWeight:0.50F, orientation:JSplitPane.VERTICAL_SPLIT, constraints: BorderLayout.CENTER) { scrollPane { inputArea = textArea( margin: new Insets(3,3,3,3), font: new Font('Monospaced',Font.PLAIN,12) ) { action(runAction) } } scrollPane { outputArea = textPane(editable:false, background: new Color(255,255,218)) addStylesToDocument(outputArea) } } statusLabel = label(id:'status', text: 'Welcome to the Groovy.', constraints: BorderLayout.SOUTH, border: BorderFactory.createLoweredBevelBorder()) } // end of frame runWaitDialog = swing.dialog(title: 'Groovy executing', owner: frame, modal: true) { //boxLayout(axis: BoxLayout.Y_AXIS) // todo mittie: dialog.setLayout -> dialog.contentPane.setLayout() label(text: "Groovy is now executing. Please wait.", border: BorderFactory.createEmptyBorder(10, 10, 10, 10), alignmentX: 0.5f) button(action: action(name: 'Interrupt', closure: this.&confirmRunInterrupt), border: BorderFactory.createEmptyBorder(10, 10, 10, 10), alignmentX: 0.5f) } // end of runWaitDialog // add listeners frame.windowClosing = this.&exit inputArea.addCaretListener(this) inputArea.document.undoableEditHappened = { setDirty(true) } systemOutInterceptor = new SystemOutputInterceptor(this.¬ifySystemOut) systemOutInterceptor.start(); bindResults() frame.show() SwingUtilities.invokeLater({inputArea.requestFocus()}); } void addStylesToDocument(JTextPane outputArea) { StyledDocument doc = outputArea.getStyledDocument(); Style defStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE); Style regular = doc.addStyle("regular", defStyle); StyleConstants.setFontFamily(regular, "Monospaced") promptStyle = doc.addStyle("prompt", regular) StyleConstants.setForeground(promptStyle, Color.BLUE) commandStyle = doc.addStyle("command", regular); StyleConstants.setForeground(commandStyle, Color.MAGENTA) outputStyle = regular resultStyle = doc.addStyle("result", regular) StyleConstants.setBackground(resultStyle, Color.BLUE) StyleConstants.setBackground(resultStyle, Color.YELLOW) } void addToHistory(record) { history.add(record) // history.size here just retrieves method closure if (history.size() > maxHistory) { history.remove(0) } // history.size doesn't work here either historyIndex = history.size() } // Append a string to the output area void appendOutput(text, style){ def doc = outputArea.styledDocument doc.insertString(doc.length, text, style) // Ensure we don't have too much in console (takes too much memory) if (doc.length > maxOutputChars) { doc.remove(0, doc.length - maxOutputChars) } } // Append a string to the output area on a new line void appendOutputNl(text, style){ def doc = outputArea.styledDocument def len = doc.length if (len > 0 && doc.getText(len - 1, 1) != "\n") { appendOutput("\n", style); } appendOutput(text, style) } // Return false if use elected to cancel boolean askToSaveFile() { if (scriptFile == null || !dirty) { return true } switch (JOptionPane.showConfirmDialog(frame, "Save changes to " + scriptFile.name + "?", "GroovyConsole", JOptionPane.YES_NO_CANCEL_OPTION)) { case JOptionPane.YES_OPTION: return fileSave() case JOptionPane.NO_OPTION: return true default: return false } } private static void beep() { Toolkit.defaultToolkit.beep() } // Binds the "_" and "__" variables in the shell void bindResults() { shell.setVariable("_", getLastResult()) // lastResult doesn't seem to work shell.setVariable("__", history.collect {it.result})
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -