Skip to content

Commit 75cbdfd

Browse files
committed
feat(repl): dot-commands, ${_} last-result, signature hints, session export
A grab-bag of power-user features for the interactive REPL: - Dot-commands intercepted before Robot's parser sees them — `.help` (with per-command drill-down via `.help <cmd>`), `.imports`, `.vars`, `.kw <name>`, `.doc <library>`, `.history`/`.history clear`/`.history del <N>`, `.cwd`, `.clear`, `.save [-a] [-t name] <file>`, `.exit`. Help text on each command documents its flags and shows examples. - `${_}` mirrors the last keyword's non-None return value, like Python's interactive `_`. Works in the next argument with no `${tmp}=` step. - F1 invokes `.help` from the prompt; Ctrl-R reverse-search now documented (was already wired via prompt_toolkit defaults). - Bottom row shows the active keyword's signature with the current argument highlighted when the cursor sits in an argument cell. Named-arg syntax (`html=True`) follows the spec position, not the positional cell index. Outside an argument cell the row is hidden so the prompt stays uncluttered. - Embedded-argument completion: `Literal[...]`-typed parameters on RF 7+ expose their allowed values as completion candidates after `name=`. Silently no-ops on RF 5/6. - `.save` writes the session to a runnable `.robot` file with imports hoisted into a `*** Settings ***` section. All features are prompt_toolkit-aware where it matters but degrade cleanly on the readline and plain backends.
1 parent 7e0c881 commit 75cbdfd

17 files changed

Lines changed: 2830 additions & 221 deletions

docs/03_reference/repl.md

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ Tab understands Robot's cell-separator semantics (2+ spaces or a tab) and its ca
128128
| After `Import Library ` | Library names — installed modules (`Coll<Tab>``Collections`), dotted module paths (`robot.libraries.Coll<Tab>`), filesystem paths (`./libs/My<Tab>``./libs/MyLib.py`) |
129129
| After `Import Resource ` | `.robot` / `.resource` files on disk |
130130
| After `Import Variables ` | `.py` / `.yaml` / `.yml` / `.json` variable files, plus discoverable variables modules |
131+
| After `<keyword> <arg>=` (RF 7+) | Literal values declared on the argument's type — e.g. for a library keyword `my_kw(level: Literal['DEBUG', 'INFO', 'WARN'])`, typing `my_kw level=<Tab>` shows the three options. Activation rules mirror Robot itself: the name before `=` must be a real positional-or-named / named-only argument of the keyword (or the keyword takes `**kwargs`). Otherwise the cell stays a literal positional value — same as Robot's own runtime behaviour. |
131132

132133
When the prefix is ambiguous the full candidate list appears on the first Tab press — no double-tap, no `Display all NNN possibilities? (y or n)` prompt.
133134

@@ -166,16 +167,18 @@ The completer runs in a background thread (`complete_in_thread=True`), and Robot
166167

167168
History is shared with the readline backend — same plain-text file, so swapping between the two extras (or having neither) doesn't lose arrow-up recall.
168169

169-
#### Session-context bottom toolbar
170+
#### Argument signature in the bottom row
170171

171-
A status line at the bottom of the prompt shows two pieces of orientation info at a glance:
172+
When the cursor sits in an argument cell of a recognised keyword, a single status line appears at the bottom of the prompt with the keyword's signature and the active argument highlighted:
172173

173174
```
174-
RF 7.4 · cwd: ~/projects/my-suite
175+
Log message · level='INFO' · html=False · console=False · repr=False
176+
─────────
175177
```
176178

177-
- **RF version** — which Robot Framework is actually running (handy when juggling several venvs).
178-
- **Working directory** — where relative paths in `Import Resource`, `Import Library`, and file-based variables resolve from.
179+
Highlight follows `name=…` syntax: typing `Log msg html=True` lights up `html`, not the positional cell at that index. Falls back to the positional cell index when the name before `=` isn't a real argument of the keyword.
180+
181+
The row only shows up when there's a signature to render — outside of an argument cell (or for an unrecognised keyword) the prompt has no toolbar at all. Discover dot-commands and shortcuts through `.help` instead; `.cwd` prints the working directory on demand.
179182

180183
#### Documentation hints in the popup
181184

@@ -194,6 +197,60 @@ The highlighter uses Robot Framework's own production tokenizer (`robot.api.get_
194197

195198
No additional dependency: Robot is already required by `robotcode-repl`, and the variable decomposer ships with `robotcode-robot`.
196199

200+
### Interactive shortcuts
201+
202+
Across all backends (PlainBackend / Readline / prompt_toolkit, with the obvious caveat that Plain has no editor):
203+
204+
- **`${_}` — last result** — like Python's interactive shell. After every keyword call the return value is mirrored into the Robot variable `${_}`. Use it directly in the next argument: `Evaluate 1 + 2``Log ${_}` prints `3`. Keywords that return `None` (e.g. `Log` itself) don't overwrite `${_}`, so the most recent meaningful value stays reachable across "noisy" interleaved calls.
205+
- **Ctrl-R reverse-history search** — type a substring and press `Ctrl-R` to walk backwards through past entries. Enter accepts, Esc cancels. Works in both the readline and prompt_toolkit backends — we deliberately leave the binding to the framework's default so users don't lose a feature they expect from every modern REPL.
206+
- **Argument signature in the bottom row** — only on the prompt_toolkit backend. When the cursor is in an argument cell of a recognised keyword, a row at the bottom shows the full signature with the active argument highlighted. Outside that context the row is hidden.
207+
208+
### REPL meta-commands
209+
210+
Dot-prefixed commands (lines that start with `.<word>`) are intercepted **before** Robot's parser sees them and run REPL-internal logic — no keyword call, no test step, no log entry. Robot syntax can't legitimately start with a dot, so the prefix is collision-free.
211+
212+
| Command | Effect |
213+
| ----- | ------ |
214+
| `.help [cmd]` | Without an argument: list all dot-commands. With an argument: print detailed help (usage, flags, examples) for that command — e.g. `.help save`. |
215+
| `.imports` | Show loaded libraries and resource files with their source path and keyword count. |
216+
| `.vars [--user]` | Variables in the current scope, name + truncated `repr` of the value. `--user` filters out Robot's internal variables (`${OUTPUT_DIR}`, `${SUITE_NAME}`, …). |
217+
| `.kw <name>` | Rich-rendered Markdown documentation for the keyword: signature, tags, docstring, source path. |
218+
| `.doc <name>` | Rich-rendered Markdown documentation for a library or resource: name, version, intro doc, list of contained keywords with one-line descriptions. Falls back to a fresh `get_library_doc()` load when the library isn't currently imported. |
219+
| `.history [N]` | Show the last N entries (default 20), numbered. |
220+
| `.history clear` | Truncate the in-memory history and the persistent history file. |
221+
| `.history del <N>` | Drop the single entry at index N from both. |
222+
| `.cwd` | Print the current working directory (where relative paths in imports resolve from). |
223+
| `.clear` | Erase the screen. |
224+
| `.save [-a] [-t NAME] <file>` | Export the session as a runnable `.robot` file (see below). |
225+
| `.exit` / `.quit` | Leave the REPL — equivalent to `Ctrl-D` on an empty prompt. |
226+
227+
The `.kw` and `.doc` output goes through `rich.markdown.Markdown` (already a dependency of the `robotcode-plugin` package), so headings, lists, code blocks and inline emphasis render properly in any modern terminal. Robot's docstring format (the default for built-in libraries) is converted to Markdown via `MarkDownFormatter` first, so `*bold*`, `_italic_`, lists, tables and preformatted blocks all survive the round-trip.
228+
229+
### Saving a session as a runnable `.robot` file
230+
231+
`.save scratch.robot` writes the inputs you typed (the ones that round-tripped through Robot's parser without errors) to a `.robot` file you can re-run with `robot scratch.robot`:
232+
233+
```
234+
robotcode repl
235+
>>> Import Library Collections
236+
>>> ${d}= Create Dictionary a=1 b=2
237+
>>> Log ${d}[a]
238+
1
239+
>>> .save scratch.robot
240+
Wrote scratch.robot (3 entries)
241+
>>> .exit
242+
$ robot scratch.robot
243+
```
244+
245+
The exporter does two things automatically:
246+
247+
- **Hoists imports.** `Import Library / Resource / Variables` calls in the session move to a `*** Settings ***` section as `Library / Resource / Variables <name>` (so the resulting file is canonical Robot syntax, not literal REPL replays).
248+
- **Wraps the body** in a single `*** Test Cases ***` block named `REPL Session <ISO-timestamp>`. Override the name with `-t MyTest`.
249+
250+
`-a` appends to an existing file instead of overwriting, so you can build a test suite incrementally across multiple REPL sessions.
251+
252+
Failed entries — anything Robot's parser rejected — are silently skipped, which is why the exported file is always runnable.
253+
197254
### libedit-backed Pythons
198255

199256
macOS' system Python and some Linux interpreters built via `python-build-standalone` (used by `uv`, `rye`, …) link `readline` against **libedit** instead of GNU readline. libedit silently ignores most of the bindings the REPL relies on, so you'd see Tab inserting a literal tab character and the verbose default completion display.

0 commit comments

Comments
 (0)