# How Text Mode Handles Multiline Input Submission with Ctrl+D in ngpt

> Discover how ngpt text mode handles multiline input submission with Ctrl+D. Learn how it captures your complete buffer for seamless interaction.

- Repository: [nazDridoy/ngpt](https://github.com/nazdridoy/ngpt)
- Tags: internals
- Published: 2026-03-07

---

**The ngpt CLI captures multiline input in text mode by detecting Ctrl+D either as a key binding in the prompt-toolkit editor or as an EOFError in the plain stdin fallback, returning the complete buffer content as the prompt.**

The `nazdridoy/ngpt` repository provides a flexible command-line interface for interacting with LLMs. When operating in **text mode**, the tool must accommodate detailed prompts that span multiple lines, requiring a reliable mechanism to signal when the user has finished typing. The implementation handles **multiline input submission** through two distinct paths depending on whether the optional prompt-toolkit library is available.

## How Multiline Input Works in ngpt Text Mode

The architecture delegates input collection to a centralized UI module while keeping the mode-specific logic separate. This separation ensures consistent behavior across different interface implementations.

### The Entry Point in text.py

The `text_mode()` function in [`ngpt/cli/modes/text.py`](https://github.com/nazdridoy/ngpt/blob/main/ngpt/cli/modes/text.py) serves as the primary orchestrator. When invoked without a pre-supplied prompt via command-line arguments, it calls `get_multiline_input()` to gather user input interactively.

```python

# From ngpt/cli/modes/text.py, lines 17-23

if args.prompt is not None:
    prompt = args.prompt
else:
    prompt = get_multiline_input()

```

This delegation allows the text mode to remain agnostic of how the input is physically collected, whether through a rich TUI or basic terminal stdin.

### The UI Layer in tui.py

The [`ngpt/ui/tui.py`](https://github.com/nazdridoy/ngpt/blob/main/ngpt/ui/tui.py) file contains the `get_multiline_input()` function and the `create_multiline_editor()` helper. The module checks for the presence of **prompt-toolkit** via a `HAS_PROMPT_TOOLKIT` flag and branches accordingly to provide the appropriate input mechanism.

## Ctrl+D Handling in Prompt-Toolkit Mode

When prompt-toolkit is available, ngpt constructs a dedicated multiline editor instance. The `create_multiline_editor()` function registers a custom key binding that intercepts **Ctrl+D** to submit the buffer.

```python

# From ngpt/ui/tui.py, lines 42-46

@kb.add('c-d')
def _(event):
    event.app.exit(result=event.app.current_buffer.text)

```

Pressing **Ctrl+D** triggers this binding, which exits the application context and returns the complete text from the current buffer. This method preserves formatting and newlines exactly as typed, providing a seamless multiline editing experience with syntax highlighting and cursor movement capabilities.

## Ctrl+D Handling in Fallback Mode (Plain Stdin)

If prompt-toolkit is not installed or the editor initialization fails, ngpt falls back to a basic stdin implementation. The `get_multiline_input()` function handles **Ctrl+D** by catching the `EOFError` that Python raises when reading past the end of a file stream.

```python

# From ngpt/ui/tui.py, lines 49-57

print("Enter your multi-line prompt (press Ctrl+D to submit):")
lines = []
while True:
    try:
        line = input()
        lines.append(line)
    except EOFError:  # Ctrl+D was pressed

        break
return "\n".join(lines)

```

In this scenario, the user types lines normally, pressing Enter after each one. When ready to submit, pressing **Ctrl+D** sends an EOF signal, raising `EOFError` and breaking the input loop. The function then joins all collected lines with newline characters and returns the resulting string as the final prompt.

## Practical Code Examples

### Using the Built-in Editor (Prompt-Toolkit Installed)

When running `ngpt text` with the rich UI available, the editor opens as a full-screen interface. Type your multiline prompt naturally, then press **Ctrl+D** to submit.

```bash
$ ngpt text

# ... editor opens ...

# (User writes multiple lines of text)

# Press Ctrl+D

# The editor closes and the complete buffer is sent to the LLM

```

### Fallback to Plain Stdin (No Prompt-Toolkit)

Without the optional dependency, the CLI provides clear instructions for submission via **Ctrl+D**.

```bash
$ ngpt text
Enter your multi-line prompt (press Ctrl+D to submit):
First line of the request
Second line, still part of the same prompt
Third line with details
<Ctrl+D>

# The tool combines the lines and sends:

# "First line of the request\nSecond line, still part of the same prompt\nThird line with details"

```

### Bypassing Multiline Input with CLI Flags

To avoid the interactive multiline interface entirely, provide the prompt directly using the `--prompt` flag.

```bash
$ ngpt text --prompt "Summarize this article."

# No multiline input UI is invoked; the prompt is sent immediately.

```

## Summary

- **Text mode** in `nazdridoy/ngpt` handles multiline input through the `get_multiline_input()` function in [`ngpt/ui/tui.py`](https://github.com/nazdridoy/ngpt/blob/main/ngpt/ui/tui.py).
- When **prompt-toolkit** is available, **Ctrl+D** triggers a key binding in `create_multiline_editor()` that exits the editor and returns the buffer text.
- In the **fallback mode**, **Ctrl+D** raises an `EOFError` in the stdin loop, breaking the collection and joining the lines into a single prompt string.
- The entry point in [`ngpt/cli/modes/text.py`](https://github.com/nazdridoy/ngpt/blob/main/ngpt/cli/modes/text.py) orchestrates this flow, allowing users to submit complex, formatted prompts regardless of their terminal capabilities.

## Frequently Asked Questions

### What happens if I press Ctrl+C instead of Ctrl+D in multiline mode?

Pressing **Ctrl+C** sends a `KeyboardInterrupt` signal, which typically terminates the entire `ngpt` process immediately rather than submitting the input. Unlike **Ctrl+D**, which signals end-of-file and triggers the submission logic in `get_multiline_input()`, **Ctrl+C** is not caught by the input loops and will cause the CLI to exit without sending any prompt to the LLM.

### Can I use Ctrl+D to submit input if I have prompt-toolkit installed?

Yes. When **prompt-toolkit** is installed, `ngpt` uses the `create_multiline_editor()` function which registers a specific key binding for `c-d` (Ctrl+D). Pressing this combination exits the full-screen editor and returns the complete buffer content as the prompt. This provides a more interactive editing experience with syntax highlighting and cursor movement while maintaining the same **Ctrl+D** submission gesture as the fallback mode.

### Why does the fallback mode print a specific message about Ctrl+D?

The fallback implementation in `get_multiline_input()` explicitly prints `"Enter your multi-line prompt (press Ctrl+D to submit):"` because the basic `input()` function in Python does not provide any visual indication that it is waiting for multiline input or how to terminate entry. Without this instruction, users might not realize they need to send an EOF signal to complete their prompt, potentially leaving them stuck in the input loop or unsure how to proceed.

### Does ngpt preserve newlines when submitting multiline input?

Yes. In both the prompt-toolkit and fallback paths, **ngpt** preserves newline characters exactly as entered. In the prompt-toolkit path, `event.app.current_buffer.text` returns the raw buffer content including `\n` characters. In the fallback path, the code explicitly joins the collected lines with `"\n".join(lines)`, ensuring that line breaks are maintained in the final prompt string sent to the LLM.