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