Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code_puppy/cli_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
emit_system_message("Type 'clear' to reset the conversation history.")
emit_system_message("Type /help to view all commands")
emit_system_message(
"Type @ for path completion, or /model to pick a model. Toggle multiline with Alt+M or F2; newline: Ctrl+J."
"Type @ for path completion, or /model to pick a model. Toggle multiline with Alt+M or F2; newline: Shift+Enter or Ctrl+J."
)
emit_system_message("Paste images: Ctrl+V (even on Mac!), F3, or /paste command.")
import platform
Expand Down
11 changes: 11 additions & 0 deletions code_puppy/command_line/prompt_toolkit_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,17 @@ def _(event):
except Exception:
pass

# Shift+Enter for newline (terminal-dependent — works in modern terminals
# like kitty, WezTerm, iTerm2, and Windows Terminal that support CSI u /
# kitty keyboard protocol; silently ignored on older terminals).
try:

@bindings.add("s-enter", eager=True)
def _(event):
event.app.current_buffer.insert_text("\n")
except Exception:
pass
Comment on lines +645 to +654
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== prompt_toolkit 3.0.52 supported key names =="
curl -fsSL https://raw.githubusercontent.com/prompt-toolkit/python-prompt-toolkit/3.0.52/src/prompt_toolkit/keys.py \
  | rg -n '"s-enter"|"c-enter"|Shift|Enter = "c-m"|BackTab'

echo
echo "== prompt_toolkit key validation path =="
curl -fsSL https://raw.githubusercontent.com/prompt-toolkit/python-prompt-toolkit/3.0.52/src/prompt_toolkit/key_binding/key_bindings.py \
  | rg -n '_parse_key|Invalid key|Keys\(key\)|len\(key\) != 1'

Repository: mpfaffenberger/code_puppy

Length of output: 1795


Update or remove Shift+Enter handler that silently fails to register.

prompt_toolkit 3.0.52 does not define s-enter as a valid key name. When KeyBindings.add("s-enter", ...) is called, _parse_key() rejects it with ValueError (unrecognized multi-character keys raise Invalid key), and the surrounding try/except silently swallows the error. This means Shift+Enter is never installed, even though the CLI help and test imply it works.

Either remove this handler if Shift+Enter support is not available, or replace it with a terminal-aware implementation that actually works. Update any help text or tests that describe this feature as available.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code_puppy/command_line/prompt_toolkit_completion.py` around lines 645 - 654,
The Shift+Enter keybinding registration using bindings.add("s-enter", ...) is
silently swallowed by the surrounding try/except because prompt_toolkit 3.0.52
does not recognize "s-enter"; update the code by either removing the failing
handler or replacing it with a terminal-aware implementation: detect terminal
capabilities and register a valid key sequence (or CSI/kitty protocol sequence)
that prompt_toolkit accepts instead of "s-enter", or skip registration and
update help/tests; locate the handler added via bindings.add("s-enter",
eager=True) and the anonymous function def _(event) that inserts "\n" and change
its registration logic accordingly so the binding is only installed when a
supported key name/sequence is validated.


# Enter behavior depends on multiline mode
@bindings.add("enter", filter=~is_searching, eager=True)
def _(event):
Expand Down
8 changes: 8 additions & 0 deletions tests/command_line/test_prompt_toolkit_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,14 @@ def test_ctrl_enter_newline(self, captured_bindings):
handler(event)
event.app.current_buffer.insert_text.assert_called_with("\n")

def test_shift_enter_newline(self, captured_bindings):
"""Test shift-enter inserts newline (terminal-dependent)."""
handler = self._find_handler(captured_bindings, "s-enter")
if handler is not None:
event = MagicMock()
handler(event)
event.app.current_buffer.insert_text.assert_called_with("\n")

Comment on lines +988 to +995
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make this test fail when the binding is missing.

if handler is not None turns this into a no-op, so CI stays green even when Shift+Enter is never registered.

Proposed fix
     def test_shift_enter_newline(self, captured_bindings):
         """Test shift-enter inserts newline (terminal-dependent)."""
         handler = self._find_handler(captured_bindings, "s-enter")
-        if handler is not None:
-            event = MagicMock()
-            handler(event)
-            event.app.current_buffer.insert_text.assert_called_with("\n")
+        assert handler is not None
+        event = MagicMock()
+        handler(event)
+        event.app.current_buffer.insert_text.assert_called_with("\n")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_shift_enter_newline(self, captured_bindings):
"""Test shift-enter inserts newline (terminal-dependent)."""
handler = self._find_handler(captured_bindings, "s-enter")
if handler is not None:
event = MagicMock()
handler(event)
event.app.current_buffer.insert_text.assert_called_with("\n")
def test_shift_enter_newline(self, captured_bindings):
"""Test shift-enter inserts newline (terminal-dependent)."""
handler = self._find_handler(captured_bindings, "s-enter")
assert handler is not None
event = MagicMock()
handler(event)
event.app.current_buffer.insert_text.assert_called_with("\n")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/command_line/test_prompt_toolkit_coverage.py` around lines 988 - 995,
The test test_shift_enter_newline currently skips if the Shift+Enter binding is
missing; change it to fail instead by asserting the handler exists and then
invoking it: locate the use of _find_handler(captured_bindings, "s-enter") in
test_shift_enter_newline, replace the conditional no-op with an explicit
assertion that handler is not None (or raise an AssertionError) so the test
fails when the binding isn't registered, then keep calling handler(event) and
asserting event.app.current_buffer.insert_text.assert_called_with("\n").

def test_ctrl_v_linux_xsel_fallback_filenotfound(self, captured_bindings):
"""Cover the FileNotFoundError xsel fallback path."""
handler = self._find_handler(captured_bindings, "c-v")
Expand Down
Loading