fix: escape Rich markup in card/conclusion/message content, keyboard hints on welcome
This commit is contained in:
parent
ab0ff2f052
commit
109ff8d5a2
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from rich.markup import escape as markup_escape
|
||||
from textual.app import ComposeResult
|
||||
from textual.widget import Widget
|
||||
from textual.widgets import Static
|
||||
|
|
@ -86,11 +87,11 @@ class PeerPanel(Widget):
|
|||
scroll.mount(Static(f"[{ACCENT}]CARD[/{ACCENT}]", classes="section-label"))
|
||||
|
||||
if card and card.strip():
|
||||
# Wrap long lines, show first 400 chars
|
||||
preview = card.strip()[:400]
|
||||
if len(card.strip()) > 400:
|
||||
preview += f"\n[{FG_MUTED}]… {len(card.strip()) - 400} more chars[/{FG_MUTED}]"
|
||||
scroll.mount(Static(preview, classes="card-body"))
|
||||
raw = card.strip()
|
||||
preview = markup_escape(raw[:400])
|
||||
if len(raw) > 400:
|
||||
preview += f"\n[{FG_MUTED}]… {len(raw) - 400} more chars[/{FG_MUTED}]"
|
||||
scroll.mount(Static(preview, classes="card-body", markup=True))
|
||||
else:
|
||||
scroll.mount(Static(f"[{FG_DIM}]no card yet[/{FG_DIM}]", classes="card-body"))
|
||||
|
||||
|
|
@ -103,11 +104,14 @@ class PeerPanel(Widget):
|
|||
else:
|
||||
for i, c in enumerate(conclusions[:12]):
|
||||
content = c.get("content", "")
|
||||
# Truncate to fit panel width
|
||||
preview = content[:55] + "…" if len(content) > 55 else content
|
||||
safe = markup_escape(content[:55] + "…" if len(content) > 55 else content)
|
||||
prefix = TREE_LAST if i == min(len(conclusions), 12) - 1 else TREE_MID
|
||||
scroll.mount(
|
||||
Static(f"[{FG_DIM}]{prefix}[/{FG_DIM}][{FG}]{preview}[/{FG}]", classes="conclusion-row")
|
||||
Static(
|
||||
f"[{FG_DIM}]{prefix}[/{FG_DIM}][{FG}]{safe}[/{FG}]",
|
||||
classes="conclusion-row",
|
||||
markup=True,
|
||||
)
|
||||
)
|
||||
if count > 12:
|
||||
scroll.mount(Static(f"[{FG_MUTED}] … {count - 12} more[/{FG_MUTED}]"))
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import datetime
|
||||
|
||||
from rich.markup import escape as markup_escape
|
||||
from rich.text import Text
|
||||
from textual.app import ComposeResult
|
||||
from textual.message import Message
|
||||
|
|
@ -72,21 +73,26 @@ class TranscriptPanel(Widget):
|
|||
if self._streaming:
|
||||
self._update_stream_cursor()
|
||||
|
||||
def _update_stream_cursor(self) -> None:
|
||||
log = self.query_one("#log", RichLog)
|
||||
cursor_char = CURSOR if self._cursor_on else " "
|
||||
# Cursor line is updated via the streaming append path
|
||||
_ = cursor_char # referenced during actual stream writes
|
||||
|
||||
# ── Public API ────────────────────────────────────────────────────────────
|
||||
|
||||
def show_welcome(self) -> None:
|
||||
log = self.query_one("#log", RichLog)
|
||||
log.clear()
|
||||
t = Text()
|
||||
t.append(" HONCHO\n", style=f"bold {ACCENT}")
|
||||
t.append("\n HONCHO\n", style=f"bold {ACCENT}")
|
||||
t.append(" memory that reasons\n\n", style=FG_MUTED)
|
||||
t.append(f" [{FG_MUTED}]select a session or query the dialectic[/{FG_MUTED}]\n")
|
||||
t.append(" select a session from the left panel\n", style=FG_DIM)
|
||||
t.append(" or query the dialectic below\n\n", style=FG_DIM)
|
||||
t.append(" bindings\n", style=f"bold {FG_DIM}")
|
||||
binds = [
|
||||
("ctrl+d", "focus dialectic input"),
|
||||
("tab", "focus session list"),
|
||||
("r", "refresh"),
|
||||
("q", "quit"),
|
||||
]
|
||||
for key, desc in binds:
|
||||
t.append(f" {key}", style=f"bold {ACCENT}")
|
||||
t.append(f" {desc}\n", style=FG_MUTED)
|
||||
log.write(t)
|
||||
|
||||
def show_no_workspace(self) -> None:
|
||||
|
|
@ -153,10 +159,12 @@ class TranscriptPanel(Widget):
|
|||
header.append("\n")
|
||||
log.write(header)
|
||||
|
||||
# Content
|
||||
# Content — escape raw text so Rich markup chars don't break rendering
|
||||
body = Text()
|
||||
for line in content.splitlines():
|
||||
body.append(f" {line}\n", style=FG)
|
||||
body.append(" ", style=FG)
|
||||
body.append(line, style=FG)
|
||||
body.append("\n")
|
||||
if not content.strip():
|
||||
body.append(" (empty)\n", style=FG_MUTED)
|
||||
log.write(body)
|
||||
|
|
@ -176,7 +184,9 @@ class TranscriptPanel(Widget):
|
|||
resp = Text()
|
||||
resp.append(" dialectic\n", style=f"bold {GREEN}")
|
||||
for line in content.splitlines():
|
||||
resp.append(f" {line}\n", style=FG)
|
||||
resp.append(" ", style=FG)
|
||||
resp.append(line, style=FG)
|
||||
resp.append("\n")
|
||||
resp.append("\n")
|
||||
log.write(resp)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue