Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions d2cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
if err != nil {
return err
}
codeThemeFlag := ms.Opts.String("CODE_THEME", "code-theme", "", "github", "Chroma syntax highlighting theme for code blocks.")
codeDarkThemeFlag := ms.Opts.String("CODE_DARK_THEME", "code-dark-theme", "", "catppuccin-mocha", "Chroma syntax highlighting theme for code blocks in dark mode.")

padFlag, err := ms.Opts.Int64("D2_PAD", "pad", "", d2svg.DEFAULT_PADDING, "pixels padded around the rendered diagram")
if err != nil {
return err
Expand Down Expand Up @@ -337,15 +340,17 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
}

renderOpts := d2svg.RenderOpts{
Pad: padFlag,
Sketch: sketchFlag,
Center: centerFlag,
ThemeID: themeFlag,
DarkThemeID: darkThemeFlag,
Scale: scale,
NoXMLTag: noXMLTagFlag,
Salt: saltFlag,
OmitVersion: omitVersionFlag,
Pad: padFlag,
Sketch: sketchFlag,
Center: centerFlag,
ThemeID: themeFlag,
DarkThemeID: darkThemeFlag,
CodeTheme: *codeThemeFlag,
CodeDarkTheme: *codeDarkThemeFlag,
Scale: scale,
NoXMLTag: noXMLTagFlag,
Salt: saltFlag,
OmitVersion: omitVersionFlag,
}

if *watchFlag {
Expand Down Expand Up @@ -946,6 +951,8 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts
MasterID: opts.MasterID,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
CodeTheme: opts.CodeTheme,
CodeDarkTheme: opts.CodeDarkTheme,
ThemeOverrides: opts.ThemeOverrides,
DarkThemeOverrides: opts.DarkThemeOverrides,
NoXMLTag: opts.NoXMLTag,
Expand Down Expand Up @@ -1045,6 +1052,8 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
Scale: scale,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
CodeTheme: opts.CodeTheme,
CodeDarkTheme: opts.CodeDarkTheme,
ThemeOverrides: opts.ThemeOverrides,
DarkThemeOverrides: opts.DarkThemeOverrides,
OmitVersion: opts.OmitVersion,
Expand Down Expand Up @@ -1153,6 +1162,8 @@ func renderPPTX(ctx context.Context, ms *xmain.State, presentation *pptx.Present
Scale: scale,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
CodeTheme: opts.CodeTheme,
CodeDarkTheme: opts.CodeDarkTheme,
ThemeOverrides: opts.ThemeOverrides,
DarkThemeOverrides: opts.DarkThemeOverrides,
OmitVersion: opts.OmitVersion,
Expand Down Expand Up @@ -1448,6 +1459,8 @@ func renderPNGsForGIF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plug
Scale: scale,
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
CodeTheme: opts.CodeTheme,
CodeDarkTheme: opts.CodeDarkTheme,
ThemeOverrides: opts.ThemeOverrides,
DarkThemeOverrides: opts.DarkThemeOverrides,
OmitVersion: opts.OmitVersion,
Expand Down
61 changes: 38 additions & 23 deletions d2renderers/d2svg/d2svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ package d2svg

import (
"bytes"

_ "embed"
"encoding/base64"
"errors"
"fmt"
"hash/fnv"
"html"
"io"
"math"
"sort"
"strings"

"math"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters"
"github.com/alecthomas/chroma/v2/lexers"
Expand All @@ -41,8 +41,7 @@ import (
)

const (
DEFAULT_PADDING = 100

DEFAULT_PADDING = 100
appendixIconRadius = 16

// Legend constants
Expand Down Expand Up @@ -84,6 +83,8 @@ type RenderOpts struct {
DarkThemeID *int64
ThemeOverrides *d2target.ThemeOverrides
DarkThemeOverrides *d2target.ThemeOverrides
CodeTheme string
CodeDarkTheme string
Font string
// the svg will be scaled by this factor, if unset the svg will fit to screen
Scale *float64
Expand Down Expand Up @@ -178,7 +179,7 @@ func dimensions(diagram *d2target.Diagram, pad int) (left, top, width, height in
return left, top, width, height
}

func RenderLegend(buf *bytes.Buffer, diagram *d2target.Diagram, diagramHash string, theme *d2themes.Theme) error {
func RenderLegend(buf *bytes.Buffer, diagram *d2target.Diagram, diagramHash string, theme *d2themes.Theme, codeTheme string, codeDarkTheme string) error {
if diagram.Legend == nil || (len(diagram.Legend.Shapes) == 0 && len(diagram.Legend.Connections) == 0) {
return nil
}
Expand Down Expand Up @@ -285,7 +286,7 @@ func RenderLegend(buf *bytes.Buffer, diagram *d2target.Diagram, diagramHash stri
iconX := legendX + LEGEND_PADDING
iconY := currentY

shapeIcon, err := renderLegendShapeIcon(s, iconX, iconY, diagramHash, theme)
shapeIcon, err := renderLegendShapeIcon(s, iconX, iconY, diagramHash, theme, codeTheme, codeDarkTheme)
if err != nil {
return err
}
Expand Down Expand Up @@ -332,7 +333,7 @@ func RenderLegend(buf *bytes.Buffer, diagram *d2target.Diagram, diagramHash stri
iconX := legendX + LEGEND_PADDING
iconY := currentY + LEGEND_ICON_SIZE/2

connIcon, err := renderLegendConnectionIcon(c, iconX, iconY, theme)
connIcon, err := renderLegendConnectionIcon(c, iconX, iconY, theme, codeTheme, codeDarkTheme)
if err != nil {
return err
}
Expand Down Expand Up @@ -364,7 +365,7 @@ func RenderLegend(buf *bytes.Buffer, diagram *d2target.Diagram, diagramHash stri
return nil
}

func renderLegendShapeIcon(s d2target.Shape, x, y int, diagramHash string, theme *d2themes.Theme) (string, error) {
func renderLegendShapeIcon(s d2target.Shape, x, y int, diagramHash string, theme *d2themes.Theme, codeTheme string, codeDarkTheme string) (string, error) {
iconShape := s
const sizeFactor = 5
iconShape.Pos.X = 0
Expand All @@ -377,7 +378,7 @@ func renderLegendShapeIcon(s d2target.Shape, x, y int, diagramHash string, theme
finalBuf := &bytes.Buffer{}
fmt.Fprintf(finalBuf, `<g transform="translate(%d, %d) scale(%f)">`,
x, y, 1.0/sizeFactor)
_, err := drawShape(buf, appendixBuf, diagramHash, iconShape, nil, theme)
_, err := drawShape(buf, appendixBuf, diagramHash, iconShape, nil, theme, codeTheme, codeDarkTheme)
if err != nil {
return "", err
}
Expand All @@ -389,7 +390,7 @@ func renderLegendShapeIcon(s d2target.Shape, x, y int, diagramHash string, theme
return finalBuf.String(), nil
}

func renderLegendConnectionIcon(c d2target.Connection, x, y int, theme *d2themes.Theme) (string, error) {
func renderLegendConnectionIcon(c d2target.Connection, x, y int, theme *d2themes.Theme, codeTheme string, codeDarkTheme string) (string, error) {
finalBuf := &bytes.Buffer{}

buf := &bytes.Buffer{}
Expand Down Expand Up @@ -426,7 +427,7 @@ func renderLegendConnectionIcon(c d2target.Connection, x, y int, theme *d2themes
fmt.Fprintf(finalBuf, `<g transform="translate(%d, %d) scale(%f)">`,
x, y, 1.0/sizeFactor)

_, err := drawConnection(buf, legendHash, legendConn, markers, idToShape, nil, theme)
_, err := drawConnection(buf, legendHash, legendConn, markers, idToShape, nil, theme, codeTheme, codeDarkTheme)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -466,7 +467,6 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection, i
polygonEl.Fill = connection.Stroke
polygonEl.ClassName = "connection"
polygonEl.Attributes = fmt.Sprintf(`stroke-width="%d"`, connection.StrokeWidth)

if isTarget {
polygonEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f",
0., 0.,
Expand Down Expand Up @@ -1003,7 +1003,7 @@ func makeBorderLabelMask(labelPosition label.Position, labelTL *geo.Point, label
)
}

func drawConnection(writer io.Writer, diagramHash string, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape, jsRunner jsrunner.JSRunner, inlineTheme *d2themes.Theme) (labelMask string, _ error) {
func drawConnection(writer io.Writer, diagramHash string, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape, jsRunner jsrunner.JSRunner, inlineTheme *d2themes.Theme, codeTheme string, codeDarkTheme string) (labelMask string, _ error) {
opacityStyle := ""
if connection.Opacity != 1.0 {
opacityStyle = fmt.Sprintf(" style='opacity:%f'", connection.Opacity)
Expand Down Expand Up @@ -1210,13 +1210,13 @@ func drawConnection(writer io.Writer, diagramHash string, connection d2target.Co
lexer = lexers.Fallback
}
for _, isLight := range []bool{true, false} {
theme := "github"
theme := codeTheme
if !isLight {
theme = "catppuccin-mocha"
theme = codeDarkTheme
}
style := styles.Get(theme)
if style == nil {
return labelMask, errors.New(`code snippet style "github" not found`)
return labelMask, errors.New(`code snippet style not found`)
}
iterator, err := lexer.Tokenise(nil, connection.Label)
if err != nil {
Expand Down Expand Up @@ -1599,7 +1599,7 @@ func render3DHexagon(diagramHash string, targetShape d2target.Shape, inlineTheme
return borderMask + mainShapeRendered + renderedSides + renderedBorder
}

func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape d2target.Shape, jsRunner jsrunner.JSRunner, inlineTheme *d2themes.Theme) (labelMask string, err error) {
func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape d2target.Shape, jsRunner jsrunner.JSRunner, inlineTheme *d2themes.Theme, codeTheme string, codeDarkTheme string) (labelMask string, err error) {
closingTag := "</g>"
if targetShape.Link != "" {

Expand Down Expand Up @@ -2105,13 +2105,14 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
lexer = lexers.Fallback
}
for _, isLight := range []bool{true, false} {
theme := "github"
theme := codeTheme
if !isLight {
theme = "catppuccin-mocha"
theme = codeDarkTheme
}

style := styles.Get(theme)
if style == nil {
return labelMask, errors.New(`code snippet style "github" not found`)
return labelMask, errors.New(`code snippet style not found`)
}
formatter := formatters.Get("svg")
if formatter == nil {
Expand Down Expand Up @@ -2729,12 +2730,18 @@ func appendOnTrigger(buf *bytes.Buffer, source string, triggers []string, newCon
}

var DEFAULT_DARK_THEME *int64 = nil // no theme selected
var DEFAULT_CODE_THEME = "github"
var DEFAULT_CODE_DARK_THEME = "catppuccin-mocha"

func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
var jsRunner jsrunner.JSRunner
pad := DEFAULT_PADDING
themeID := d2themescatalog.NeutralDefault.ID
darkThemeID := DEFAULT_DARK_THEME

codeTheme := DEFAULT_CODE_THEME
codeDarkTheme := DEFAULT_CODE_DARK_THEME

var scale *float64
if opts != nil {
if opts.Pad != nil {
Expand All @@ -2752,6 +2759,14 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
}
darkThemeID = opts.DarkThemeID
scale = opts.Scale

if opts.CodeTheme != "" {
codeTheme = opts.CodeTheme
}
if opts.CodeDarkTheme != "" {
codeDarkTheme = opts.CodeDarkTheme
}

} else {
opts = &RenderOpts{}
}
Expand Down Expand Up @@ -2829,15 +2844,15 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
}
for _, obj := range allObjects {
if c, is := obj.(d2target.Connection); is {
labelMask, err := drawConnection(buf, isolatedDiagramHash, c, markers, idToShape, jsRunner, inlineTheme)
labelMask, err := drawConnection(buf, isolatedDiagramHash, c, markers, idToShape, jsRunner, inlineTheme, codeTheme, codeDarkTheme)
if err != nil {
return nil, err
}
if labelMask != "" {
labelMasks = append(labelMasks, labelMask)
}
} else if s, is := obj.(d2target.Shape); is {
labelMask, err := drawShape(buf, appendixItemBuf, diagramHash, s, jsRunner, inlineTheme)
labelMask, err := drawShape(buf, appendixItemBuf, diagramHash, s, jsRunner, inlineTheme, codeTheme, codeDarkTheme)
if err != nil {
return nil, err
} else if labelMask != "" {
Expand All @@ -2852,7 +2867,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {

if diagram.Legend != nil && (len(diagram.Legend.Shapes) > 0 || len(diagram.Legend.Connections) > 0) {
legendBuf := &bytes.Buffer{}
err := RenderLegend(legendBuf, diagram, diagramHash, inlineTheme)
err := RenderLegend(legendBuf, diagram, diagramHash, inlineTheme, codeTheme, codeDarkTheme)
if err != nil {
return nil, err
}
Expand Down
Loading