╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Title.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
233 "##...#", 234 "#.#..#", 235 "#..#.#", 236 "#...##", 237 "#...##", 238 "#....#", 239 "#....#", 240 }, 241 'O' => .{ 242 ".####.", 243 "#....#", 244 "#....#", 245 "#....#", 246 "#....#", 247 "#....#", 248 "#....#", 249 "#....#", 250 ".####.", 251 }, 252 'P' => .{ 253 "#####.", 254 "#....#", 255 "#....#", 256 "#....#", 257 "#####.", 258 "#.....", 259 "#.....", 260 "#.....", 261 "#.....", 262 }, 263 'Q' => .{ 264 ".####.", 265 "#....#", 266 "#....#", 267 "#....#", 268 "#....#", 269 "#....#", 270 "#..#.#", 271 ".####.", 272 ".....#", 273 }, 274 'R' => .{ 275 "#####.", 276 "#....#", 277 "#....#", 278 "#....#", 279 "#####.", 280 "#.#...", 281 "#..#..", 282 "#...#.", 283 "#....#", 284 }, 285 'S' => .{ 286 ".####.", 287 "#....#", 288 "#.....", 289 "#.....", 290 ".####.", 291 ".....#", 292 ".....#", 293 "#....#", 294 ".####.", 295 }, 296 'T' => .{ 297 "######", 298 "..##..", 299 "..##..", 300 "..##..", 301 "..##..", 302 "..##..", 303 "..##..", 304 "..##..", 305 "..##..", 306 }, 307 'U' => .{ 308 "#....#", 309 "#....#", 310 "#....#", 311 "#....#", 312 "#....#", 313 "#....#", 314 "#....#", 315 "#....#", 316 ".####.", 317 }, 318 'V' => .{ 319 "#....#", 320 "#....#", 321 "#....#", 322 ".#..#.", 323 ".#..#.", 324 ".#..#.", 325 ".#..#.", 326 ".#..#.", 327 "..##..", 328 }, 329 'W' => .{ 330 "#....#", 331 "#....#", 332 "#....#", 333 "#....#", 334 "#....#", 335 "#.##.#", 336 "#.##.#", 337 "##..##", 338 ".#..#.", 339 }, 340 'X' => .{ 341 "#....#", 342 ".#..#.", 343 ".#..#.", 344 "..##..", 345 "..##..", 346 "..##..", 347 ".#..#.", 348 ".#..#.", 349 "#....#", 350 }, 351 'Y' => .{ 352 "#....#", 353 ".#..#.", 354 ".#..#.", 355 "..##..", 356 "..##..", 357 "..##..", 358 "..##..", 359 "..##..", 360 "..##..", 361 }, 362 'Z' => .{ 363 "######", 364 "....#.", 365 "....#.", 366 "...#..", 367 "..##..", 368 "..#...", 369 ".#....", 370 ".#....", 371 "######", 372 }, 373 '0' => .{ 374 ".####.", 375 "#...##", 376 "#..#.#", 377 "#..#.#", 378 "#.#..#", 379 "#.#..#", 380 "##...#", 381 "#....#", 382 ".####.", 383 }, 384 '1' => .{ 385 "..##..", 386 ".###..", 387 "..##..", 388 "..##..", 389 "..##..", 390 "..##..", 391 "..##..", 392 "..##..", 393 "######", 394 }, 395 '2' => .{ 396 ".####.", 397 "#....#", 398 ".....#", 399 "....#.", 400 "...#..", 401 "..#...", 402 ".#....", 403 "#.....", 404 "######", 405 }, 406 '3' => .{ 407 ".####.", 408 "#....#", 409 ".....#", 410 ".....#", 411 ".####.", 412 ".....#", 413 ".....#", 414 "#....#", 415 ".####.", 416 }, 417 '4' => .{ 418 "....#.", 419 "...##.", 420 "..#.#.", 421 ".#..#.", 422 "#...#.", 423 "######", 424 "....#.", 425 "....#.", 426 "....#.", 427 }, 428 '5' => .{ 429 "######", 430 "#.....", 431 "#.....", 432 "#.....", 433 "#####.", 434 ".....#", 435 ".....#", 436 "#....#", 437 ".####.", 438 }, 439 '6' => .{ 440 ".####.", 441 "#....#", 442 "#.....", 443 "#.....", 444 "#####.", 445 "#....#", 446 "#....#", 447 "#....#", 448 ".####.", 449 }, 450 '7' => .{ 451 "######", 452 ".....#", 453 "....#.", 454 "....#.", 455 "...#..", 456 "...#..", 457 "..#...", 458 "..#...", 459 ".#....", 460 }, 461 '8' => .{ 462 ".####.", 463 "#....#", 464 "#....#", 465 "#....#", 466 ".####.", 467 "#....#", 468 "#....#", 469 "#....#", 470 ".####.", 471 }, 472 '9' => .{ 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 "..##..", 504 }, 505 else => null, 506 }; 507 } 508 509 // whether every char of `text` has a glyph 510 pub fn covers(text: []const u8) bool { 511 for (text) |c| { 512 if (glyphFor(c) == null) return false; 513 } 514 return true; 515 } 516 517 // map a 2x3 sub-pixel pattern to its corresponding sextant codepoint 518 fn sextantCodepoint(pattern: u6) u21 { 519 return switch (pattern) { 520 0b000000 => ' ', 521 0b010101 => 0x258C, // ▌ left half block 522 0b101010 => 0x2590, // ▐ right half block 523 0b111111 => 0x2588, // █ full block 524 else => blk: { 525 var offset: u21 = @as(u21, pattern) - 1; 526 if (pattern > 0b010101) offset -= 1; 527 if (pattern > 0b101010) offset -= 1; 528 break :blk 0x1FB00 + offset; 529 }, 530 }; 531 } 532 533 fn renderTitle(allocator: std.mem.Allocator, input: []const u8, style: Style) ![]const u8 { 534 var rows: [3]std.ArrayList(u8) = .{ .empty, .empty, .empty }; 535 defer for (&rows) |*r| r.deinit(allocator); 536 537 var first = true; 538 for (input) |c| { 539 const glyph = glyphFor(c) orelse continue; 540 541 // scanlines: keep on-pixels only at even bitmap rows. 542 var kept: [9][6]bool = std.mem.zeroes([9][6]bool); 543 for (0..9) |r| { 544 if (style == .scanlines and r % 2 != 0) continue; 545 for (0..6) |col| { 546 kept[r][col] = glyph[r][col] == '#'; 547 } 548 } 549 550 if (!first) { 551 for (&rows) |*r| try r.append(allocator, ' '); 552 } 553 first = false; 554 555 for (0..3) |text_row| { 556 for (0..3) |text_col| { 557 var pattern: u6 = 0; 558 for (0..3) |sub_row| { 559 for (0..2) |sub_col| { 560 const row_idx = text_row * 3 + sub_row; 561 const col_idx = text_col * 2 + sub_col; 562 if (kept[row_idx][col_idx]) { 563 pattern |= @as(u6, 1) << @intCast(sub_row * 2 + sub_col); 564 } 565 } 566 } 567 const cp = sextantCodepoint(pattern); 568 var utf8_buf: [4]u8 = undefined; 569 const len = try std.unicode.utf8Encode(cp, &utf8_buf); 570 try rows[text_row].appendSlice(allocator, utf8_buf[0..len]); 571 } 572 } 573 } 574 575 var out: std.ArrayList(u8) = .empty; 576 errdefer out.deinit(allocator); 577 try out.appendSlice(allocator, rows[0].items); 578 try out.append(allocator, '\n'); 579 try out.appendSlice(allocator, rows[1].items); 580 try out.append(allocator, '\n'); 581 try out.appendSlice(allocator, rows[2].items); 582 return out.toOwnedSlice(allocator); 583 } 584