╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Markdown.zig ─────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
310 if (level == 1) { 311 const title = try ui.Title.init(page_arena, text, .solid); 312 self.title_width = try title.width(); 313 self.title = try ui.Title.View.init(allocator, &title); 314 } 315 errdefer if (self.title) |*title| title.deinit(allocator); 316 const sub_title = try ui.SubTitle.init(page_arena, text); 317 self.sub_title_width = try sub_title.width(); 318 self.sub_title = try ui.SubTitle.View.init(allocator, &sub_title); 319 return self; 320 } 321 322 pub fn deinit(self: *Heading, allocator: std.mem.Allocator) void { 323 self.focus.destroy(allocator); 324 self.text.deinit(allocator); 325 if (self.title) |*title| title.deinit(allocator); 326 if (self.sub_title) |*sub_title| sub_title.deinit(allocator); 327 } 328 329 pub fn build(self: *Heading, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 330 self.clearGrid(); 331 self.focus.clear(); 332 const max_width = constraint.max_size.width orelse std.math.maxInt(usize); 333 self.shown = if (self.title != null and self.title_width <= max_width) 334 .title 335 else if (self.sub_title != null and self.sub_title_width <= max_width) 336 .sub_title 337 else 338 .text; 339 switch (self.shown) { 340 .title => try self.buildShown(allocator, constraint, root_focus, if (self.title) |*title| title else unreachable), 341 .sub_title => try self.buildShown(allocator, constraint, root_focus, if (self.sub_title) |*sub_title| sub_title else unreachable), 342 .text => try self.buildShown(allocator, constraint, root_focus, &self.text), 343 } 344 } 345 346 fn buildShown(self: *Heading, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus, widget: anytype) !void { 347 try widget.build(allocator, constraint, root_focus); 348 const grid = widget.getGrid() orelse return; 349 try self.focus.addChild(allocator, widget.getFocus(), grid.size, 0, 0); 350 } 351 352 pub fn input(self: *Heading, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 353 _ = self; 354 _ = allocator; 355 _ = key; 356 _ = root_focus; 357 } 358 359 pub fn clearGrid(self: *Heading) void { 360 self.text.clearGrid(); 361 if (self.title) |*title| title.clearGrid(); 362 if (self.sub_title) |*sub_title| sub_title.clearGrid(); 363 } 364 365 pub fn getGrid(self: Heading) ?Grid { 366 return switch (self.shown) { 367 .title => if (self.title) |title| title.getGrid() else null, 368 .sub_title => if (self.sub_title) |sub_title| sub_title.getGrid() else null, 369 .text => self.text.getGrid(), 370 }; 371 } 372 373 pub fn getFocus(self: *Heading) *Focus { 374 return self.focus; 375 } 376 }; 377 378 // a marker column beside a child, so wrapped lines hang under the child's 379 // first line: a list item's bullet, or a quote's bar on every row. 380 pub const Gutter = struct { 381 focus: *Focus, 382 grid: ?Grid, 383 child: wgt.Box(ui.Widget), 384 marker: []const u8, 385 // draw the marker on every row rather than only the first 386 repeat: bool, 387 style: Grid.Style, 388 389 // takes ownership of `child` on success 390 fn init(allocator: std.mem.Allocator, marker: []const u8, repeat: bool, style: Grid.Style, child: wgt.Box(ui.Widget)) !Gutter { 391 return .{ .focus = try Focus.create(allocator, .container), .grid = null, .child = child, .marker = marker, .repeat = repeat, .style = style }; 392 } 393 394 pub fn deinit(self: *Gutter, allocator: std.mem.Allocator) void { 395 self.focus.destroy(allocator); 396 self.clearGrid(); 397 self.child.deinit(allocator); 398 } 399 400 pub fn build(self: *Gutter, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 401 self.clearGrid(); 402 self.focus.clear(); 403 const marker_width = try xitui.width.displayWidth(self.marker); 404 if (constraint.max_size.width) |w| if (w <= marker_width) return; 405 if (constraint.max_size.height == 0) return; 406 407 try self.child.build(allocator, .{ 408 .min_size = .{ .width = null, .height = null }, 409 .max_size = .{ .width = if (constraint.max_size.width) |w| w - marker_width else null, .height = constraint.max_size.height }, 410 }, root_focus); 411 const child_grid = self.child.getGrid(); 412 const child_size: layout.Size = if (child_grid) |g| g.size else .{ .width = 0, .height = 0 }; 413 414 var grid = try Grid.init(allocator, .{ .width = marker_width + child_size.width, .height = @max(1, child_size.height) }); 415 errdefer grid.deinit(); 416 for (0..if (self.repeat) grid.size.height else 1) |y| { 417 var x: usize = 0; 418 var utf8 = (try std.unicode.Utf8View.init(self.marker)).iterator(); 419 while (utf8.nextCodepoint()) |rune| { 420 (try grid.cell(x, y)).style = self.style; 421 try grid.setRune(x, y, rune); 422 x += xitui.width.cellWidth(rune); 423 } 424 } 425 if (child_grid) |g| { 426 try grid.drawGrid(g, marker_width, 0); 427 try self.focus.addChild(allocator, self.child.getFocus(), g.size, marker_width, 0); 428 } 429 self.grid = grid; 430 } 431 432 pub fn input(self: *Gutter, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 433 _ = self; 434 _ = allocator; 435 _ = key; 436 _ = root_focus; 437 } 438 439 pub fn clearGrid(self: *Gutter) void { 440 if (self.grid) |*grid| { 441 grid.deinit(); 442 self.grid = null; 443 } 444 self.child.clearGrid(); 445 } 446 447 pub fn getGrid(self: Gutter) ?Grid { 448 return self.grid; 449 } 450 451 pub fn getFocus(self: *Gutter) *Focus { 452 return self.focus; 453 } 454 }; 455