Add client command to show protocol and terminal info
This commit is contained in:
parent
27db31c976
commit
9fdc7b9cad
2 changed files with 197 additions and 1 deletions
|
|
@ -260,6 +260,69 @@ async def cmd_skills(player: Player, args: str) -> None:
|
||||||
await player.send(" ".join(names) + "\r\n")
|
await player.send(" ".join(names) + "\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_client(player: Player, args: str) -> None:
|
||||||
|
"""Show client protocol negotiation and terminal capabilities."""
|
||||||
|
lines = ["client protocols"]
|
||||||
|
|
||||||
|
# Protocol status
|
||||||
|
gmcp = "active" if player.gmcp_enabled else "not active"
|
||||||
|
msdp = "active" if player.msdp_enabled else "not active"
|
||||||
|
lines.append(f" GMCP: {gmcp}")
|
||||||
|
lines.append(f" MSDP: {msdp}")
|
||||||
|
|
||||||
|
# Terminal info
|
||||||
|
lines.append("terminal")
|
||||||
|
|
||||||
|
# Terminal type from TTYPE negotiation
|
||||||
|
ttype = None
|
||||||
|
if player.writer is not None:
|
||||||
|
ttype = player.writer.get_extra_info("TERM") or None
|
||||||
|
lines.append(f" type: {ttype or 'unknown'}")
|
||||||
|
|
||||||
|
# Terminal size from NAWS
|
||||||
|
cols, rows = 80, 24
|
||||||
|
if player.writer is not None:
|
||||||
|
cols = player.writer.get_extra_info("cols") or 80
|
||||||
|
rows = player.writer.get_extra_info("rows") or 24
|
||||||
|
lines.append(f" size: {cols}x{rows}")
|
||||||
|
|
||||||
|
# Color depth
|
||||||
|
lines.append(f" colors: {player.color_depth}")
|
||||||
|
|
||||||
|
# MTTS capabilities
|
||||||
|
caps = player.caps
|
||||||
|
mtts_flags = []
|
||||||
|
if caps.ansi:
|
||||||
|
mtts_flags.append("ANSI")
|
||||||
|
if caps.vt100:
|
||||||
|
mtts_flags.append("VT100")
|
||||||
|
if caps.utf8:
|
||||||
|
mtts_flags.append("UTF-8")
|
||||||
|
if caps.colors_256:
|
||||||
|
mtts_flags.append("256 colors")
|
||||||
|
if caps.truecolor:
|
||||||
|
mtts_flags.append("truecolor")
|
||||||
|
if caps.mouse_tracking:
|
||||||
|
mtts_flags.append("mouse tracking")
|
||||||
|
if caps.screen_reader:
|
||||||
|
mtts_flags.append("screen reader")
|
||||||
|
if caps.proxy:
|
||||||
|
mtts_flags.append("proxy")
|
||||||
|
if caps.mnes:
|
||||||
|
mtts_flags.append("MNES")
|
||||||
|
if caps.mslp:
|
||||||
|
mtts_flags.append("MSLP")
|
||||||
|
if caps.ssl:
|
||||||
|
mtts_flags.append("SSL")
|
||||||
|
|
||||||
|
if mtts_flags:
|
||||||
|
lines.append(f" MTTS: {', '.join(mtts_flags)}")
|
||||||
|
else:
|
||||||
|
lines.append(" MTTS: none detected")
|
||||||
|
|
||||||
|
await player.send("\r\n".join(lines) + "\r\n")
|
||||||
|
|
||||||
|
|
||||||
# Register the commands command
|
# Register the commands command
|
||||||
register(
|
register(
|
||||||
CommandDefinition(
|
CommandDefinition(
|
||||||
|
|
@ -282,6 +345,17 @@ register(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Register the client command
|
||||||
|
register(
|
||||||
|
CommandDefinition(
|
||||||
|
"client",
|
||||||
|
cmd_client,
|
||||||
|
aliases=[],
|
||||||
|
mode="*",
|
||||||
|
help="show client protocol and terminal info",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def cmd_help(player: Player, args: str) -> None:
|
async def cmd_help(player: Player, args: str) -> None:
|
||||||
"""Show help for a command or skill.
|
"""Show help for a command or skill.
|
||||||
|
|
@ -293,7 +367,7 @@ async def cmd_help(player: Player, args: str) -> None:
|
||||||
args = args.strip()
|
args = args.strip()
|
||||||
if not args:
|
if not args:
|
||||||
await player.send(
|
await player.send(
|
||||||
"type help <command> for details. see also: commands, skills\r\n"
|
"type help <command> for details. see also: commands, skills, client\r\n"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
await _show_command_detail(player, args)
|
await _show_command_detail(player, args)
|
||||||
|
|
|
||||||
122
tests/test_help.py
Normal file
122
tests/test_help.py
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
"""Tests for client command."""
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from mudlib.caps import ClientCaps
|
||||||
|
from mudlib.commands.help import cmd_client
|
||||||
|
from mudlib.player import Player, players
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def clear_state():
|
||||||
|
players.clear()
|
||||||
|
yield
|
||||||
|
players.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_writer():
|
||||||
|
writer = MagicMock()
|
||||||
|
writer.write = MagicMock()
|
||||||
|
writer.drain = AsyncMock()
|
||||||
|
writer.send_gmcp = MagicMock()
|
||||||
|
writer.send_msdp = MagicMock()
|
||||||
|
writer.local_option = MagicMock()
|
||||||
|
writer.local_option.enabled = MagicMock(return_value=True)
|
||||||
|
writer.remote_option = MagicMock()
|
||||||
|
writer.remote_option.enabled = MagicMock(return_value=True)
|
||||||
|
writer.get_extra_info = MagicMock(
|
||||||
|
side_effect=lambda key: {
|
||||||
|
"TERM": "TINTIN",
|
||||||
|
"cols": 191,
|
||||||
|
"rows": 54,
|
||||||
|
}.get(key)
|
||||||
|
)
|
||||||
|
return writer
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_shows_protocols(mock_writer):
|
||||||
|
"""Test client command shows GMCP and MSDP status."""
|
||||||
|
p = Player(name="Test", writer=mock_writer)
|
||||||
|
p.caps = ClientCaps(ansi=True, truecolor=True)
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = mock_writer.write.call_args[0][0]
|
||||||
|
assert "GMCP: active" in output
|
||||||
|
assert "MSDP: active" in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_shows_terminal_info(mock_writer):
|
||||||
|
"""Test client command shows terminal type and size."""
|
||||||
|
p = Player(name="Test", writer=mock_writer)
|
||||||
|
p.caps = ClientCaps(ansi=True)
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = mock_writer.write.call_args[0][0]
|
||||||
|
assert "type: TINTIN" in output
|
||||||
|
assert "size: 191x54" in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_shows_color_depth(mock_writer):
|
||||||
|
"""Test client command shows color depth."""
|
||||||
|
p = Player(name="Test", writer=mock_writer)
|
||||||
|
p.caps = ClientCaps(ansi=True, truecolor=True, colors_256=True)
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = mock_writer.write.call_args[0][0]
|
||||||
|
assert "colors: truecolor" in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_shows_mtts_flags(mock_writer):
|
||||||
|
"""Test client command shows MTTS capabilities."""
|
||||||
|
p = Player(name="Test", writer=mock_writer)
|
||||||
|
p.caps = ClientCaps(ansi=True, vt100=True, utf8=True, colors_256=True)
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = mock_writer.write.call_args[0][0]
|
||||||
|
assert "ANSI" in output
|
||||||
|
assert "VT100" in output
|
||||||
|
assert "UTF-8" in output
|
||||||
|
assert "256 colors" in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_not_negotiated(mock_writer):
|
||||||
|
"""Test client command when protocols not negotiated."""
|
||||||
|
mock_writer.local_option.enabled.return_value = False
|
||||||
|
mock_writer.remote_option.enabled.return_value = False
|
||||||
|
|
||||||
|
p = Player(name="Test", writer=mock_writer)
|
||||||
|
p.caps = ClientCaps()
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = mock_writer.write.call_args[0][0]
|
||||||
|
assert "GMCP: not active" in output
|
||||||
|
assert "MSDP: not active" in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_client_no_mtts():
|
||||||
|
"""Test client command with no MTTS capabilities."""
|
||||||
|
writer = MagicMock()
|
||||||
|
writer.write = MagicMock()
|
||||||
|
writer.drain = AsyncMock()
|
||||||
|
writer.local_option = MagicMock()
|
||||||
|
writer.local_option.enabled = MagicMock(return_value=False)
|
||||||
|
writer.remote_option = MagicMock()
|
||||||
|
writer.remote_option.enabled = MagicMock(return_value=False)
|
||||||
|
writer.get_extra_info = MagicMock(return_value=None)
|
||||||
|
|
||||||
|
p = Player(name="Test", writer=writer)
|
||||||
|
p.caps = ClientCaps()
|
||||||
|
await cmd_client(p, "")
|
||||||
|
|
||||||
|
output = writer.write.call_args[0][0]
|
||||||
|
assert "type: unknown" in output
|
||||||
|
assert "MTTS: none detected" in output
|
||||||
Loading…
Reference in a new issue