╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Markdown.zig ─────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯
410 for (self.plain, chars) |c, *char| char.* = c; 411 var lines: std.ArrayList(wgt.Line) = .empty; 412 try wgt.wrapLines(aa, &lines, chars, .word, max_chars); 413 414 // a blank row between lines keeps the glyphs from touching 415 var out: std.ArrayList(u8) = .empty; 416 for (lines.items, 0..) |line, i| { 417 if (i > 0) try out.appendSlice(aa, "\n\n"); 418 const text = std.mem.trimEnd(u8, self.plain[line.start..line.end], " "); 419 try out.appendSlice(aa, switch (font) { 420 .title => (try ui.Title.init(&arena, text, .solid)).content, 421 .sub_title => (try ui.SubTitle.init(&arena, text)).content, 422 }); 423 } 424 try self.font_box.setContent(allocator, out.items); 425 return true; 426 } 427 428 fn buildShown(self: *Heading, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus, widget: anytype) !void { 429 try widget.build(allocator, constraint, root_focus); 430 const grid = widget.getGrid() orelse return; 431 try self.focus.addChild(allocator, widget.getFocus(), grid.size, 0, 0); 432 } 433 434 pub fn input(self: *Heading, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 435 _ = self; 436 _ = allocator; 437 _ = key; 438 _ = root_focus; 439 } 440 441 pub fn clearGrid(self: *Heading) void { 442 self.text.clearGrid(); 443 self.font_box.clearGrid(); 444 } 445 446 pub fn getGrid(self: Heading) ?Grid { 447 // only the one last built has a grid 448 return self.font_box.getGrid() orelse self.text.getGrid(); 449 } 450 451 pub fn getFocus(self: *Heading) *Focus { 452 return self.focus; 453 } 454 }; 455 456 // a marker column beside a child, so wrapped lines hang under the child's 457 // first line: a list item's bullet, or a quote's bar on every row. 458 pub const Gutter = struct { 459 focus: *Focus, 460 grid: ?Grid, 461 child: wgt.Box(ui.Widget), 462 marker: []const u8, 463 // draw the marker on every row rather than only the first 464 repeat: bool, 465 style: Grid.Style, 466 467 // takes ownership of `child` on success 468 fn init(allocator: std.mem.Allocator, marker: []const u8, repeat: bool, style: Grid.Style, child: wgt.Box(ui.Widget)) !Gutter { 469 return .{ .focus = try Focus.create(allocator, .container), .grid = null, .child = child, .marker = marker, .repeat = repeat, .style = style }; 470 } 471 472 pub fn deinit(self: *Gutter, allocator: std.mem.Allocator) void { 473 self.focus.destroy(allocator); 474 self.clearGrid(); 475 self.child.deinit(allocator); 476 } 477 478 pub fn build(self: *Gutter, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 479 self.clearGrid(); 480 self.focus.clear(); 481 const marker_width = try xitui.width.displayWidth(self.marker); 482 if (constraint.max_size.width) |w| if (w <= marker_width) return; 483 if (constraint.max_size.height == 0) return; 484 485 try self.child.build(allocator, .{ 486 .min_size = .{ .width = null, .height = null }, 487 .max_size = .{ .width = if (constraint.max_size.width) |w| w - marker_width else null, .height = constraint.max_size.height }, 488 }, root_focus); 489 const child_grid = self.child.getGrid(); 490 const child_size: layout.Size = if (child_grid) |g| g.size else .{ .width = 0, .height = 0 }; 491 492 var grid = try Grid.init(allocator, .{ .width = marker_width + child_size.width, .height = @max(1, child_size.height) }); 493 errdefer grid.deinit(); 494 for (0..if (self.repeat) grid.size.height else 1) |y| { 495 var x: usize = 0; 496 var utf8 = (try std.unicode.Utf8View.init(self.marker)).iterator(); 497 while (utf8.nextCodepoint()) |rune| { 498 (try grid.cell(x, y)).style = self.style; 499 try grid.setRune(x, y, rune); 500 x += xitui.width.cellWidth(rune); 501 } 502 } 503 if (child_grid) |g| { 504 try grid.drawGrid(g, marker_width, 0); 505 try self.focus.addChild(allocator, self.child.getFocus(), g.size, marker_width, 0); 506 } 507 self.grid = grid; 508 } 509 510 pub fn input(self: *Gutter, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 511 _ = self; 512 _ = allocator; 513 _ = key; 514 _ = root_focus; 515 } 516 517 pub fn clearGrid(self: *Gutter) void { 518 if (self.grid) |*grid| { 519 grid.deinit(); 520 self.grid = null; 521 } 522 self.child.clearGrid(); 523 } 524 525 pub fn getGrid(self: Gutter) ?Grid { 526 return self.grid; 527 } 528 529 pub fn getFocus(self: *Gutter) *Focus { 530 return self.focus; 531 } 532 }; 533