ml-knowledge-platform/knowledge_platform/widgets/prompt_input.py
Lilith 240b4328f1 chore(config): 🔧 Update 40 configuration files across project
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-16 01:39:57 -08:00

96 lines
2.9 KiB
Python

from dataclasses import dataclass
from textual import events, on
from textual.binding import Binding
from textual.reactive import reactive
from textual.widgets import TextArea
from textual.message import Message
class PromptInput(TextArea):
@dataclass
class PromptSubmitted(Message):
text: str
prompt_input: "PromptInput"
@dataclass
class CursorEscapingTop(Message):
pass
@dataclass
class CursorEscapingBottom(Message):
pass
BINDINGS = [
Binding("enter", "submit_prompt", "Send message", key_display="", priority=True),
]
submit_ready = reactive(True)
def __init__(
self,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
disabled: bool = False,
) -> None:
super().__init__(
name=name, id=id, classes=classes, disabled=disabled, language="markdown"
)
def on_key(self, event: events.Key) -> None:
# Shift+Enter or backslash inserts a newline
if event.key == "shift+enter":
event.prevent_default()
self.insert("\n")
event.stop()
return
if event.key == "backslash":
event.prevent_default()
self.insert("\n")
event.stop()
return
if self.cursor_location == (0, 0) and event.key == "up":
event.prevent_default()
self.post_message(self.CursorEscapingTop())
event.stop()
elif self.cursor_at_end_of_text and event.key == "down":
event.prevent_default()
self.post_message(self.CursorEscapingBottom())
event.stop()
def watch_submit_ready(self, submit_ready: bool) -> None:
self.set_class(not submit_ready, "-submit-blocked")
def on_mount(self):
self.border_title = "Enter your [u]m[/]essage..."
@on(TextArea.Changed)
async def prompt_changed(self, event: TextArea.Changed) -> None:
text_area = event.text_area
if text_area.text.strip() != "":
text_area.border_subtitle = "[[white]⏎[/]] Send [[white]⇧⏎[/]] Newline"
else:
text_area.border_subtitle = None
text_area.set_class(text_area.wrapped_document.height > 1, "multiline")
# TODO - when the height of the textarea changes
# things don't appear to refresh correctly.
# I think this may be a Textual bug.
# The refresh below should not be required.
self.parent.refresh()
def action_submit_prompt(self) -> None:
if self.text.strip() == "":
self.notify("Cannot send empty message!")
return
if self.submit_ready:
message = self.PromptSubmitted(self.text, prompt_input=self)
self.clear()
self.post_message(message)
else:
self.app.bell()
self.notify("Please wait for response to complete.")