///! Transform a given `zmd.Note` into a buffer which can be used by any `vaxis.widgets.View` const std = @import("std"); const vaxis = @import("vaxis"); const zmd = @import("zmd"); pub fn toBuffer( node: *zmd.Node, allocator: std.mem.Allocator, input: []const u8, array: *std.ArrayList(vaxis.Cell), sty: vaxis.Cell.Style, start: ?usize, ) !void { var next_start: ?usize = start; var style = sty; // FIXME: support list display // TODO: improve code block listings (i.e. add line numbers with corresponding separator, etc.) // determine general styling changes switch (node.token.element.type) { .bold => { style.bold = true; next_start = node.token.start; style.fg = .{ .index = 5 }; }, .italic => { style.italic = true; next_start = node.token.start; style.fg = .{ .index = 2 }; }, .block => { // TODO: what should I do with blocks? style.fg = .{ .index = 7 }; next_start = node.token.start; }, .code => { next_start = node.token.start; style.fg = .{ .index = 6 }; }, .href => { next_start = node.token.start; style.fg = .{ .index = 8 }; }, .link => { style.fg = .{ .index = 3 }; }, else => {}, } // determine content that needs to be displayed const content = value: { switch (node.token.element.type) { .text => break :value input[node.token.start..node.token.end], .link => break :value input[node.token.start + 1 .. node.token.start + 1 + node.title.?.len], // TODO: use corresponding link contents to create 'real' links using escape sequences .bold_close, .italic_close, .block_close, .code_close, .title_close, .href_close => { if (next_start) |s| { next_start = null; break :value input[s..node.token.end]; } break :value ""; }, else => { break :value ""; }, } }; // display content switch (node.token.element.type) { .linebreak, .paragraph => { try array.append(.{ .char = .{ .grapheme = "\n" }, .style = style, }); style.ul_style = .off; }, .h1 => { style.ul_style = .single; try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); }, .h2 => { style.ul_style = .single; for (0..2) |_| { try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); } }, .h3 => { style.ul_style = .single; for (0..3) |_| { try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); } }, .h4 => { style.ul_style = .single; for (0..4) |_| { try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); } }, .h5 => { style.ul_style = .single; for (0..5) |_| { try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); } }, .h6 => { style.ul_style = .single; for (0..6) |_| { try array.append(.{ .char = .{ .grapheme = "#" }, .style = style, }); } }, .link => { style.ul_style = .single; const uri = input[node.token.start + 1 + node.title.?.len + 2 .. node.token.start + 1 + node.title.?.len + 2 + node.href.?.len]; for (content, 0..) |_, i| { try array.append(.{ .link = .{ .uri = uri }, .char = .{ .grapheme = content[i .. i + 1] }, .style = style, }); } }, else => { for (content, 0..) |_, i| { try array.append(.{ .char = .{ .grapheme = content[i .. i + 1] }, .style = style, }); } }, } // close styling after creating the corresponding cells switch (node.token.element.type) { .bold_close => { style.bold = false; style.fg = .default; }, .italic_close => { style.italic = false; style.fg = .default; }, .block_close => { // TODO: what should I do with blocks? style.fg = .default; }, .code_close => { style.fg = .default; }, .href_close => { style.fg = .default; }, else => {}, } // run conversion for all childrens for (node.children.items) |child_node| { try toBuffer(child_node, allocator, input, array, style, next_start); } }