Mark unread private messages in inbox

This commit is contained in:
m1ngsama 2026-05-29 18:01:05 +08:00
parent 1f8fb7acf4
commit 2fca031362
7 changed files with 29 additions and 6 deletions

View file

@ -114,6 +114,7 @@ Command output pages use `j/k`, `Ctrl+D/U`, and `g/G` for paging. `:inbox`
shows incoming and sent private messages newest-first; press `r` to refresh it
manually, and it refreshes when a new private message arrives while the inbox
is open. `:reply text` and `:r text` send to the latest private-message peer.
Unread incoming private messages are marked with `*` until `:inbox` renders.
Private messages are per-session only and are not written to `messages.log`.
**Special messages (INSERT mode)**

View file

@ -167,8 +167,9 @@ persisted to `messages.log` and are not included in exec `tail`, exec `dump`,
Each participant keeps a bounded in-memory `:inbox` for the current session.
Recipients see incoming private messages; senders see local sent-message
copies. `:inbox` displays newest messages first, can be refreshed with `r`,
and refreshes automatically while open when a new private message arrives.
copies. Unread incoming messages are marked with `*` until `:inbox` renders.
`:inbox` displays newest messages first, can be refreshed with `r`, and
refreshes automatically while open when a new private message arrives.
### `help`

View file

@ -38,7 +38,8 @@ The product path should stay short:
reconnect.
- `:inbox` is live enough for normal chat use: it can be refreshed with `r`
and refreshes automatically when a new private message arrives while the
inbox is open.
inbox is open. Incoming unread messages are marked with `*` until the inbox
renders them.
- `:reply` / `:r` keeps the private-message path keyboard-short: it answers
the latest private-message peer in the current session without retyping a
username.

View file

@ -17,6 +17,7 @@ typedef struct {
char to[MAX_USERNAME_LEN];
char content[MAX_MESSAGE_LEN];
bool outgoing;
bool unread;
} whisper_t;
typedef enum {

View file

@ -82,6 +82,7 @@ static void client_append_whisper(client_t *owner, const char *from,
snprintf(owner->whisper_inbox[slot].content,
sizeof(owner->whisper_inbox[slot].content), "%s", content);
owner->whisper_inbox[slot].outgoing = outgoing;
owner->whisper_inbox[slot].unread = count_unread;
snprintf(owner->last_whisper_peer, sizeof(owner->last_whisper_peer), "%s",
outgoing ? to : from);
if (count_unread) {
@ -142,6 +143,9 @@ static void append_inbox_output(client_t *client, char *output,
snap_count = client->whisper_inbox_count;
memcpy(snapshot, client->whisper_inbox,
snap_count * sizeof(whisper_t));
for (int i = 0; i < snap_count; i++) {
client->whisper_inbox[i].unread = false;
}
client->unread_whispers = 0;
pthread_mutex_unlock(&client->whisper_lock);
@ -157,6 +161,7 @@ static void append_inbox_output(client_t *client, char *output,
for (int i = snap_count - 1; i >= 0; i--) {
char ts[20];
char peer[MAX_USERNAME_LEN + 16];
const char *marker = snapshot[i].unread ? "\033[1;35m*\033[0m" : " ";
struct tm tmi;
localtime_r(&snapshot[i].timestamp, &tmi);
strftime(ts, sizeof(ts), "%m-%d %H:%M", &tmi);
@ -169,8 +174,8 @@ static void append_inbox_output(client_t *client, char *output,
snprintf(peer, sizeof(peer), "%s", snapshot[i].from);
}
buffer_appendf(output, buf_size, pos,
" \033[90m%s\033[0m \033[35m%s\033[0m: %s\n",
ts, peer, snapshot[i].content);
" %s \033[90m%s\033[0m \033[35m%s\033[0m: %s\n",
marker, ts, peer, snapshot[i].content);
}
}

View file

@ -273,6 +273,18 @@ else
fi
BOB_PID=""
if grep -q '.*alice.*private lifecycle second' "$STATE_DIR/bob.log" &&
grep -q '\*.*alice.*private lifecycle second' "$STATE_DIR/bob.log" &&
grep -q '\*.*bob.*private lifecycle reply' "$STATE_DIR/alice.log"; then
echo "✓ unread private messages are visibly marked in inbox"
PASS=$((PASS + 1))
else
echo "✗ inbox unread marker missing"
sed -n '1,220p' "$STATE_DIR/bob.log"
sed -n '1,260p' "$STATE_DIR/alice.log"
FAIL=$((FAIL + 1))
fi
TAIL_OUTPUT=$(ssh $SSH_EXEC_OPTS localhost "tail -n 10" 2>/dev/null || true)
printf '%s\n' "$TAIL_OUTPUT" | grep -q 'hello lifecycle alpha' &&
printf '%s\n' "$TAIL_OUTPUT" | grep -q 'alice2 ships lifecycle'

4
tnt.1
View file

@ -253,7 +253,9 @@ The
.B :inbox
page shows incoming messages and local sent-message copies for the current
session. It refreshes automatically when a new private message arrives while
it is open. Use
it is open. Incoming unread messages are marked with
.B *
until the inbox renders them. Use
.B :reply
or
.B :r