╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ SubTitle.zig ─────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
114 'E' => .{ 115 "####", 116 "#...", 117 "###.", 118 "#...", 119 "#...", 120 "####", 121 }, 122 'F' => .{ 123 "####", 124 "#...", 125 "###.", 126 "#...", 127 "#...", 128 "#...", 129 }, 130 'G' => .{ 131 ".###", 132 "#...", 133 "#.##", 134 "#..#", 135 "#..#", 136 ".###", 137 }, 138 'H' => .{ 139 "#..#", 140 "#..#", 141 "####", 142 "#..#", 143 "#..#", 144 "#..#", 145 }, 146 'I' => .{ 147 "####", 148 ".##.", 149 ".##.", 150 ".##.", 151 ".##.", 152 "####", 153 }, 154 'J' => .{ 155 "..##", 156 "...#", 157 "...#", 158 "...#", 159 "#..#", 160 ".##.", 161 }, 162 'K' => .{ 163 "#..#", 164 "#.#.", 165 "##..", 166 "##..", 167 "#.#.", 168 "#..#", 169 }, 170 'L' => .{ 171 "#...", 172 "#...", 173 "#...", 174 "#...", 175 "#...", 176 "####", 177 }, 178 'M' => .{ 179 "#..#", 180 "####", 181 "####", 182 "#..#", 183 "#..#", 184 "#..#", 185 }, 186 'N' => .{ 187 "#..#", 188 "##.#", 189 "##.#", 190 "#.##", 191 "#.##", 192 "#..#", 193 }, 194 'O' => .{ 195 ".##.", 196 "#..#", 197 "#..#", 198 "#..#", 199 "#..#", 200 ".##.", 201 }, 202 'P' => .{ 203 "###.", 204 "#..#", 205 "###.", 206 "#...", 207 "#...", 208 "#...", 209 }, 210 'Q' => .{ 211 ".##.", 212 "#..#", 213 "#..#", 214 "#.##", 215 ".##.", 216 "...#", 217 }, 218 'R' => .{ 219 "###.", 220 "#..#", 221 "###.", 222 "##..", 223 "#.#.", 224 "#..#", 225 }, 226 'S' => .{ 227 ".###", 228 "#...", 229 ".##.", 230 "...#", 231 "#..#", 232 "###.", 233 }, 234 'T' => .{ 235 "####", 236 ".##.", 237 ".##.", 238 ".##.", 239 ".##.", 240 ".##.", 241 }, 242 'U' => .{ 243 "#..#", 244 "#..#", 245 "#..#", 246 "#..#", 247 "#..#", 248 ".##.", 249 }, 250 'V' => .{ 251 "#..#", 252 "#..#", 253 "#..#", 254 "#..#", 255 ".##.", 256 ".##.", 257 }, 258 'W' => .{ 259 "#..#", 260 "#..#", 261 "#..#", 262 "####", 263 "####", 264 ".##.", 265 }, 266 'X' => .{ 267 "#..#", 268 "#..#", 269 ".##.", 270 ".##.", 271 "#..#", 272 "#..#", 273 }, 274 'Y' => .{ 275 "#..#", 276 "#..#", 277 ".##.", 278 ".##.", 279 ".##.", 280 ".##.", 281 }, 282 'Z' => .{ 283 "####", 284 "...#", 285 "..#.", 286 ".#..", 287 "#...", 288 "####", 289 }, 290 '0' => .{ 291 ".##.", 292 "#.##", 293 "#.##", 294 "##.#", 295 "##.#", 296 ".##.", 297 }, 298 '1' => .{ 299 ".##.", 300 "###.", 301 ".##.", 302 ".##.", 303 ".##.", 304 "####", 305 }, 306 '2' => .{ 307 ".##.", 308 "#..#", 309 "..#.", 310 ".#..", 311 "#...", 312 "####", 313 }, 314 '3' => .{ 315 "###.", 316 "...#", 317 ".##.", 318 "...#", 319 "#..#", 320 "###.", 321 }, 322 '4' => .{ 323 "..#.", 324 ".##.", 325 "#.#.", 326 "####", 327 "..#.", 328 "..#.", 329 }, 330 '5' => .{ 331 "####", 332 "#...", 333 "###.", 334 "...#", 335 "#..#", 336 "###.", 337 }, 338 '6' => .{ 339 ".##.", 340 "#...", 341 "###.", 342 "#..#", 343 "#..#", 344 ".##.", 345 }, 346 '7' => .{ 347 "####", 348 "...#", 349 "..#.", 350 "..#.", 351 ".#..", 352 ".#..", 353 }, 354 '8' => .{ 355 ".##.", 356 "#..#", 357 ".##.", 358 "#..#", 359 "#..#", 360 ".##.", 361 }, 362 '9' => .{ 363 ".##.", 364 "#..#", 365 "#..#", 366 ".###", 367 "...#", 368 ".##.", 369 }, 370 '-' => .{ 371 "....", 372 "....", 373 ".##.", 374 ".##.", 375 "....", 376 "....", 377 }, 378 '.' => .{ 379 "....", 380 "....", 381 "....", 382 "....", 383 ".##.", 384 ".##.", 385 }, 386 else => null, 387 }; 388 } 389 390 // map a 2x3 sub-pixel pattern to its corresponding sextant codepoint 391 fn sextantCodepoint(pattern: u6) u21 { 392 return switch (pattern) { 393 0b000000 => ' ', 394 0b010101 => 0x258C, // ▌ left half block 395 0b101010 => 0x2590, // ▐ right half block 396 0b111111 => 0x2588, // █ full block 397 else => blk: { 398 var offset: u21 = @as(u21, pattern) - 1; 399 if (pattern > 0b010101) offset -= 1; 400 if (pattern > 0b101010) offset -= 1; 401 break :blk 0x1FB00 + offset; 402 }, 403 }; 404 } 405 406 fn renderSubTitle(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { 407 var rows: [2]std.ArrayList(u8) = .{ .empty, .empty }; 408 defer for (&rows) |*r| r.deinit(allocator); 409 410 var first = true; 411 for (input) |c| { 412 const glyph = glyphFor(c) orelse continue; 413 414 var on: [6][4]bool = std.mem.zeroes([6][4]bool); 415 for (0..6) |r| { 416 for (0..4) |col| { 417 on[r][col] = glyph[r][col] == '#'; 418 } 419 } 420 421 if (!first) { 422 for (&rows) |*r| try r.append(allocator, ' '); 423 } 424 first = false; 425 426 for (0..2) |text_row| { 427 for (0..2) |text_col| { 428 var pattern: u6 = 0; 429 for (0..3) |sub_row| { 430 for (0..2) |sub_col| { 431 const row_idx = text_row * 3 + sub_row; 432 const col_idx = text_col * 2 + sub_col; 433 if (on[row_idx][col_idx]) { 434 pattern |= @as(u6, 1) << @intCast(sub_row * 2 + sub_col); 435 } 436 } 437 } 438 const cp = sextantCodepoint(pattern); 439 var utf8_buf: [4]u8 = undefined; 440 const len = try std.unicode.utf8Encode(cp, &utf8_buf); 441 try rows[text_row].appendSlice(allocator, utf8_buf[0..len]); 442 } 443 } 444 } 445 446 var out: std.ArrayList(u8) = .empty; 447 errdefer out.deinit(allocator); 448 try out.appendSlice(allocator, rows[0].items); 449 try out.append(allocator, '\n'); 450 try out.appendSlice(allocator, rows[1].items); 451 return out.toOwnedSlice(allocator); 452 } 453