tangled
alpha
login
or
join now
rockorager.dev
/
comlink
2
fork
atom
an experimental irc client
2
fork
atom
overview
issues
pulls
pipelines
irc: refactor insertMessage
rockorager.dev
1 year ago
0757eff8
de640965
verified
This commit was signed with the committer's
known signature
.
rockorager.dev
SSH Key Fingerprint:
SHA256:qn/Fjy7CpbcogGEPB14Y53hLnQleZNFY9lkQnuudFLs=
+68
-64
1 changed file
expand all
collapse all
unified
split
src
irc.zig
+68
-64
src/irc.zig
···
306
307
pub fn insertMessage(self: *Channel, msg: Message) !void {
308
try self.messages.append(msg);
309
-
std.sort.insertion(Message, self.messages.items, {}, Message.compareTime);
310
if (self.scroll.msg_offset) |offset| {
311
self.scroll.msg_offset = offset + 1;
0
0
0
0
0
0
312
}
313
}
314
···
1426
return Command.parse(src[i..end]);
1427
}
1428
0
0
0
0
0
0
0
0
0
0
0
0
0
1429
pub fn paramIterator(msg: Message) ParamIterator {
1430
const src = msg.bytes;
1431
var i: usize = 0;
···
2171
.PRIVMSG, .NOTICE => {
2172
// syntax: <target> :<message>
2173
const msg2 = Message.init(try self.app.alloc.dupe(u8, msg.bytes));
0
0
0
0
0
0
0
0
0
0
0
0
0
2174
var iter = msg2.paramIterator();
2175
const target = blk: {
2176
const tgt = iter.next() orelse return;
2177
if (mem.eql(u8, tgt, client.nickname())) {
2178
-
// If the target is us, it likely has our
2179
-
// hostname in it.
2180
-
const source = msg2.source() orelse return;
2181
-
const n = mem.indexOfScalar(u8, source, '!') orelse source.len;
2182
-
break :blk source[0..n];
2183
} else break :blk tgt;
2184
};
0
0
0
0
0
2185
2186
-
// We handle batches separately. When we encounter a
2187
-
// PRIVMSG from a batch, we use the original target
2188
-
// from the batch start. We also never notify from a
2189
-
// batched message. Batched messages also require
2190
-
// sorting
2191
-
if (msg2.getTag("batch")) |tag| {
2192
-
const entry = client.batches.getEntry(tag) orelse @panic("TODO");
2193
-
var channel = entry.value_ptr.*;
2194
-
try channel.insertMessage(msg2);
2195
-
channel.at_oldest = false;
2196
-
if (msg2.timestamp_s > channel.last_read) {
2197
-
channel.has_unread = true;
2198
-
const content = iter.next() orelse return;
2199
-
if (std.mem.indexOf(u8, content, client.nickname())) |_| {
2200
-
channel.has_unread_highlight = true;
2201
-
}
2202
-
}
2203
-
} else {
2204
-
// standard handling
2205
-
var channel = try client.getOrCreateChannel(target);
2206
-
try channel.insertMessage(msg2);
2207
-
const content = iter.next() orelse return;
2208
-
var has_highlight = false;
2209
-
{
2210
-
const sender: []const u8 = blk: {
2211
-
const src = msg2.source() orelse break :blk "";
2212
-
const l = std.mem.indexOfScalar(u8, src, '!') orelse
2213
-
std.mem.indexOfScalar(u8, src, '@') orelse
2214
-
src.len;
2215
-
break :blk src[0..l];
2216
-
};
2217
-
try lua.onMessage(self.app.lua, client, channel.name, sender, content);
2218
-
}
2219
-
if (std.mem.indexOf(u8, content, client.nickname())) |_| {
2220
-
var buf: [64]u8 = undefined;
2221
-
const title_or_err = if (msg2.source()) |source|
2222
-
std.fmt.bufPrint(&buf, "{s} - {s}", .{ channel.name, source })
2223
-
else
2224
-
std.fmt.bufPrint(&buf, "{s}", .{channel.name});
2225
-
const title = title_or_err catch title: {
2226
-
const len = @min(buf.len, channel.name.len);
2227
-
@memcpy(buf[0..len], channel.name[0..len]);
2228
-
break :title buf[0..len];
2229
-
};
2230
-
try ctx.sendNotification(title, content);
2231
-
has_highlight = true;
2232
-
}
2233
-
if (msg2.timestamp_s > channel.last_read) {
2234
-
channel.has_unread_highlight = has_highlight;
2235
-
channel.has_unread = true;
2236
-
}
2237
2238
-
// Set the typing time to 0
2239
-
const sender = msg2.senderNick() orelse "";
2240
-
for (channel.members.items) |*member| {
2241
-
if (!std.mem.eql(u8, member.user.nick, sender)) {
2242
-
continue;
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2243
}
2244
-
member.typing = 0;
2245
-
return;
2246
}
2247
}
2248
},
···
306
307
pub fn insertMessage(self: *Channel, msg: Message) !void {
308
try self.messages.append(msg);
0
309
if (self.scroll.msg_offset) |offset| {
310
self.scroll.msg_offset = offset + 1;
311
+
}
312
+
if (msg.timestamp_s > self.last_read) {
313
+
self.has_unread = true;
314
+
if (msg.containsPhrase(self.client.nickname())) {
315
+
self.has_unread_highlight = true;
316
+
}
317
}
318
}
319
···
1431
return Command.parse(src[i..end]);
1432
}
1433
1434
+
pub fn containsPhrase(self: Message, phrase: []const u8) bool {
1435
+
switch (self.command()) {
1436
+
.PRIVMSG, .NOTICE => {},
1437
+
else => return false,
1438
+
}
1439
+
var iter = self.paramIterator();
1440
+
// We only handle PRIVMSG and NOTICE which have syntax <target> :<content>. Skip the target
1441
+
_ = iter.next() orelse return false;
1442
+
1443
+
const content = iter.next() orelse return false;
1444
+
return std.mem.indexOf(u8, content, phrase) != null;
1445
+
}
1446
+
1447
pub fn paramIterator(msg: Message) ParamIterator {
1448
const src = msg.bytes;
1449
var i: usize = 0;
···
2189
.PRIVMSG, .NOTICE => {
2190
// syntax: <target> :<message>
2191
const msg2 = Message.init(try self.app.alloc.dupe(u8, msg.bytes));
2192
+
2193
+
// We handle batches separately. When we encounter a PRIVMSG from a batch, we use
2194
+
// the original target from the batch start. We also never notify from a batched
2195
+
// message. Batched messages also require sorting
2196
+
if (msg2.getTag("batch")) |tag| {
2197
+
const entry = client.batches.getEntry(tag) orelse @panic("TODO");
2198
+
var channel = entry.value_ptr.*;
2199
+
try channel.insertMessage(msg2);
2200
+
std.sort.insertion(Message, channel.messages.items, {}, Message.compareTime);
2201
+
channel.at_oldest = false;
2202
+
return;
2203
+
}
2204
+
2205
var iter = msg2.paramIterator();
2206
const target = blk: {
2207
const tgt = iter.next() orelse return;
2208
if (mem.eql(u8, tgt, client.nickname())) {
2209
+
// If the target is us, we use the sender nick as the identifier
2210
+
break :blk msg2.senderNick() orelse unreachable;
0
0
0
2211
} else break :blk tgt;
2212
};
2213
+
// Get the channel
2214
+
var channel = try client.getOrCreateChannel(target);
2215
+
// Add the message to the channel. We don't need to sort because these come
2216
+
// chronologically
2217
+
try channel.insertMessage(msg2);
2218
2219
+
// Get values for our lua callbacks
2220
+
const content = iter.next() orelse return;
2221
+
const sender = msg2.senderNick() orelse "";
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2222
2223
+
// Do the lua callback
2224
+
try lua.onMessage(self.app.lua, client, channel.name, sender, content);
2225
+
2226
+
// Send a notification if this has our nick
2227
+
if (msg2.containsPhrase(client.nickname())) {
2228
+
var buf: [64]u8 = undefined;
2229
+
const title_or_err = if (sender.len > 0)
2230
+
std.fmt.bufPrint(&buf, "{s} - {s}", .{ channel.name, sender })
2231
+
else
2232
+
std.fmt.bufPrint(&buf, "{s}", .{channel.name});
2233
+
const title = title_or_err catch title: {
2234
+
const len = @min(buf.len, channel.name.len);
2235
+
@memcpy(buf[0..len], channel.name[0..len]);
2236
+
break :title buf[0..len];
2237
+
};
2238
+
try ctx.sendNotification(title, content);
2239
+
2240
+
if (client.caps.@"message-tags") {
2241
+
// Set the typing time to 0. We only need to do this when the server
2242
+
// supports message-tags
2243
+
for (channel.members.items) |*member| {
2244
+
if (!std.mem.eql(u8, member.user.nick, sender)) {
2245
+
continue;
2246
+
}
2247
+
member.typing = 0;
2248
+
return;
2249
}
0
0
2250
}
2251
}
2252
},