From 2727c586100c335330454298ef98c0d25d7a2c24 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 13 Jan 2023 20:51:11 -0800 Subject: [PATCH 1/5] add md_h1_li_li regression test --- e2etests/regression_test.go | 8 + .../md_h1_li_li/dagre/board.exp.json | 223 +++++ .../md_h1_li_li/dagre/sketch.exp.svg | 824 ++++++++++++++++++ .../regression/md_h1_li_li/elk/board.exp.json | 205 +++++ .../regression/md_h1_li_li/elk/sketch.exp.svg | 824 ++++++++++++++++++ 5 files changed, 2084 insertions(+) create mode 100644 e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json create mode 100644 e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg create mode 100644 e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json create mode 100644 e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index fe6413827..5239201c0 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -364,6 +364,14 @@ no leading: |python | `, }, + { + name: "md_h1_li_li", + script: mdTestScript(` +# hey +- they + 1. they +`), + }, } runa(t, tcs) diff --git a/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json b/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json new file mode 100644 index 000000000..190f5ee5e --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json @@ -0,0 +1,223 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "md", + "type": "text", + "pos": { + "x": 9, + "y": 226 + }, + "width": 95, + "height": 110, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n# hey\n- they\n\t1. they\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 95, + "labelHeight": 110, + "zIndex": 0, + "level": 1 + }, + { + "id": "a", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "", + "pos": { + "x": 0, + "y": 436 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> md)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "md", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 56.5, + "y": 126 + }, + { + "x": 56.5, + "y": 166 + }, + { + "x": 56.5, + "y": 186 + }, + { + "x": 56.5, + "y": 226 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(md -> b)[0]", + "src": "md", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 56.5, + "y": 336 + }, + { + "x": 56.5, + "y": 376 + }, + { + "x": 56.5, + "y": 396 + }, + { + "x": 56.5, + "y": 436 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg b/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg new file mode 100644 index 000000000..ee8454068 --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg @@ -0,0 +1,824 @@ + +

hey

+
    +
  • they +
      +
    1. they
    2. +
    +
  • +
+
ab + + +
\ No newline at end of file diff --git a/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json b/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json new file mode 100644 index 000000000..3f26d8123 --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json @@ -0,0 +1,205 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "md", + "type": "text", + "pos": { + "x": 21, + "y": 238 + }, + "width": 95, + "height": 110, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n# hey\n- they\n\t1. they\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 95, + "labelHeight": 110, + "zIndex": 0, + "level": 1 + }, + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "", + "pos": { + "x": 12, + "y": 448 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> md)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "md", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 68.5, + "y": 138 + }, + { + "x": 68.5, + "y": 238 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(md -> b)[0]", + "src": "md", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 68.5, + "y": 348 + }, + { + "x": 68.5, + "y": 448 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg b/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg new file mode 100644 index 000000000..8624d8414 --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg @@ -0,0 +1,824 @@ + +

hey

+
    +
  • they +
      +
    1. they
    2. +
    +
  • +
+
ab + + +
\ No newline at end of file From 1a07492517c7673ad8033ad3bad0dee7d7fb95ae Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 13 Jan 2023 20:55:10 -0800 Subject: [PATCH 2/5] update li measurement + h1 border-bottom --- lib/textmeasure/markdown.go | 84 +++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/lib/textmeasure/markdown.go b/lib/textmeasure/markdown.go index bf12dc7ab..4a30afbbb 100644 --- a/lib/textmeasure/markdown.go +++ b/lib/textmeasure/markdown.go @@ -2,6 +2,7 @@ package textmeasure import ( "bytes" + "fmt" "math" "strings" @@ -33,6 +34,7 @@ const ( MarginTop_h = 24 MarginBottom_h = 16 PaddingBottom_h1_h2_em = 0.3 + BorderBottom_h1_h2 = 1 Height_hr = 4 MarginTopBottom_hr = 24 @@ -203,6 +205,18 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon parentElementType = n.Parent.Data } + debugMeasure := false + var depthStr string + if debugMeasure { + if depth == 0 { + fmt.Println() + } + depthStr = "┌" + for i := 0; i < depth; i++ { + depthStr += "-" + } + } + switch n.Type { case html.TextNode: if strings.TrimSpace(n.Data) == "" { @@ -244,6 +258,9 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon w *= FontSize_pre_code_em h *= FontSize_pre_code_em } + if debugMeasure { + fmt.Printf("%stext(%v,%v)\n", depthStr, w, h) + } return blockAttrs{w + spaceWidths, h, 0, 0} case html.ElementNode: isCode := false @@ -273,58 +290,58 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon last := getPrev(n.LastChild) var blocks []blockAttrs - var current *blockAttrs + var inlineBlock *blockAttrs // first create blocks from combined inline elements, then combine all blocks - // current will be non-nil while inline elements are being combined into a block + // inlineBlock will be non-nil while inline elements are being combined into a block + endInlineBlock := func() { + if !isCode && inlineBlock.height > 0 && inlineBlock.height < MarkdownLineHeightPx { + inlineBlock.height = MarkdownLineHeightPx + } + blocks = append(blocks, *inlineBlock) + inlineBlock = nil + } for child := n.FirstChild; child != nil; child = child.NextSibling { childBlock := ruler.measureNode(depth+1, child, fontFamily, fontSize, fontStyle) if child.Type == html.ElementNode && isBlockElement(child.Data) { - if current != nil { - blocks = append(blocks, *current) + if inlineBlock != nil { + endInlineBlock() } - current = &blockAttrs{} + newBlock := &blockAttrs{} + newBlock.width = childBlock.width + newBlock.height = childBlock.height if child == first && n.Data == "blockquote" { - current.marginTop = 0. + newBlock.marginTop = 0. } else { - current.marginTop = childBlock.marginTop + newBlock.marginTop = childBlock.marginTop } if child == last && n.Data == "blockquote" { - current.marginBottom = 0. + newBlock.marginBottom = 0. } else { - current.marginBottom = childBlock.marginBottom + newBlock.marginBottom = childBlock.marginBottom } - current.width = childBlock.width - current.height = childBlock.height - blocks = append(blocks, *current) - current = nil + blocks = append(blocks, *newBlock) } else if child.Type == html.ElementNode && child.Data == "br" { - if current != nil { - if !isCode && current.height > 0 && current.height < MarkdownLineHeightPx { - current.height = MarkdownLineHeightPx - } - blocks = append(blocks, *current) - current = nil + if inlineBlock != nil { + endInlineBlock() } } else if childBlock.isNotEmpty() { - if current == nil { - current = &childBlock + if inlineBlock == nil { + // start inline block with child + inlineBlock = &childBlock } else { - current.marginTop = go2.Max(current.marginTop, childBlock.marginTop) - current.marginBottom = go2.Max(current.marginBottom, childBlock.marginBottom) + // stack inline element dimensions horizontally + inlineBlock.width += childBlock.width + inlineBlock.height = go2.Max(inlineBlock.height, childBlock.height) - current.width += childBlock.width - current.height = go2.Max(current.height, childBlock.height) + inlineBlock.marginTop = go2.Max(inlineBlock.marginTop, childBlock.marginTop) + inlineBlock.marginBottom = go2.Max(inlineBlock.marginBottom, childBlock.marginBottom) } } } - if current != nil { - if !isCode && current.height > 0 && current.height < MarkdownLineHeightPx { - current.height = MarkdownLineHeightPx - } - blocks = append(blocks, *current) - current = nil + if inlineBlock != nil { + endInlineBlock() } var prevMarginBottom float64 @@ -363,7 +380,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon block.marginBottom = go2.Max(block.marginBottom, MarginBottom_h) switch n.Data { case "h1", "h2": - block.height += PaddingBottom_h1_h2_em * float64(fontSize) + block.height += PaddingBottom_h1_h2_em*float64(fontSize) + BorderBottom_h1_h2 } case "li": block.width += PaddingLeft_ul_ol @@ -394,6 +411,9 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon if block.height > 0 && block.height < MarkdownLineHeightPx { block.height = MarkdownLineHeightPx } + if debugMeasure { + fmt.Printf("%s%s(%v,%v) mt:%v mb:%v\n", depthStr, n.Data, block.width, block.height, block.marginTop, block.marginBottom) + } return block } return blockAttrs{} From 41741e0d673a3d33c3b05c3e7ac0a614810c8bf4 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 13 Jan 2023 20:59:50 -0800 Subject: [PATCH 3/5] update test --- .../regression/md_h1_li_li/dagre/board.exp.json | 14 +++++++------- .../regression/md_h1_li_li/dagre/sketch.exp.svg | 8 ++++---- .../regression/md_h1_li_li/elk/board.exp.json | 10 +++++----- .../regression/md_h1_li_li/elk/sketch.exp.svg | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json b/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json index 190f5ee5e..636f04603 100644 --- a/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json +++ b/e2etests/testdata/regression/md_h1_li_li/dagre/board.exp.json @@ -10,7 +10,7 @@ "y": 226 }, "width": 95, - "height": 110, + "height": 115, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -37,7 +37,7 @@ "bold": false, "underline": false, "labelWidth": 95, - "labelHeight": 110, + "labelHeight": 115, "zIndex": 0, "level": 1 }, @@ -86,7 +86,7 @@ "type": "", "pos": { "x": 0, - "y": 436 + "y": 441 }, "width": 113, "height": 126, @@ -198,19 +198,19 @@ "route": [ { "x": 56.5, - "y": 336 + "y": 341 }, { "x": 56.5, - "y": 376 + "y": 381 }, { "x": 56.5, - "y": 396 + "y": 401 }, { "x": 56.5, - "y": 436 + "y": 441 } ], "isCurve": true, diff --git a/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg b/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg index ee8454068..8f944eaa4 100644 --- a/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/md_h1_li_li/dagre/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="317" height="766" viewBox="-102 -102 317 766">

hey

+

hey

  • they
      @@ -804,8 +804,8 @@ width="317" height="766" viewBox="-102 -102 317 766">

      hey

      +

      hey

      • they
          @@ -804,8 +804,8 @@ width="317" height="766" viewBox="-90 -90 317 766">xyThe top of the mountainJoeDonald

          Cats, no less liquid than their shadows, offer no angles to the wind.

          +xyThe top of the mountainJoeDonald

          Cats, no less liquid than their shadows, offer no angles to the wind.

          If we can't fix it, it ain't broke.

          Dieters live life in the fasting lane.

          -
          i am top lefti am top righti am bottom lefti am bottom right - +
          i am top lefti am top righti am bottom lefti am bottom right + xyThe top of the mountainJoeDonald

          Cats, no less liquid than their shadows, offer no angles to the wind.

          +xyThe top of the mountainJoeDonald

          Cats, no less liquid than their shadows, offer no angles to the wind.

          If we can't fix it, it ain't broke.

          Dieters live life in the fasting lane.

          -
          i am top lefti am top righti am bottom lefti am bottom right - +
          i am top lefti am top righti am bottom lefti am bottom right + poll the peopleresultsunfavorablefavorablewill of the people

          A winning strategy

          -
          - +poll the peopleresultsunfavorablefavorablewill of the people

          A winning strategy

          +
          + poll the peopleresultsunfavorablefavorablewill of the people

          A winning strategy

          -
          - +poll the peopleresultsunfavorablefavorablewill of the people

          A winning strategy

          +
          +

          Markdown: Syntax

          +

          Markdown: Syntax

          • Overview
              @@ -1053,8 +1053,8 @@ title for the link, surrounded in quotes. For example:

              Code

              Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

              -
          ab - +
          ab +

          Markdown: Syntax

          +

          Markdown: Syntax

          • Overview
              @@ -1053,8 +1053,8 @@ title for the link, surrounded in quotes. For example:

              Code

              Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

              -
          ab - +
          ab +

          Note: This document is itself written using Markdown; you +

          Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


          Overview

          -
          ab - +
          ab +

          Note: This document is itself written using Markdown; you +

          Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


          Overview

          -
          ab - +
          ab +

          Markdown: Syntax

          -
          ab - +

          Markdown: Syntax

          +
          ab +

          Markdown: Syntax

          -
          ab - +

          Markdown: Syntax

          +
          ab +

          Every frustum longs to be a cone

          +

          Every frustum longs to be a cone

          • A continuing flow of paper is sufficient to continue the flow of paper
          • Please remain calm, it's no use both of us being hysterical at the same time
          • Visits always give pleasure: if not on arrival, then on the departure

          Festivity Level 1: Your guests are chatting amiably with each other.

          -
          xy - +
          xy +

          Every frustum longs to be a cone

          +

          Every frustum longs to be a cone

          • A continuing flow of paper is sufficient to continue the flow of paper
          • Please remain calm, it's no use both of us being hysterical at the same time
          • Visits always give pleasure: if not on arrival, then on the departure

          Festivity Level 1: Your guests are chatting amiably with each other.

          -
          xy - +
          xy + container

          they did it in style

          -

          a header

          +container

          they did it in style

          +

          a header

          a line of text and an

          {
           	indented: "block",
          @@ -805,8 +805,8 @@ width="516" height="685" viewBox="-102 -102 516 685">container

          they did it in style

          -

          a header

          +container

          they did it in style

          +

          a header

          a line of text and an

          {
           	indented: "block",
          @@ -805,8 +805,8 @@ width="566" height="735" viewBox="-90 -90 566 735">