From fe6ea164bf4d240845025c5d81d0f00ba7c3f1ff Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Thu, 26 Mar 2026 15:08:12 +0400 Subject: [PATCH] v10: /color command to reshuffle user colors (web + terminal) Co-Authored-By: Claude Opus 4.6 (1M context) --- chat.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/chat.py b/chat.py index 73559b1..4a0874c 100644 --- a/chat.py +++ b/chat.py @@ -25,7 +25,7 @@ import html import urllib.parse PORT = 9999 -VERSION = "9" +VERSION = "10" TUNNEL_TARGETS = { "parspack": ("185.208.174.152", 22), "mequ": ("188.213.68.133", 2022), @@ -149,13 +149,23 @@ const USER_COLORS = [ '#ffb74d', '#aed581', '#f06292', '#4dd0e1' ]; +let colorSeed = 0; // bump this to rearrange colors + function userColor(name) { if (name === $name.value.trim()) return '#4ade80'; - let h = 0; + let h = colorSeed; for (let i = 0; i < name.length; i++) h = ((h << 5) - h + name.charCodeAt(i)) | 0; return USER_COLORS[Math.abs(h) % USER_COLORS.length]; } +function reshuffleColors() { + colorSeed = Math.floor(Math.random() * 100000); + // re-render all messages + const msgs = document.querySelectorAll('.msg'); + // can't easily re-render, so just note it applies to new messages + addMsg({ts: Date.now()/1000, user: '***', text: 'Colors reshuffled!'}); +} + function esc(s) { const d = document.createElement('div'); d.textContent = s; @@ -217,6 +227,13 @@ function send() { const text = $input.value.trimEnd(); const name = $name.value.trim() || 'anon'; if (!text) return; + // Local commands + if (text === '/colors' || text === '/color') { + reshuffleColors(); + $input.value = ''; + $input.style.height = 'auto'; + return; + } fetch('/chat/send', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, @@ -723,6 +740,18 @@ class ChatClient: self.reader: asyncio.StreamReader | None = None self.writer: asyncio.StreamWriter | None = None self.running = True + self.color_seed = 0 + + def get_color(self, username: str) -> int: + """Color pair for username, affected by color_seed.""" + if username == "***": + return CP_SYSTEM + if username == self.name: + return CP_MY_NAME + h = self.color_seed + for c in username: + h = ((h << 5) - h + ord(c)) & 0xFFFFFFFF + return 10 + (h % len(OTHER_CURSES_COLORS)) def notify(self, msg: dict): """Send terminal bell + update title for messages from others.""" @@ -742,7 +771,7 @@ class ChatClient: def add_message(self, msg: dict): t = time.strftime("%H:%M", time.localtime(msg["ts"])) - cp = user_color_pair(msg["user"], self.name) + cp = self.get_color(msg["user"]) if msg["user"] == "***": self.messages.append((f" {t} {msg['text']}", CP_SYSTEM)) elif msg.get("file_id"): @@ -850,6 +879,9 @@ class ChatClient: cmd = self.input_buf.strip() if cmd == "/quit": break + elif cmd in ("/color", "/colors"): + self.color_seed += 1 + self.messages.append((" *** Colors reshuffled!", CP_SYSTEM)) elif cmd.startswith("/file "): await self.send_file(cmd[6:].strip()) else: