XREPL: eXtended REPL
1 Installing XREPL
If you want to enable XREPL automatically, add this expression to your Racket initialization file. To load XREPL conditionally (e.g., not in older Racket versions), you can use (dynamic-require 'xrepl #f). This is a plain expression that can be placed inside when and elsewhere. An easy way to do the necessary editing is to enter ,install!, which will inspect and edit your initialization file (it will describe the change and ask for your permission). Alternatively, you can edit the file directly: on Unix, it is "~/.racketrc", and for other platforms evaluate (find-system-path 'init-file) to see where it is.
XREPL will set up a readline-based reader, so you do not need to load that yourself. If your initialization file was previously set to load readline via install-readline!, the ,install! command will (notify you and) remove it. If you added it yourself, consider removing it. (This is not strictly needed, but XREPL is slightly better at detecting when to use readline.)
2 Meta REPL Commands
Most of the XREPL extensions are implemented as meta commands. These
commands are entered at the REPL, prefixed by a , and followed
by the command name. Note that several commands correspond directly to
Racket functions (e.g., ,exit) —
2.1 Generic Commands
,help [<command-name>] |
display available commands |
[Synonyms: ,h ,?] |
Without an argument, displays a list of all known commands. Specify a command to get help specific to that command.
,exit [<exit-code>] |
exit racket |
[Synonyms: ,quit ,ex] |
Exits Racket, optionally with an error code (see exit).
,cd [<path>] |
change the current directory |
Sets the current-directory to the given path. If no path is specified, use your home directory. Path arguments are passed through expand-user-path so you can use ~. An argument of - means “the previous path”.
display the current directory |
Reports the value of current-directory.
,shell <shell-command> |
run a shell command |
[Synonyms: ,sh ,ls ,cp ,mv ,rm ,md ,rd ,git ,svn] |
Use ,shell (or ,sh) to run a generic shell command (via
system). For convenience, a few synonyms are provided —
When the REPL is in the context of a module with a known source file, the shell command can use the F environment variable as the path to the file. Otherwise, F is set to an empty string.
,edit <file> ... |
edit files in your $EDITOR |
[Synonyms: ,e] |
Runs an editor, as specified by your EDITOR environment variable, with the given file/s arguments. If no files are specified and the REPL is currently inside a module’s namespace, then the file for that module is used. If the EDITOR environment variable is not set, use the ,drracket command instead.
,drracket [-flag] <file> ... |
edit files in DrRacket |
[Synonyms: ,dr ,drr] |
Runs DrRacket with the specified file/s. If no files are given, and the REPL is currently inside a module, the file for that module is used.
DrRacket is launched directly, without starting a new subprocess, and
it is then kept running in a hidden window so further invocations are
immediate. (When this command is used for the first time, you will
see DrRacket start as usual, and then its window will disappear —
-new: opens a new editing window. This is the default when no files are given and the REPL is not inside a module,
-open: opens the specified file/s (or the current module’s file). This is the default when files are given or when inside a module.
-quit: exits the running DrRacket instance. Quitting DrRacket is usually not necessary. Therefore, if you try to quit it from the DrRacket window, it will instead just close the window but DrRacket will still be running in the background. Use this command in case there is some exceptional problem that requires actually quitting the IDE. (Once you do so, future uses of this command will start a fresh instance.)
2.2 Binding Information
,apropos <search-for> ... |
look for a binding |
[Synonyms: ,ap] |
Searches for known bindings in the current namespace. The arguments specify which binding to look for: use a symbol (without a ') to look for bindings that contain that name, and use a regexp (e.g., #rx"...") to use a regexp for the search. Multiple arguments are and-ed together.
If no arguments are given, all bindings are listed.
,describe [<phase-number>] <identifier-or-module> ... |
describe a (bound) identifier |
[Synonyms: ,desc ,id] |
For each of the specified names, describe where where it is coming from and how it was defined if it names a known binding. In addition, describe the module (list its imports and exports) that is named by arguments that are known module names.
By default, bindings are searched for at the runtime level (phase 0). You can add a different phase level for identifier lookups as a first argument. In this case, only a binding can be described, even if the same name is a known module.
,doc <any> ... |
browse the racket documentation |
Uses Racket’s help to browse the documentation, look for a binding, etc. Note that this can be used even in languages that don’t have the help binding.
2.3 Requiring and Loading Files
,require <require-spec> ...+ |
require a module |
[Synonyms: ,req ,r] |
Most arguments are passed to require as is. As a convenience, if a symbolic argument specifies an existing file name, then use its string form to specify the require, or use a file in case of an absolute path. In addition, an argument that names a known symbolic module name (e.g., one that was defined on the REPL, or a builtin module like #%network), then its quoted form is used. (Note that these shorthands do not work inside require subforms like only-in.)
,require-reloadable <module> ... |
require a module, make it reloadable |
[Synonyms: ,reqr ,rr] |
Same as ,require, but arranges to load the code in a way that makes it possible to reload it later, or if a module was already loaded (using this command) then reload it. Note that the arguments should be simple module names, without any require macros. If no arguments are given, use arguments from the last use of this command (if any).
Module reloading is enabled by turning off the
compile-enforce-module-constants parameter —
,enter [<module>] [noisy?] |
require a module and go into its namespace |
[Synonyms: ,en] |
Uses enter! to have the REPL go “inside” a given module’s namespace. A module name can specify an existing file as with the ,require-reloadable command. If no module is given, and the REPL is already in some module’s namespace, then ‘enter!’ is used with that module, causing it to reload if needed. Using #f makes it go back to the toplevel namespace.
Note that this can be used even in languages that don’t have the enter! binding. In addition, enter! is used in a way that does not make it require itself into the target namespace.
go back to the toplevel |
[Synonyms: ,top] |
Makes the REPL go back to the toplevel namespace. Same as using the ,enter command with a #f argument.
,load <filename> ... |
load a file |
[Synonyms: ,ld] |
Uses load to load the specified file(s).
2.4 Debugging
see a backtrace of the last exception |
[Synonyms: ,bt] |
Whenever an error is displayed, XREPL will not show its context printout. Instead, use the ,backtrace command to display the backtrace for the last error.
,time [<count>] <expr> ... |
time an expression |
Times execution of an expression (or expressions). This is similar to "time" but the information that is displayed is a bit easier to read.
In addition, you can provide an initial number to specify repeating the evaluation a number of times. In this case, each iteration is preceded by two garbage collections, and when the iteration is done its timing information and evaluation result(s) are displayed. When the requested number of repetitions is done, some extreme results are removed (top and bottom 2/7ths), and the remaining results are be averaged. Finally, the resulting value(s) are from the last run are returned (and can be accessed via the bindings for the last few results, see Past Evaluation Results).
,trace <function> ... |
trace a function |
[Synonyms: ,tr] |
Traces the named function (or functions), using trace.
,untrace <function> ... |
untrace a function |
[Synonyms: ,untr] |
Untraces the named function (or functions), using untrace.
,errortrace [<flag>] |
errortrace instrumentation control |
[Synonyms: ,errt ,inst] |
errortrace is a useful Racket library which can provide a number of useful services like precise profiling, test coverage, and accurate error information. However, using it can be a little tricky. ,errortrace and a few related commands fill this gap, making errortrace easier to use.
,errortrace controls global use of errortrace. With a flag argument of + errortrace instrumentation is turned on, with - it is turned off, and with no arguments it is toggled. In addition, a ? flag displays instrumentation state.
Remember that errortrace instrumentation hooks into the Racket compiler, and applies only to source code that gets loaded from source and therefore compiled. Therefore, you should use it before loading the code that you want to instrument.
,profile [<expr> | <flag> ...] |
profiler control |
[Synonyms: ,prof] |
This command can perform profiling of code in one of two very different ways: either statistical profiling via the profile library, or using the exact profiler feature of errortrace.
When given a parenthesized expression, ,profile will run it via the statistical profiler, as with the profile form, reporting results as usual. This profiler adds almost no overhead, and it requires no special setup. In particular, it does not require pre-compiling code in a special way. However, there are some imprecise elements to this profiling: the profiler samples stack snapshots periodically which can miss certain calls, and it is also sensitive to some compiler optimizations like inlining procedures and thereby not showing them in the displayed analysis. See Profile: Statistical Profiler for more information.
In the second mode of operation, ,profile uses the precise errortrace profiler. This profiler produces precise results, but like other uses of the errortrace, it must be enabled before loading the code that is to be profiled. It can add noticeable overhead (potentially affecting the reported runtimes), but the results are accurate in the sense that no procedure is skipped. (For additional details, see Errortrace: Debugging and Profiling.)
In this mode, the arguments are flags that control the profiler. A
+ flag turns the profiler on —
Note that using any of these flags turns errortrace instrumentation on, even ,prof - (or no flags). Use the ,errortrace command to turn off instrumentation completely.
,execution-counts <file> ... |
execution counts |
This command makes it easy to use the execution counts functionality of errortrace. Given a file name (or names), ,execution-counts will enable errortrace instrumentation for coverage, require the file(s), display the results, disables coverage, and disables instrumentation (if it wasn’t previously turned on). This is useful as an indication of how well the test coverage is for some file.
,coverage <file> |
coverage information via a sandbox |
[Synonyms: ,cover] |
Runs a given file and displays coverage information for the run. This is somewhat similar to the ,execution-counts command, but instead of using errortrace directly, it runs the file in a (trusted) sandbox, using the racket/sandbox library and its ability to provide coverage information.
2.5 Miscellaneous Commands
,switch-namespace [<name>] [? | - | ! [<init>]] |
switch to a different repl namespace |
[Synonyms: ,switch] |
This powerful command controls the REPL’s namespace. While ,enter can be used to make the REPL go into the namespace of a specific module, the ,switch-namespace command can switch between toplevel namespaces, allowing you to get multiple separate “workspaces”.
Namespaces are given names that are symbols or integers, where
* is the name for the first initial namespace, serving as
the default one. These names are not bindings —
The most basic usage for this command is to simply specify a new name. A namespace that corresponds to that name will be created and the REPL will switch to that namespace. The prompt will now indicate this namespace’s name. The name is usually insignificant, except when it is a require-able module: in this case, the new namespace is initialized to use that module’s bindings. For example, ,switch racket/base creates a new namespace that is called racket/base and initializes it with racket/base. For all other names, the new namespace is initialized the same as the current one.
,switch ! —
reset the current namespace, recreating it using the same initial library. Note that it is forbidden to reset the default initial namespace, the one named * — this namespace corresponds to the one that Racket was started with, and where XREPL was initialized. There is no technical reason for forbidding this, but doing so is not useful as no resources will actually be freed. ,switch ! <module> —
resets the current namespace with the explicitly given simple module spec. ,switch <name> ! —
switch to a newly made namespace. If a namespace by that name already existed, it is rest. ,switch <name> ! <module> —
same, but reset to the given module instead of what it previously used. ,switch - <name> —
drop the specified namespace, making it possible to garbage-collect away any associated resources. You cannot drop the current namespace or the default one (*). ,switch ? —
list all known namespaces.
Do not confuse namespaces with sandboxes or custodians. The
,switch command changes only the
current-namespace —
,syntax [<expr>] [<flag> ...] |
set syntax object to inspect, and control it |
[Synonyms: ,stx ,st] |
Manipulate syntaxes and inspect their expansion.
Useful operations revolve around a “currently set syntax”. With no arguments, the currently set syntax is displayed; an argument of ^ sets the current syntax from the last input to the REPL; and an argument that holds any other s-expression will set it as the current syntax.
+ uses expand-once on the current syntax and prints the resulting syntax. In addition, the result becomes the new “current” syntax, so you can use this as a poor-man’s syntax stepper. (Note that in some rare cases expansion via a sequence of expand-once might differ from the actual expansion.)
! uses expand to completely expand the current syntax.
* uses the macro debugger’s textual output to show expansion steps for the current syntax, leaving macros from racket/base intact. Does not change the current syntax. Uses expand/step-text, see Macro Debugger: Inspecting Macro Expansion for details.
** uses the macro debugger similarly to *, but expands racket/base macros too, showing the resulting full expansion process.
,check-requires [<module>] |
check the `require's of a module |
[Synonyms: ,ckreq] |
Uses show-requires to analyze the requires of the specified module, defaulting to the currently entered module if we’re in one. See Macro Debugger: Inspecting Macro Expansion for details.
,log <level> |
control log output |
a known level name (currently one of fatal, error, warning, info, debug),
#f for no logging,
#t for maximum logging,
an integer level specification, with 0 for no logging and bigger ones for additional verbosity.
install xrepl in your Racket init file |
Convenient utility command to install XREPL in your Racket initialization file. This is done carefully, you will be notified of potential issues, and asked to authorize changes.
3 Past Evaluation Results
XREPL makes the last few interaction results available for evaluation via special toplevel variables: ^, ^^, ..., ^^^^^. The first, ^, refers to the last result, ^^ to the previous one and so on.
-> 1 |
1 |
-> (values 2 3) |
2 |
3 |
-> (values 4) |
4 |
-> (list ^ ^^ ^^^ ^^^^) |
'(4 3 2 1) |
In addition to these names, XREPL also binds $1, $2, ..., $5 to the same references, so you can choose the style that you like. All of these bindings are made available only if they are not already defined. This means that if you have code that uses these names, it will continue to work as usual (and it will shadow the saved value binding).
The bindings are identifier macros that expand to the literal saved values; so referring to a saved value that is missing (because not enough values were shown) raises a syntax error. In addition, the values are held in a weak reference, so they can disappear after a garbage-collection.
Note that this facility can be used to “transfer” values from one
namespace to another—
4 Hacking XREPL
XREPL is mainly a convenience tool, and as such you might want to hack it to better suite your needs. Currently, there is no convenient way to customize and extend it, but this will be added in the future.
-> ,en xrepl/xrepl |
xrepl/xrepl> ,e |
xrepl/xrepl> (saved-values-char #\~) |
xrepl/xrepl> ,top |
-> 123 |
123 |
-> ~ |
123 |
-> ,en xrepl/xrepl |
xrepl/xrepl> (defcommand eli "stuff" "eli says" ["Make eli say stuff"] |
(printf "Eli says: ~a\n" (getarg 'line))) |
xrepl/xrepl> ,top |
-> ,eli moo |
Eli says: moo |
If you have any useful tweaks and extensions, please mail the author or the Racket developer’s mailing list.
5 License Issues
Under most circumstances XREPL uses the readline library, and therefore a similar license caveat applies: XREPL cannot be enabled by default because of the readline licensing, you have to explicitly do so yourself to use it. (Note that XREPL is intended to be used only for enhanced interaction, not as a library; so there are no additional issues.)