Interactive command-line shell (REPL) for evaluating Groovy expressions with advanced editing, completion, and command features
—
The Groovy Shell provides advanced interactive features including multi-line editing, command history, buffer management, and terminal integration. These features create a rich REPL experience for Groovy development.
The interactive shell runner provides JLine integration for readline functionality, history management, and completion.
/**
* Abstract base class for shell runners
*/
abstract class ShellRunner {
/** Run the shell */
abstract void run()
/** Set error handling closure */
void setErrorHandler(Closure errorHandler)
}
/**
* Interactive shell runner with JLine integration for readline, history, and completion
*/
class InteractiveShellRunner extends ShellRunner implements Runnable {
/** JLine console reader for terminal input */
ConsoleReader reader
/** Prompt rendering closure */
final Closure prompt
/** Multi-command completer aggregating all completers */
final CommandsMultiCompleter completer
/** Enhanced input stream wrapper */
WrappedInputStream wrappedInputStream
/**
* Start interactive session with readline support
*/
void run()
/**
* Configure command history
* @param history - File-based history implementation
*/
void setHistory(FileHistory history)
/**
* Create interactive shell runner
* @param shell - Shell instance to run
* @param prompt - Closure for rendering shell prompt
*/
InteractiveShellRunner(Groovysh shell, Closure prompt)
}Aggregates multiple completers for comprehensive command and code completion.
/**
* Aggregates multiple completers for interactive command completion
*/
class CommandsMultiCompleter extends AggregateCompleter {
/**
* Add completer for command
* @param command - Command to add completer for
*/
def add(Command command)
/** Refresh completer list */
void refresh()
/**
* Perform completion
* @param buffer - Input buffer
* @param pos - Cursor position
* @param cand - Candidate list to populate
* @return Completion start position
*/
int complete(String buffer, int pos, List cand)
}Multi-buffer editing system for managing complex code input across multiple buffers.
/**
* Manages multiple code buffers for multi-line editing and buffer switching
*/
class BufferManager {
/** List of code buffers */
final List<List<String>> buffers
/** Currently selected buffer index */
int selected
/** Reset all buffers to empty state */
void reset()
/** Get current buffer */
List<String> current()
/**
* Select buffer by index
* @param index - Buffer index to select
*/
void select(int index)
/**
* Create new buffer
* @param select - Whether to select the new buffer
* @return Index of created buffer
*/
int create(boolean select)
/**
* Delete buffer by index
* @param index - Buffer index to delete
*/
void delete(int index)
/** Get number of buffers */
int size()
/** Delete currently selected buffer */
void deleteSelected()
/** Clear current buffer contents */
void clearSelected()
/**
* Update current buffer contents
* @param buffer - New buffer contents
*/
void updateSelected(List buffer)
BufferManager()
}Usage Examples:
import org.apache.groovy.groovysh.BufferManager
def bufferManager = new BufferManager()
// Work with multiple buffers
bufferManager.current() << "def x = 10"
bufferManager.current() << "println x"
// Create additional buffer
int newBuffer = bufferManager.create(false)
bufferManager.select(newBuffer)
bufferManager.current() << "def y = 20"
// Switch between buffers
bufferManager.select(0)
println "Buffer 0: ${bufferManager.current()}"
bufferManager.select(1)
println "Buffer 1: ${bufferManager.current()}"Multi-pass parsing system with support for incomplete expressions and error recovery.
/**
* Interface for parsing Groovy code
*/
interface Parsing {
/**
* Parse code buffer and return status
* @param buffer - Collection of code lines
* @return Parse status indicating success, failure, or incomplete
*/
ParseStatus parse(Collection<String> buffer)
}
/**
* Parser with preference-based implementation selection
*/
class Parser implements Parsing {
/** System line separator */
static final String NEWLINE = System.lineSeparator()
/**
* Parse buffer and return status
* @param buffer - Code buffer to parse
* @return Parse status
*/
ParseStatus parse(Collection<String> buffer)
/** Create parser with preference-based selection */
Parser()
}
/**
* Parse result codes
*/
final class ParseCode {
/** Parse completed successfully */
static final ParseCode COMPLETE
/** Parse incomplete, needs more input */
static final ParseCode INCOMPLETE
/** Parse error occurred */
static final ParseCode ERROR
}
/**
* Parse status with result code and optional error
*/
final class ParseStatus {
/** Parse result code */
final ParseCode code
/** Exception if error occurred */
final Throwable cause
ParseStatus(ParseCode code, Throwable cause)
ParseStatus(ParseCode code)
ParseStatus(Throwable cause)
}Alternative parser implementation using ANTLR4 for more lenient parsing.
/**
* Relaxed parser implementation using ANTLR4 for more lenient parsing
*/
class RelaxedParser implements Parsing {
/**
* Parse code buffer with relaxed error handling
* @param buffer - Code to parse
* @return Parse status
*/
ParseStatus parse(Collection<String> buffer)
}Parser Usage Examples:
import org.apache.groovy.groovysh.Parser
import org.apache.groovy.groovysh.ParseCode
def parser = new Parser()
// Complete expression
def status = parser.parse(['def x = 1', 'println x'])
assert status.code == ParseCode.COMPLETE
// Incomplete expression (missing closing brace)
status = parser.parse(['if (true) {'])
assert status.code == ParseCode.INCOMPLETE
// Parse error
status = parser.parse(['def x = '])
// Handle error case
if (status.code == ParseCode.ERROR) {
println "Parse error: ${status.cause.message}"
}Code evaluation system with binding context and class loading support.
/**
* Interface for evaluating code
*/
interface Evaluator {
/**
* Evaluate code strings
* @param strings - Code to evaluate
* @return Evaluation result
*/
Object evaluate(Collection<String> strings)
}
/**
* Interpreter for evaluating Groovy code with binding context
*/
class Interpreter implements Evaluator {
/** Default script filename for evaluation */
static final String SCRIPT_FILENAME = 'groovysh_evaluate'
/**
* Evaluate code buffer
* @param buffer - Code lines to evaluate
* @return Evaluation result
*/
Object evaluate(Collection<String> buffer)
/** Get interpreter class loader */
GroovyClassLoader getClassLoader()
/** Get evaluation binding context */
Binding getContext()
/** Get underlying GroovyShell */
GroovyShell getShell()
/**
* Create interpreter
* @param classLoader - Parent class loader
* @param binding - Variable binding context
* @param configuration - Compiler configuration (optional)
*/
Interpreter(ClassLoader classLoader, Binding binding, CompilerConfiguration configuration = null)
}Terminal detection and ANSI color support for enhanced display.
/**
* Detects ANSI terminal capabilities
*/
class AnsiDetector {
/**
* Detect if terminal supports ANSI codes
* @return true if ANSI is supported
*/
static boolean isAnsiSupported()
/**
* Configure ANSI support for terminal
* @param force - Force ANSI support regardless of detection
*/
static void configureAnsiSupport(boolean force = false)
}Wrapper around input stream with character insertion capabilities.
/**
* Wrapper around InputStream with character insertion support
*/
class WrappedInputStream extends FilterInputStream {
/**
* Insert characters into the input stream
* @param chars - Characters to insert
*/
void insert(String chars)
/**
* Create wrapped input stream
* @param input - Input stream to wrap
*/
WrappedInputStream(InputStream input)
}Security manager that prevents System.exit() calls during shell operation.
/**
* Security manager that prevents System.exit() calls during shell operation
*/
class NoExitSecurityManager extends SecurityManager {
/** Override security checks to prevent exit */
void checkExit(int status)
/** Allow other security operations */
void checkPermission(Permission perm)
}The shell integrates with Groovy's preference system for configuration:
// Key preference settings available in Groovysh
static final String INTERPRETER_MODE_PREFERENCE_KEY = 'interpreterMode'
static final String AUTOINDENT_PREFERENCE_KEY = 'autoindent'
static final String COLORS_PREFERENCE_KEY = 'colors'
static final String SANITIZE_PREFERENCE_KEY = 'sanitizeStackTrace'
static final String SHOW_LAST_RESULT_PREFERENCE_KEY = 'showLastResult'
static final String METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY = 'meta-completion-prefix-length'Configuration Usage:
// Set shell preferences
shell.execute(':set interpreterMode true') // Enable interpreter mode
shell.execute(':set autoindent true') // Enable auto-indentation
shell.execute(':set colors false') // Disable ANSI colors
shell.execute(':set sanitizeStackTrace true') // Clean stack traces
shell.execute(':set showLastResult false') // Hide last result display
// Access preferences programmatically
import org.codehaus.groovy.tools.shell.util.Preferences
def prefs = shell.preferences
prefs.put(Groovysh.COLORS_PREFERENCE_KEY, 'true')
prefs.put(Groovysh.AUTOINDENT_PREFERENCE_KEY, 'false')/**
* Error thrown to signal shell exit
*/
class ExitNotification extends Error {
/** Exit code */
final int code
/**
* Create exit notification
* @param code - Exit code to use
*/
ExitNotification(int code)
}Shell State Directory:
// Get user's groovy state directory
File stateDir = shell.getUserStateDirectory()
// Typically: ~/.groovy/
// History file location
File historyFile = new File(stateDir, 'groovysh.history')
// Preferences location
File prefsFile = new File(stateDir, 'groovysh.prefs')Session Information:
// Display shell information
shell.execute(':show variables') // Show bound variables
shell.execute(':show classes') // Show loaded classes
shell.execute(':show imports') // Show import statements
shell.execute(':show preferences') // Show configuration
shell.execute(':show all') // Show everything
// Buffer operations
shell.displayBuffer(shell.buffers.current()) // Display current buffer
println shell.getImportStatements() // Get formatted imports
println shell.renderPrompt() // Get colored promptMulti-line Editing Features:
// Check for type/method declarations (affects indentation)
def buffer = ['class MyClass {', ' def method() {']
boolean isDeclaration = Groovysh.isTypeOrMethodDeclaration(buffer)
// Get indentation prefix for continuation lines
String indent = shell.getIndentPrefix()
// Automatic indentation based on context
shell.indentSize = 4 // Set indentation size (default: 2)The shell features provide a comprehensive interactive environment with advanced editing capabilities, robust error handling, and extensive configuration options for productive Groovy development.
Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-groovysh