Skip to content

feat: add external break signal for read_line interruption and mark Signal as non_exhaustive#1035

Merged
fdncred merged 3 commits intonushell:mainfrom
eitsupi:feat/external-break-signal
Mar 12, 2026
Merged

feat: add external break signal for read_line interruption and mark Signal as non_exhaustive#1035
fdncred merged 3 commits intonushell:mainfrom
eitsupi:feat/external-break-signal

Conversation

@eitsupi
Copy link
Copy Markdown
Contributor

@eitsupi eitsupi commented Mar 11, 2026

Add a break signal that allows external threads to interrupt read_line(), causing it to return a new Signal::ExternalBreak(String) variant with the current buffer contents.

Motivation

Applications that embed a REPL alongside external control systems (e.g., AI agents) need a way to interrupt read_line() from another thread.
For example, an AI agent controlling the console may need to inject input while the user is at the prompt — but read_line() is a blocking loop with no external interruption mechanism.

Currently, there is no way for an external thread to cause read_line() to return.
The external_printer feature can print messages above the prompt, but cannot break out of the input loop.
The idle_callback feature (#1015) allows periodic processing but also cannot cause an early return.

Design

The break signal check is placed in the read_line_helper loop alongside idle_callback and external_printer.
When break_signal is configured, needs_polling is set to true so read_line() uses poll() instead of blocking indefinitely on crossterm::event::read().

API

use std::sync::{atomic::AtomicBool, Arc};

let break_signal = Arc::new(AtomicBool::new(false));
let mut editor = Reedline::create()
    .with_break_signal(break_signal.clone());

// From another thread:
break_signal.store(true, Ordering::Relaxed);

// read_line() returns:
// Ok(Signal::ExternalBreak(buffer_contents))

Note

Signal is now #[non_exhaustive].
Downstream match arms on Signal will need a wildcard _ pattern.
This is a one-time change that prevents future additions from being breaking.

@eitsupi eitsupi changed the title feat!: add external break signal for read_line interruption and mark Signal as non_exhaustive feat: add external break signal for read_line interruption and mark Signal as non_exhaustive Mar 11, 2026
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Mar 11, 2026

Is there any way to test this automatically and/or manually?

@eitsupi
Copy link
Copy Markdown
Contributor Author

eitsupi commented Mar 12, 2026

Is there any way to test this automatically and/or manually?

I've added an example so you can test it manually.

Automated testing requires a terminal, which is tested in arf test suite (eitsupi/arf#113) using https://github.com/doy/vt100-rust (unfortunately not compatible with Windows).

@fdncred fdncred merged commit 5c2f105 into nushell:main Mar 12, 2026
7 checks passed
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Mar 12, 2026

Thanks!

@Juhan280
Copy link
Copy Markdown
Contributor

Hi. I was bumping reedline in nushell. How should nushell handle this? Should it just ignore it? Both nusehll repl and the input command uses it.

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Mar 12, 2026

@Juhan280 For now it can be ignored but in the future it would be cool to have proper support for it.

@Juhan280
Copy link
Copy Markdown
Contributor

Ok

@eitsupi eitsupi deleted the feat/external-break-signal branch March 12, 2026 15:05
eitsupi added a commit to eitsupi/arf that referenced this pull request Mar 19, 2026
…113)

## Summary

Add an experimental JSON-RPC 2.0 IPC server for AI agents, IDE extensions, and other external tools to interact with a running arf R session.

### Features

- **Transport**: Unix domain sockets (Linux/macOS), Windows named pipes
- **Protocol**: JSON-RPC 2.0 over HTTP (curl-compatible) or raw JSON
- **`evaluate` method**: Silent or visible evaluation with captured stdout/value/error via WriteConsoleEx interception
- **`user_input` method**: Inject code into the REPL via reedline's `ExternalBreak` signal (nushell/reedline#1035), with full echo, history, spinner, and duration tracking
- **`send` method**: Alias for `user_input`
- **`:ipc` meta command**: Start/stop/check server status at runtime
- **`arf ipc` subcommand**: CLI client for eval/send/list/status from another terminal
- **Session discovery**: `~/.cache/arf/sessions/<pid>.json`, cleaned up on exit

### Safety

- Mutual exclusion with console input: IPC requests are rejected with `USER_IS_TYPING` (-32003) when the user has typed something in the buffer
- Alternate screen modes (help pager, history browser, shell mode): IPC requests are rejected immediately with `R_NOT_AT_PROMPT` (-32001)
- Prompt position is preserved after rejected ExternalBreak (reedline fix: nushell/reedline#1042)

### Tests

- 7 cross-platform IPC unit tests (protocol, evaluate, user_input)
- 6 PTY integration tests (evaluate capture, visible/silent modes, user_input, rejection, prompt position)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants