diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 42bb445ab..d94bb45fe 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -14,3 +14,4 @@ - Fixes attributes being ignored for `sql_table` to `sql_table` connections. [#658](https://github.com/terrastruct/d2/pull/658) - Fixes tooltip/link attributes being ignored for `sql_table` and `class`. [#658](https://github.com/terrastruct/d2/pull/658) - Fixes arrowheads sometimes appearing broken with sketch on. [#656](https://github.com/terrastruct/d2/pull/656) +- Fixes code snippets not being tall enough with leading newlines. [#664](https://github.com/terrastruct/d2/pull/664) diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 21361304a..28ea03ef9 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1027,6 +1027,27 @@ func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2 var h int if t.Language != "" { w, h = ruler.Measure(d2fonts.SourceCodePro.Font(t.FontSize, d2fonts.FONT_STYLE_REGULAR), t.Text) + + // count empty leading and trailing lines since ruler will not be able to measure it + lines := strings.Split(t.Text, "\n") + leadingLines := 0 + for _, line := range lines { + if strings.TrimSpace(line) == "" { + leadingLines++ + } else { + break + } + } + trailingLines := 0 + for i := len(lines) - 1; i >= 0; i-- { + if strings.TrimSpace(lines[i]) == "" { + trailingLines++ + } else { + break + } + } + h += t.FontSize * (leadingLines + trailingLines) + // padding w += 12 h += 12 diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index 2943852d9..fe6413827 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -329,6 +329,39 @@ a.c { style.stroke: white d } +`, + }, + { + name: "code_leading_trailing_newlines", + script: ` +hello world: |python + + + # 2 leading, 2 trailing + def hello(): + + print "world" + + +| + +no trailing: |python + + + # 2 leading + def hello(): + + print "world" +| + +no leading: |python + # 2 trailing + def hello(): + + print "world" + + +| `, }, } diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json new file mode 100644 index 000000000..6096ee9c0 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json @@ -0,0 +1,124 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hello world", + "type": "code", + "pos": { + "x": 0, + "y": 0 + }, + "width": 239, + "height": 150, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading, 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 239, + "labelHeight": 150, + "zIndex": 0, + "level": 1 + }, + { + "id": "no trailing", + "type": "code", + "pos": { + "x": 299, + "y": 16 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading\ndef hello():\n\n print \"world\"", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + }, + { + "id": "no leading", + "type": "code", + "pos": { + "x": 519, + "y": 16 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "# 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg new file mode 100644 index 000000000..b35570020 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg @@ -0,0 +1,69 @@ + + + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json new file mode 100644 index 000000000..da4f01ab5 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json @@ -0,0 +1,124 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hello world", + "type": "code", + "pos": { + "x": 12, + "y": 12 + }, + "width": 239, + "height": 150, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading, 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 239, + "labelHeight": 150, + "zIndex": 0, + "level": 1 + }, + { + "id": "no trailing", + "type": "code", + "pos": { + "x": 271, + "y": 28 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading\ndef hello():\n\n print \"world\"", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + }, + { + "id": "no leading", + "type": "code", + "pos": { + "x": 451, + "y": 28 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "# 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg new file mode 100644 index 000000000..5f47f871b --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg @@ -0,0 +1,69 @@ + + + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file