mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Escape special characters and handle whitespace in Markdown
This commit is contained in:
@@ -154,7 +154,7 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
|
|||||||
.img => {
|
.img => {
|
||||||
try writer.writeAll(";
|
try writer.writeAll("](");
|
||||||
if (el.getAttributeSafe(comptime .wrap("src"))) |src| {
|
if (el.getAttributeSafe(comptime .wrap("src"))) |src| {
|
||||||
@@ -243,6 +243,18 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for pure whitespace
|
||||||
|
const is_all_whitespace = for (text) |c| {
|
||||||
|
if (!std.ascii.isWhitespace(c)) break false;
|
||||||
|
} else true;
|
||||||
|
|
||||||
|
if (is_all_whitespace) {
|
||||||
|
if (!state.last_char_was_newline) {
|
||||||
|
try writer.writeByte(' ');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Collapse whitespace
|
// Collapse whitespace
|
||||||
var it = std.mem.tokenizeAny(u8, text, " \t\n\r");
|
var it = std.mem.tokenizeAny(u8, text, " \t\n\r");
|
||||||
var first = true;
|
var first = true;
|
||||||
@@ -261,7 +273,7 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
|
|||||||
try writer.writeByte(' ');
|
try writer.writeByte(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(word);
|
try escapeMarkdown(writer, word);
|
||||||
state.last_char_was_newline = false;
|
state.last_char_was_newline = false;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
@@ -274,9 +286,101 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void {
|
||||||
|
// Escaping: \ ` * _ { } [ ] ( ) # + - . ! | < >
|
||||||
|
for (text) |c| {
|
||||||
|
switch (c) {
|
||||||
|
'\\',
|
||||||
|
'`',
|
||||||
|
'*',
|
||||||
|
'_',
|
||||||
|
'{',
|
||||||
|
'}',
|
||||||
|
'[',
|
||||||
|
']',
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'#',
|
||||||
|
'+',
|
||||||
|
'-',
|
||||||
|
'.',
|
||||||
|
'!',
|
||||||
|
'|',
|
||||||
|
'<',
|
||||||
|
'>',
|
||||||
|
=> {
|
||||||
|
try writer.writeByte('\\');
|
||||||
|
try writer.writeByte(c);
|
||||||
|
},
|
||||||
|
else => try writer.writeByte(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn writeIndentation(level: usize, writer: *std.Io.Writer) anyerror!void {
|
fn writeIndentation(level: usize, writer: *std.Io.Writer) anyerror!void {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < level) : (i += 1) {
|
while (i < level) : (i += 1) {
|
||||||
try writer.writeAll(" ");
|
try writer.writeAll(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "markdown: basic" {
|
||||||
|
const testing = @import("../testing.zig");
|
||||||
|
const page = try testing.test_session.createPage();
|
||||||
|
defer testing.test_session.removePage();
|
||||||
|
const doc = page.window._document;
|
||||||
|
|
||||||
|
const div = try doc.createElement("div", null, page);
|
||||||
|
try div.asNode().setTextContent("Hello world", page);
|
||||||
|
|
||||||
|
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
try dump(div.asNode(), .{}, &aw.writer, page);
|
||||||
|
|
||||||
|
try testing.expectString("Hello world\n", aw.written());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: whitespace" {
|
||||||
|
const testing = @import("../testing.zig");
|
||||||
|
const page = try testing.test_session.createPage();
|
||||||
|
defer testing.test_session.removePage();
|
||||||
|
const doc = page.window._document;
|
||||||
|
|
||||||
|
const div = try doc.createElement("div", null, page);
|
||||||
|
|
||||||
|
const s1 = try doc.createElement("span", null, page);
|
||||||
|
try s1.asNode().setTextContent("A", page);
|
||||||
|
const s2 = try doc.createElement("span", null, page);
|
||||||
|
try s2.asNode().setTextContent("B", page);
|
||||||
|
|
||||||
|
_ = try div.asNode().appendChild(s1.asNode(), page);
|
||||||
|
// Add text node with space
|
||||||
|
const txt = try page.createTextNode(" ");
|
||||||
|
_ = try div.asNode().appendChild(txt, page);
|
||||||
|
_ = try div.asNode().appendChild(s2.asNode(), page);
|
||||||
|
|
||||||
|
var aw = std.Io.Writer.Allocating.init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
try dump(div.asNode(), .{}, &aw.writer, page);
|
||||||
|
|
||||||
|
try testing.expectString("A B\n", aw.written());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: escaping" {
|
||||||
|
const testing = @import("../testing.zig");
|
||||||
|
const page = try testing.test_session.createPage();
|
||||||
|
defer testing.test_session.removePage();
|
||||||
|
const doc = page.window._document;
|
||||||
|
|
||||||
|
const div = try doc.createElement("div", null, page);
|
||||||
|
|
||||||
|
const p = try doc.createElement("p", null, page);
|
||||||
|
try p.asNode().setTextContent("# Not a header", page);
|
||||||
|
_ = try div.asNode().appendChild(p.asNode(), page);
|
||||||
|
|
||||||
|
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
try dump(div.asNode(), .{}, &aw.writer, page);
|
||||||
|
|
||||||
|
try testing.expectString("\n\\# Not a header\n", aw.written());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user