╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Title.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
311 "#....#", 312 "#....#", 313 "#....#", 314 ".####.", 315 }, 316 'V' => .{ 317 "#....#", 318 "#....#", 319 "#....#", 320 ".#..#.", 321 ".#..#.", 322 ".#..#.", 323 ".#..#.", 324 ".#..#.", 325 "..##..", 326 }, 327 'W' => .{ 328 "#....#", 329 "#....#", 330 "#....#", 331 "#....#", 332 "#....#", 333 "#.##.#", 334 "#.##.#", 335 "##..##", 336 ".#..#.", 337 }, 338 'X' => .{ 339 "#....#", 340 ".#..#.", 341 ".#..#.", 342 "..##..", 343 "..##..", 344 "..##..", 345 ".#..#.", 346 ".#..#.", 347 "#....#", 348 }, 349 'Y' => .{ 350 "#....#", 351 ".#..#.", 352 ".#..#.", 353 "..##..", 354 "..##..", 355 "..##..", 356 "..##..", 357 "..##..", 358 "..##..", 359 }, 360 'Z' => .{ 361 "######", 362 "....#.", 363 "....#.", 364 "...#..", 365 "..##..", 366 "..#...", 367 ".#....", 368 ".#....", 369 "######", 370 }, 371 '0' => .{ 372 ".####.", 373 "#...##", 374 "#..#.#", 375 "#..#.#", 376 "#.#..#", 377 "#.#..#", 378 "##...#", 379 "#....#", 380 ".####.", 381 }, 382 '1' => .{ 383 "..##..", 384 ".###..", 385 "..##..", 386 "..##..", 387 "..##..", 388 "..##..", 389 "..##..", 390 "..##..", 391 "######", 392 }, 393 '2' => .{ 394 ".####.", 395 "#....#", 396 ".....#", 397 "....#.", 398 "...#..", 399 "..#...", 400 ".#....", 401 "#.....", 402 "######", 403 }, 404 '3' => .{ 405 ".####.", 406 "#....#", 407 ".....#", 408 ".....#", 409 ".####.", 410 ".....#", 411 ".....#", 412 "#....#", 413 ".####.", 414 }, 415 '4' => .{ 416 "....#.", 417 "...##.", 418 "..#.#.", 419 ".#..#.", 420 "#...#.", 421 "######", 422 "....#.", 423 "....#.", 424 "....#.", 425 }, 426 '5' => .{ 427 "######", 428 "#.....", 429 "#.....", 430 "#.....", 431 "#####.", 432 ".....#", 433 ".....#", 434 "#....#", 435 ".####.", 436 }, 437 '6' => .{ 438 ".####.", 439 "#....#", 440 "#.....", 441 "#.....", 442 "#####.", 443 "#....#", 444 "#....#", 445 "#....#", 446 ".####.", 447 }, 448 '7' => .{ 449 "######", 450 ".....#", 451 "....#.", 452 "....#.", 453 "...#..", 454 "...#..", 455 "..#...", 456 "..#...", 457 ".#....", 458 }, 459 '8' => .{ 460 ".####.", 461 "#....#", 462 "#....#", 463 "#....#", 464 ".####.", 465 "#....#", 466 "#....#", 467 "#....#", 468 ".####.", 469 }, 470 '9' => .{ 471 ".####.", 472 "#....#", 473 "#....#", 474 "#....#", 475 ".#####", 476 ".....#", 477 ".....#", 478 "#....#", 479 ".####.", 480 }, 481 '-' => .{ 482 "......", 483 "......", 484 "......", 485 "......", 486 ".####.", 487 "......", 488 "......", 489 "......", 490 "......", 491 }, 492 '.' => .{ 493 "......", 494 "......", 495 "......", 496 "......", 497 "......", 498 "......", 499 "......", 500 "..##..", 501 "..##..", 502 }, 503 else => null, 504 }; 505 } 506 507 // map a 2x3 sub-pixel pattern to its corresponding sextant codepoint 508 fn sextantCodepoint(pattern: u6) u21 { 509 return switch (pattern) { 510 0b000000 => ' ', 511 0b010101 => 0x258C, // ▌ left half block 512 0b101010 => 0x2590, // ▐ right half block 513 0b111111 => 0x2588, // █ full block 514 else => blk: { 515 var offset: u21 = @as(u21, pattern) - 1; 516 if (pattern > 0b010101) offset -= 1; 517 if (pattern > 0b101010) offset -= 1; 518 break :blk 0x1FB00 + offset; 519 }, 520 }; 521 } 522 523 fn renderTitle(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { 524 var rows: [3]std.ArrayList(u8) = .{ .empty, .empty, .empty }; 525 defer for (&rows) |*r| r.deinit(allocator); 526 527 var first = true; 528 for (input) |c| { 529 const glyph = glyphFor(c) orelse continue; 530 531 // row-aligned dither: keep on-pixels only at even bitmap rows. 532 var kept: [9][6]bool = std.mem.zeroes([9][6]bool); 533 for (0..9) |r| { 534 if (r % 2 != 0) continue; 535 for (0..6) |col| { 536 kept[r][col] = glyph[r][col] == '#'; 537 } 538 } 539 540 if (!first) { 541 for (&rows) |*r| try r.append(allocator, ' '); 542 } 543 first = false; 544 545 for (0..3) |text_row| { 546 for (0..3) |text_col| { 547 var pattern: u6 = 0; 548 for (0..3) |sub_row| { 549 for (0..2) |sub_col| { 550 const row_idx = text_row * 3 + sub_row; 551 const col_idx = text_col * 2 + sub_col; 552 if (kept[row_idx][col_idx]) { 553 pattern |= @as(u6, 1) << @intCast(sub_row * 2 + sub_col); 554 } 555 } 556 } 557 const cp = sextantCodepoint(pattern); 558 var utf8_buf: [4]u8 = undefined; 559 const len = try std.unicode.utf8Encode(cp, &utf8_buf); 560 try rows[text_row].appendSlice(allocator, utf8_buf[0..len]); 561 } 562 } 563 } 564 565 var out: std.ArrayList(u8) = .empty; 566 errdefer out.deinit(allocator); 567 try out.appendSlice(allocator, rows[0].items); 568 try out.append(allocator, '\n'); 569 try out.appendSlice(allocator, rows[1].items); 570 try out.append(allocator, '\n'); 571 try out.appendSlice(allocator, rows[2].items); 572 return out.toOwnedSlice(allocator); 573 } 574