authorgravatar for ian@ianjohnson.devIan Johnson <ian@ianjohnson.dev> 2024-04-08 05:49:22-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-04-08 09:49:22+00:00
log6dcbad780cb716fe1d2a4b2ce201a757ea7f03a4
tree409a785cc7e9c79b96c701ac593be3b92a571c5f
parent355cceebc7104d2e818b4959b0e43f822e19a9b5
signaturebadge-check Signed by PGP key B5690EEEBB952194

Autodoc: fix Markdown indented lists (#19577)

Previously, indentation was not being handled correctly in some cases, causing examples such as `std.json.WriteStream` to be rendered with improper list nesting. Additionally, some more test cases have been added to ensure indentation (or lack of indentation) is handled correctly in some other constructs.

2 files changed, 145 insertions(+), 13 deletions(-)

lib/docs/wasm/markdown.zig+132
......@@ -376,6 +376,106 @@ test "lists with block content" {
376376 );
377377}
378378
379test "indented lists" {
380 try testRender(
381 \\Test:
382 \\ * a1
383 \\ * a2
384 \\ * b1
385 \\ * b2
386 \\
387 \\---
388 \\
389 \\ Test:
390 \\ - One
391 \\Two
392 \\ - Three
393 \\Four
394 \\ Five
395 \\Six
396 \\
397 \\---
398 \\
399 \\None of these items are indented far enough from the previous one to
400 \\start a nested list:
401 \\ - One
402 \\ - Two
403 \\ - Three
404 \\ - Four
405 \\ - Five
406 \\ - Six
407 \\ - Seven
408 \\ - Eight
409 \\ - Nine
410 \\
411 \\---
412 \\
413 \\ - One
414 \\ - Two
415 \\ - Three
416 \\ - Four
417 \\ - Five
418 \\ - Six
419 \\- Seven
420 \\
421 ,
422 \\<p>Test:</p>
423 \\<ul>
424 \\<li>a1</li>
425 \\<li>a2<ul>
426 \\<li>b1</li>
427 \\<li>b2</li>
428 \\</ul>
429 \\</li>
430 \\</ul>
431 \\<hr />
432 \\<p>Test:</p>
433 \\<ul>
434 \\<li>One
435 \\Two<ul>
436 \\<li>Three
437 \\Four
438 \\Five
439 \\Six</li>
440 \\</ul>
441 \\</li>
442 \\</ul>
443 \\<hr />
444 \\<p>None of these items are indented far enough from the previous one to
445 \\start a nested list:</p>
446 \\<ul>
447 \\<li>One</li>
448 \\<li>Two</li>
449 \\<li>Three</li>
450 \\<li>Four</li>
451 \\<li>Five</li>
452 \\<li>Six</li>
453 \\<li>Seven</li>
454 \\<li>Eight</li>
455 \\<li>Nine</li>
456 \\</ul>
457 \\<hr />
458 \\<ul>
459 \\<li>One<ul>
460 \\<li>Two<ul>
461 \\<li>Three<ul>
462 \\<li>Four</li>
463 \\</ul>
464 \\</li>
465 \\</ul>
466 \\</li>
467 \\<li>Five<ul>
468 \\<li>Six</li>
469 \\</ul>
470 \\</li>
471 \\</ul>
472 \\</li>
473 \\<li>Seven</li>
474 \\</ul>
475 \\
476 );
477}
478
379479test "tables" {
380480 try testRender(
381481 \\| Operator | Meaning |
......@@ -394,6 +494,10 @@ test "tables" {
394494 \\| :--- | :----: | ----: |
395495 \\| Left | Center | Right |
396496 \\
497 \\ | One | Two |
498 \\ | Three | Four |
499 \\ | Five | Six |
500 \\
397501 ,
398502 \\<table>
399503 \\<tr>
......@@ -446,6 +550,20 @@ test "tables" {
446550 \\<td style="text-align: right">Right</td>
447551 \\</tr>
448552 \\</table>
553 \\<table>
554 \\<tr>
555 \\<td>One</td>
556 \\<td>Two</td>
557 \\</tr>
558 \\<tr>
559 \\<td>Three</td>
560 \\<td>Four</td>
561 \\</tr>
562 \\<tr>
563 \\<td>Five</td>
564 \\<td>Six</td>
565 \\</tr>
566 \\</table>
449567 \\
450568 );
451569}
......@@ -597,6 +715,14 @@ test "code blocks" {
597715 \\ try std.testing.expect(2 + 2 == 4);
598716 \\}
599717 \\```
718 \\ ```
719 \\ Indentation up to the fence is removed.
720 \\ Like this.
721 \\ Doesn't need to be fully indented.
722 \\ ```
723 \\```
724 \\Overly indented closing fence is fine:
725 \\ ```
600726 \\
601727 ,
602728 \\<pre><code>Hello, world!
......@@ -608,6 +734,12 @@ test "code blocks" {
608734 \\ try std.testing.expect(2 + 2 == 4);
609735 \\}
610736 \\</code></pre>
737 \\<pre><code>Indentation up to the fence is removed.
738 \\ Like this.
739 \\Doesn't need to be fully indented.
740 \\</code></pre>
741 \\<pre><code>Overly indented closing fence is fine:
742 \\</code></pre>
611743 \\
612744 );
613745}
lib/docs/wasm/markdown/Parser.zig+13-13
......@@ -152,7 +152,7 @@ const Block = struct {
152152 ""
153153 else
154154 null,
155 .table => if (unindented.len > 0) unindented else null,
155 .table => if (unindented.len > 0) line else null,
156156 .table_row => null,
157157 .heading => null,
158158 .code_block => code_block: {
......@@ -168,7 +168,7 @@ const Block = struct {
168168 unindented[1..]
169169 else
170170 null,
171 .paragraph => if (unindented.len > 0) unindented else null,
171 .paragraph => if (unindented.len > 0) line else null,
172172 .thematic_break => null,
173173 };
174174 }
......@@ -225,7 +225,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
225225 p.pending_blocks.items.len > 0 and
226226 p.pending_blocks.getLast().tag == .paragraph)
227227 {
228 try p.addScratchStringLine(rest_line);
228 try p.addScratchStringLine(mem.trimLeft(u8, rest_line, " \t"));
229229 return;
230230 }
231231
......@@ -271,8 +271,8 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
271271 // loose, since we might just be looking at a blank line after the
272272 // end of the last item in the list. The final determination will be
273273 // made when appending the next child of the list or list item.
274 const maybe_containing_list = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().tag == .list_item)
275 &p.pending_blocks.items[p.pending_blocks.items.len - 2]
274 const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().tag == .list_item)
275 p.pending_blocks.items.len - 2
276276 else
277277 null;
278278
......@@ -285,8 +285,8 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
285285 try p.addScratchStringLine(rest_line_trimmed);
286286 }
287287
288 if (maybe_containing_list) |containing_list| {
289 containing_list.data.list.last_line_blank = rest_line_trimmed.len == 0;
288 if (maybe_containing_list_index) |containing_list_index| {
289 p.pending_blocks.items[containing_list_index].data.list.last_line_blank = rest_line_trimmed.len == 0;
290290 }
291291 },
292292 .inlines => try p.addScratchStringLine(rest_line_trimmed),
......@@ -515,7 +515,7 @@ fn startBlock(p: *Parser, line: []const u8) !?BlockStart {
515515 .data = .{ .list_item = .{
516516 .marker = list_item.marker,
517517 .number = list_item.number,
518 .continuation_indent = list_item.continuation_indent,
518 .continuation_indent = indent + list_item.marker_len,
519519 } },
520520 .rest = list_item.rest,
521521 };
......@@ -559,7 +559,7 @@ fn startBlock(p: *Parser, line: []const u8) !?BlockStart {
559559const ListItemStart = struct {
560560 marker: Block.Data.ListMarker,
561561 number: u30,
562 continuation_indent: usize,
562 marker_len: usize,
563563 rest: []const u8,
564564};
565565
......@@ -568,21 +568,21 @@ fn startListItem(unindented_line: []const u8) ?ListItemStart {
568568 return .{
569569 .marker = .@"-",
570570 .number = undefined,
571 .continuation_indent = 2,
571 .marker_len = 2,
572572 .rest = unindented_line[2..],
573573 };
574574 } else if (mem.startsWith(u8, unindented_line, "* ")) {
575575 return .{
576576 .marker = .@"*",
577577 .number = undefined,
578 .continuation_indent = 2,
578 .marker_len = 2,
579579 .rest = unindented_line[2..],
580580 };
581581 } else if (mem.startsWith(u8, unindented_line, "+ ")) {
582582 return .{
583583 .marker = .@"+",
584584 .number = undefined,
585 .continuation_indent = 2,
585 .marker_len = 2,
586586 .rest = unindented_line[2..],
587587 };
588588 }
......@@ -600,7 +600,7 @@ fn startListItem(unindented_line: []const u8) ?ListItemStart {
600600 return .{
601601 .marker = marker,
602602 .number = number,
603 .continuation_indent = number_end + 2,
603 .marker_len = number_end + 2,
604604 .rest = after_number[2..],
605605 };
606606}