diff options
| author | 2024-08-29 20:41:04 +0800 | |
|---|---|---|
| committer | 2024-08-29 20:41:04 +0800 | |
| commit | 34b7dc964b3516457f04d00d3ec910d3b6fd585b (patch) | |
| tree | 7a0a44ce334cc1411952cdbde056b7b57720f06e | |
| parent | Do some extra user input validation (diff) | |
| download | ukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.tar.gz ukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.tar.xz ukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.zip | |
thank you Q&A, now theres proper unicode support n shit
| -rw-r--r-- | build.zig | 12 | ||||
| -rw-r--r-- | build.zig.zon | 4 | ||||
| -rw-r--r-- | src/main.zig | 50 | ||||
| -rw-r--r-- | src/utils.zig | 55 |
4 files changed, 97 insertions, 24 deletions
| @@ -7,15 +7,17 @@ pub fn build(b: *Build) void { | |||
| 7 | const target = b.standardTargetOptions(.{}); | 7 | const target = b.standardTargetOptions(.{}); |
| 8 | const optimize = b.standardOptimizeOption(.{}); | 8 | const optimize = b.standardOptimizeOption(.{}); |
| 9 | 9 | ||
| 10 | const version = getVersion(b); | ||
| 11 | |||
| 12 | const config = b.addOptions(); | ||
| 13 | config.addOption(SemanticVersion, "version", version); | ||
| 14 | |||
| 10 | const sqlite = b.dependency("sqlite", .{ | 15 | const sqlite = b.dependency("sqlite", .{ |
| 11 | .target = target, | 16 | .target = target, |
| 12 | .optimize = optimize, | 17 | .optimize = optimize, |
| 13 | }); | 18 | }); |
| 14 | 19 | ||
| 15 | const version = getVersion(b); | 20 | const zg = b.dependency("zg", .{}); |
| 16 | |||
| 17 | const config = b.addOptions(); | ||
| 18 | config.addOption(SemanticVersion, "version", version); | ||
| 19 | 21 | ||
| 20 | const exe = b.addExecutable(.{ | 22 | const exe = b.addExecutable(.{ |
| 21 | .name = "ukkobot", | 23 | .name = "ukkobot", |
| @@ -25,6 +27,8 @@ pub fn build(b: *Build) void { | |||
| 25 | .optimize = optimize, | 27 | .optimize = optimize, |
| 26 | }); | 28 | }); |
| 27 | exe.root_module.addOptions("ukkobot-config", config); | 29 | exe.root_module.addOptions("ukkobot-config", config); |
| 30 | exe.root_module.addImport("CaseData", zg.module("CaseData")); | ||
| 31 | exe.root_module.addImport("GenCatData", zg.module("GenCatData")); | ||
| 28 | exe.root_module.addImport("sqlite", sqlite.module("sqlite")); | 32 | exe.root_module.addImport("sqlite", sqlite.module("sqlite")); |
| 29 | exe.linkLibrary(sqlite.artifact("sqlite")); | 33 | exe.linkLibrary(sqlite.artifact("sqlite")); |
| 30 | b.installArtifact(exe); | 34 | b.installArtifact(exe); |
diff --git a/build.zig.zon b/build.zig.zon index 0346cf0..4a582c0 100644 --- a/build.zig.zon +++ b/build.zig.zon | |||
| @@ -7,5 +7,9 @@ | |||
| 7 | .url = "https://git.enes.lv/zig-sqlite/snapshot/zig-sqlite-e4afe26b30e03ee5d8b61946893b19c2585745f8.tar.xz", | 7 | .url = "https://git.enes.lv/zig-sqlite/snapshot/zig-sqlite-e4afe26b30e03ee5d8b61946893b19c2585745f8.tar.xz", |
| 8 | .hash = "122019ea6e071dbd932c3e51d9631d99f007240e3e08d5436a1da20ad088343ca4a7", | 8 | .hash = "122019ea6e071dbd932c3e51d9631d99f007240e3e08d5436a1da20ad088343ca4a7", |
| 9 | }, | 9 | }, |
| 10 | .zg = .{ | ||
| 11 | .url = "https://git.enes.lv/zg/snapshot/zg-0.13.2.tar.xz", | ||
| 12 | .hash = "122055beff332830a391e9895c044d33b15ea21063779557024b46169fb1984c6e40", | ||
| 13 | }, | ||
| 10 | }, | 14 | }, |
| 11 | } | 15 | } |
diff --git a/src/main.zig b/src/main.zig index 544b105..2e33cfc 100644 --- a/src/main.zig +++ b/src/main.zig | |||
| @@ -199,22 +199,29 @@ fn onTextMessage(bot: *Bot, msg: types.Message, text: []const u8) !void { | |||
| 199 | }, | 199 | }, |
| 200 | }); | 200 | }); |
| 201 | } else if (std.ascii.startsWithIgnoreCase(text, "big ")) { | 201 | } else if (std.ascii.startsWithIgnoreCase(text, "big ")) { |
| 202 | var output = ArrayList(u8).init(bot.allocator); | 202 | const trimmed = try utils.trim(text[4..]); |
| 203 | defer output.deinit(); | 203 | const cd = try utils.getCD(); |
| 204 | if (trimmed.len > 0) { | ||
| 205 | const uppercased = try cd.toUpperStr(bot.allocator, trimmed); | ||
| 206 | defer bot.allocator.free(uppercased); | ||
| 204 | 207 | ||
| 205 | try output.appendSlice("<b>"); | 208 | var output = ArrayList(u8).init(bot.allocator); |
| 206 | try utils.escapeXml(output.writer(), text[4..]); | 209 | defer output.deinit(); |
| 207 | try output.appendSlice("</b>"); | ||
| 208 | 210 | ||
| 209 | try bot.sendMessage_(.{ | 211 | try output.appendSlice("<b>"); |
| 210 | .chat_id = msg.chat.id, | 212 | try utils.escapeXml(output.writer(), uppercased); |
| 211 | .text = output.items, | 213 | try output.appendSlice("</b>"); |
| 212 | .parse_mode = .html, | 214 | |
| 213 | .reply_parameters = .{ | 215 | try bot.sendMessage_(.{ |
| 214 | .message_id = msg.message_id, | ||
| 215 | .chat_id = msg.chat.id, | 216 | .chat_id = msg.chat.id, |
| 216 | }, | 217 | .text = output.items, |
| 217 | }); | 218 | .parse_mode = .html, |
| 219 | .reply_parameters = .{ | ||
| 220 | .message_id = msg.message_id, | ||
| 221 | .chat_id = msg.chat.id, | ||
| 222 | }, | ||
| 223 | }); | ||
| 224 | } | ||
| 218 | } else if (std.ascii.eqlIgnoreCase(text, "forgor")) { | 225 | } else if (std.ascii.eqlIgnoreCase(text, "forgor")) { |
| 219 | try bot.sendMessage_(.{ | 226 | try bot.sendMessage_(.{ |
| 220 | .chat_id = msg.chat.id, | 227 | .chat_id = msg.chat.id, |
| @@ -244,14 +251,17 @@ fn onTextMessage(bot: *Bot, msg: types.Message, text: []const u8) !void { | |||
| 244 | }, | 251 | }, |
| 245 | }); | 252 | }); |
| 246 | } else if (std.ascii.startsWithIgnoreCase(text, "say ")) { | 253 | } else if (std.ascii.startsWithIgnoreCase(text, "say ")) { |
| 247 | try bot.sendMessage_(.{ | 254 | const trimmed = try utils.trim(text[4..]); |
| 248 | .chat_id = msg.chat.id, | 255 | if (trimmed.len > 0) { |
| 249 | .text = text[4..], | 256 | try bot.sendMessage_(.{ |
| 250 | .reply_parameters = .{ | ||
| 251 | .message_id = msg.message_id, | ||
| 252 | .chat_id = msg.chat.id, | 257 | .chat_id = msg.chat.id, |
| 253 | }, | 258 | .text = trimmed, |
| 254 | }); | 259 | .reply_parameters = .{ |
| 260 | .message_id = msg.message_id, | ||
| 261 | .chat_id = msg.chat.id, | ||
| 262 | }, | ||
| 263 | }); | ||
| 264 | } | ||
| 255 | } else if (std.ascii.eqlIgnoreCase(text, "uwu")) { | 265 | } else if (std.ascii.eqlIgnoreCase(text, "uwu")) { |
| 256 | try bot.sendMessage_(.{ | 266 | try bot.sendMessage_(.{ |
| 257 | .chat_id = msg.chat.id, | 267 | .chat_id = msg.chat.id, |
diff --git a/src/utils.zig b/src/utils.zig index c6e8508..631e464 100644 --- a/src/utils.zig +++ b/src/utils.zig | |||
| @@ -2,6 +2,9 @@ const std = @import("std"); | |||
| 2 | 2 | ||
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | const ArrayList = std.ArrayList; | 4 | const ArrayList = std.ArrayList; |
| 5 | const CaseData = @import("CaseData"); | ||
| 6 | const GenCatData = @import("GenCatData"); | ||
| 7 | const Utf8View = std.unicode.Utf8View; | ||
| 5 | 8 | ||
| 6 | pub fn escapeXml(writer: anytype, text: []const u8) !void { | 9 | pub fn escapeXml(writer: anytype, text: []const u8) !void { |
| 7 | for (text) |ch| { | 10 | for (text) |ch| { |
| @@ -15,6 +18,26 @@ pub fn escapeXml(writer: anytype, text: []const u8) !void { | |||
| 15 | } | 18 | } |
| 16 | } | 19 | } |
| 17 | 20 | ||
| 21 | var gcd_global: ?GenCatData = null; | ||
| 22 | |||
| 23 | pub fn getGCD() !GenCatData { | ||
| 24 | if (gcd_global) |gcd| { | ||
| 25 | return gcd; | ||
| 26 | } | ||
| 27 | gcd_global = try GenCatData.init(std.heap.page_allocator); | ||
| 28 | return gcd_global.?; | ||
| 29 | } | ||
| 30 | |||
| 31 | var cd_global: ?CaseData = null; | ||
| 32 | |||
| 33 | pub fn getCD() !CaseData { | ||
| 34 | if (cd_global) |cd| { | ||
| 35 | return cd; | ||
| 36 | } | ||
| 37 | cd_global = try CaseData.init(std.heap.page_allocator); | ||
| 38 | return cd_global.?; | ||
| 39 | } | ||
| 40 | |||
| 18 | pub inline fn isNull(value: anytype) bool { | 41 | pub inline fn isNull(value: anytype) bool { |
| 19 | return switch (@typeInfo(@TypeOf(value))) { | 42 | return switch (@typeInfo(@TypeOf(value))) { |
| 20 | .Null => true, | 43 | .Null => true, |
| @@ -22,3 +45,35 @@ pub inline fn isNull(value: anytype) bool { | |||
| 22 | else => false, | 45 | else => false, |
| 23 | }; | 46 | }; |
| 24 | } | 47 | } |
| 48 | |||
| 49 | pub fn trim(str: []const u8) ![]const u8 { | ||
| 50 | const view = try Utf8View.init(str); | ||
| 51 | const gcd = try getGCD(); | ||
| 52 | |||
| 53 | var it = view.iterator(); | ||
| 54 | var idx: usize = 0; | ||
| 55 | const first = while (it.nextCodepoint()) |cp| { | ||
| 56 | if (!isTrimmable(gcd, cp)) { | ||
| 57 | break idx; | ||
| 58 | } | ||
| 59 | idx = it.i; | ||
| 60 | } else { | ||
| 61 | return ""; | ||
| 62 | }; | ||
| 63 | |||
| 64 | idx = it.i; | ||
| 65 | |||
| 66 | var last = first; | ||
| 67 | while (it.nextCodepoint()) |cp| { | ||
| 68 | if (!isTrimmable(gcd, cp)) { | ||
| 69 | last = idx + (std.unicode.utf8CodepointSequenceLength(cp) catch unreachable) - 1; | ||
| 70 | } | ||
| 71 | idx = it.i; | ||
| 72 | } | ||
| 73 | |||
| 74 | return str[first .. last + 1]; | ||
| 75 | } | ||
| 76 | |||
| 77 | inline fn isTrimmable(gcd: GenCatData, cp: u21) bool { | ||
| 78 | return gcd.isSeparator(cp) or gcd.isControl(cp); | ||
| 79 | } | ||