Client/main:
- Colorize display: hide raw IDs in rendered messages
- Chat lines now “Name: message” (ID omitted)
- [join]/[leave] now “[join] Name” / “[leave] Name”
- [rename] now “[rename] OldName -> NewName”
- Welcome now “Welcome Name”
- Init: if already connected, start reading immediately (textarea.Blink + readLineCmd)
- Pre-connect before TUI starts:
- Dial with 3s timeout, read up to two initial lines with 1s deadline
- Seed model with pre-read messages and existing conn
Server:
- IDs now lowercase hex; default username uses ID as-is
- Use strings.CutPrefix for “/name ” parsing
- Add structured logs for join/rename/leave with user, id, and remote addr
UI:
- Simplify chat line format for readability; keep color-coding based on ID-derived color
- Add go-nanoid to generate 6-char per-connection IDs; fallback to RemoteAddr
- Introduce sanitizeUsername with rules: [A-Za-z0-9_.-], spaces→_, trim ._-, max 12 chars
- Support /name <username> to change username with validation and broadcast [rename]
- Greet client with default username user_<id> and usage hint for /name
- Broadcast joins/leaves and messages including username and ID; exclude self on join
- Handle /quit to trigger unified leave flow; consistent leave announcement
- Comment/document broadcast struct, Hub, and startTCPServer
- Increase scanner buffer and add newline-delimited send in broadcaster
Client/main:
- Add flags: -host (default "localhost:9000") and -server (run only server)
- When -server is set, startTCPServer(host) and exit
- Use provided host for client connection
- Center header with width-aware lipgloss styling; adjust padding
Server:
- Introduce broadcast struct {text string, exclude net.Conn}
- Hub.msgCh now chan broadcast; send messages with optional exclusion
- On join: send “[join] …” to others (exclude the joiner)
- Broadcast chat lines without exclusion; newline-delimited as before
- Handle “/quit” by breaking loop (graceful disconnect)
- On leave: broadcast “[leave] …” to all
Refactor notes:
- Remove unconditional embedded server from client startup
- Scanner loop unchanged aside from quit handling and broadcast usage
- Introduce typed msgs: connectedMsg, disconnectedMsg, errorMsg, and netMsg
- connectCmd now returns connectedMsg on success instead of “[connected]”
- Add readLineCmd to read a single line via bufio.Reader and emit netMsg
- Handles io.EOF as disconnectedMsg; reports other errors as “[error] read: …”
- Update loop:
- On connectedMsg: store conn, append “[connected]”, schedule first readLineCmd
- On netMsg: append message, schedule next readLineCmd unless it’s a read error
- On disconnectedMsg: append “[disconnected]”, close and clear conn
- UI tweaks: textarea placeholder uses "..." and height reduced from 3 to 2
- Window sizing: set viewport width; removed old netMsg branch now superseded by typed msgs
This removes the scanner goroutine pattern in favor of Cmd-driven incremental reads.
- Add net/bufio/time imports and model fields (conn, server, err)
- initialModel now accepts server address; display it as header
- Init batches textarea.Blink with connectCmd to dial TCP on startup
- Implement connectCmd with 3s timeout; emit [connected]/[disconnected]/error via netMsg
- Spawn scanner goroutine to read lines from conn and forward as netMsg
- Implement sendCmd to write input lines to the connection
- Update: on Enter, send via sendCmd instead of local echo; handle netMsg to append messages and status
- Close connection on Ctrl+C/Esc
- main: start local TCP server in goroutine; delay 200ms; connect to 127.0.0.1:9000
- Minor: append textarea cmd only if non-nil; render server header above viewport