Merge branch 'master' into shape-specific-inner-boxes
|
|
@ -228,6 +228,7 @@ let us know and we'll be happy to include it here!
|
|||
- **Comparison site**: [https://github.com/terrastruct/text-to-diagram-site](https://github.com/terrastruct/text-to-diagram-site)
|
||||
- **Playground**: [https://github.com/terrastruct/d2-playground](https://github.com/terrastruct/d2-playground)
|
||||
- **Language docs**: [https://github.com/terrastruct/d2-docs](https://github.com/terrastruct/d2-docs)
|
||||
- **Hosted icons**: [https://icons.terrastruct.com](https://icons.terrastruct.com)
|
||||
|
||||
## FAQ
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
#### Features 🚀
|
||||
|
||||
- `double-circle` keyword implemented. [#565](https://github.com/terrastruct/d2/pull/565)
|
||||
- `double-border` keyword implemented. [#565](https://github.com/terrastruct/d2/pull/565)
|
||||
- The [Dockerfile](./docs/INSTALL.md#docker) now supports rendering PNGs [#594](https://github.com/terrastruct/d2/issues/594)
|
||||
|
||||
- There was a minor breaking change as part of this where the default working directory of the Dockerfile is now `/home/debian/src` instead of `/root/src` to allow UID remapping with [`fixuid`](https://github.com/boxboat/fixuid).
|
||||
|
||||
- `d2 fmt` accepts multiple files to be formatted [#718](https://github.com/terrastruct/d2/issues/718)
|
||||
|
||||
#### Improvements 🧹
|
||||
|
||||
- Reduces default padding of shapes. [#702](https://github.com/terrastruct/d2/pull/702)
|
||||
|
|
@ -14,5 +17,7 @@
|
|||
|
||||
#### Bugfixes ⛑️
|
||||
|
||||
- Fixes groups overlapping in sequence diagrams when they end in a self loop. [#728](https://github.com/terrastruct/d2/pull/728)
|
||||
- Fixed dimensions of unlabeled squares or circles with only a set width or height. [#702](https://github.com/terrastruct/d2/pull/702)
|
||||
- Fixed scaling of actor shapes in sequence diagrams. [#702](https://github.com/terrastruct/d2/pull/702)
|
||||
- Code snippets use bold and italic font styles as determined by highlighter [#710](https://github.com/terrastruct/d2/issues/710), [#741](https://github.com/terrastruct/d2/issues/741)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
.Nm d2
|
||||
.Ar layout Op Ar name
|
||||
.Nm d2
|
||||
.Ar fmt Ar file.d2
|
||||
.Ar fmt Ar file.d2 ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
compiles and renders
|
||||
|
|
@ -83,10 +83,8 @@ Print version information and exit.
|
|||
Lists available layout engine options with short help.
|
||||
.It Ar layout Op Ar name
|
||||
Display long help for a particular layout engine, including its configuration options.
|
||||
.It Ar fmt Ar file.d2
|
||||
Format
|
||||
.Ar file.d2
|
||||
.Ns .
|
||||
.It Ar fmt Ar file.d2 ...
|
||||
Format all passed files.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr d2plugin-tala 1
|
||||
|
|
|
|||
|
|
@ -1074,6 +1074,12 @@ func appendTextDedup(texts []*d2target.MText, t *d2target.MText) []*d2target.MTe
|
|||
}
|
||||
|
||||
func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) error {
|
||||
if ruler != nil && fontFamily != nil {
|
||||
if ok := ruler.HasFontFamilyLoaded(fontFamily); !ok {
|
||||
return fmt.Errorf("ruler does not have entire font family %s loaded, is a style missing?", *fontFamily)
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range g.Objects {
|
||||
obj.Box = &geo.Box{}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,3 +97,12 @@ func (e *Edge) ContainedBy(obj *Object) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Edge) GetGroup() *Object {
|
||||
for _, ref := range e.References {
|
||||
if ref.ScopeObj.IsSequenceDiagramGroup() {
|
||||
return ref.ScopeObj
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -451,6 +451,8 @@ func (sd *sequenceDiagram) placeSpans() {
|
|||
// routeMessages routes horizontal edges (messages) from Src to Dst lifeline (actor/span center)
|
||||
// in another step, routes are adjusted to spans borders when necessary
|
||||
func (sd *sequenceDiagram) routeMessages() error {
|
||||
var prevIsLoop bool
|
||||
var prevGroup *d2graph.Object
|
||||
messageOffset := sd.maxActorHeight + sd.yStep
|
||||
for _, message := range sd.messages {
|
||||
message.ZIndex = MESSAGE_Z_INDEX
|
||||
|
|
@ -460,6 +462,14 @@ func (sd *sequenceDiagram) routeMessages() error {
|
|||
noteOffset += note.Height + sd.yStep
|
||||
}
|
||||
}
|
||||
|
||||
// we need extra space if the previous message is a loop in a different group
|
||||
group := message.GetGroup()
|
||||
if prevIsLoop && prevGroup != group {
|
||||
messageOffset += MIN_MESSAGE_DISTANCE
|
||||
}
|
||||
prevGroup = group
|
||||
|
||||
startY := messageOffset + noteOffset
|
||||
|
||||
var startX, endX float64
|
||||
|
|
@ -496,11 +506,13 @@ func (sd *sequenceDiagram) routeMessages() error {
|
|||
geo.NewPoint(midX, endY),
|
||||
geo.NewPoint(endX, endY),
|
||||
}
|
||||
prevIsLoop = true
|
||||
} else {
|
||||
message.Route = []*geo.Point{
|
||||
geo.NewPoint(startX, startY),
|
||||
geo.NewPoint(endX, startY),
|
||||
}
|
||||
prevIsLoop = false
|
||||
}
|
||||
messageOffset += sd.yStep
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,12 @@ var sourceSansProItalicBase64 string
|
|||
//go:embed encoded/SourceCodePro-Regular.txt
|
||||
var sourceCodeProRegularBase64 string
|
||||
|
||||
//go:embed encoded/SourceCodePro-Bold.txt
|
||||
var sourceCodeProBoldBase64 string
|
||||
|
||||
//go:embed encoded/SourceCodePro-Italic.txt
|
||||
var sourceCodeProItalicBase64 string
|
||||
|
||||
//go:embed encoded/ArchitectsDaughter-Regular.txt
|
||||
var architectsDaughterRegularBase64 string
|
||||
|
||||
|
|
@ -108,6 +114,14 @@ func init() {
|
|||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_REGULAR,
|
||||
}: sourceCodeProRegularBase64,
|
||||
{
|
||||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_BOLD,
|
||||
}: sourceCodeProBoldBase64,
|
||||
{
|
||||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_ITALIC,
|
||||
}: sourceCodeProItalicBase64,
|
||||
{
|
||||
Family: HandDrawn,
|
||||
Style: FONT_STYLE_REGULAR,
|
||||
|
|
@ -144,6 +158,22 @@ func init() {
|
|||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_REGULAR,
|
||||
}] = b
|
||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
FontFaces[Font{
|
||||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_BOLD,
|
||||
}] = b
|
||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
FontFaces[Font{
|
||||
Family: SourceCodePro,
|
||||
Style: FONT_STYLE_ITALIC,
|
||||
}] = b
|
||||
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
|||
1
d2renderers/d2fonts/encoded/SourceCodePro-Bold.txt
Normal file
1
d2renderers/d2fonts/encoded/SourceCodePro-Italic.txt
Normal file
BIN
d2renderers/d2fonts/ttf/SourceCodePro-Bold.ttf
Normal file
BIN
d2renderers/d2fonts/ttf/SourceCodePro-Italic.ttf
Normal file
|
|
@ -47,7 +47,8 @@ func styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
return styles[tt]
|
||||
out := strings.Replace(styles[tt], `font-weight="bold"`, `class="text-mono-bold"`, -1)
|
||||
return strings.Replace(out, `font-style="italic"`, `class="text-mono-italic"`, -1)
|
||||
}
|
||||
|
||||
// <<< END
|
||||
|
|
|
|||
|
|
@ -1185,6 +1185,44 @@ func embedFonts(buf *bytes.Buffer, fontFamily *d2fonts.FontFamily) {
|
|||
}
|
||||
}
|
||||
|
||||
triggers = []string{
|
||||
`class="text-mono-bold"`,
|
||||
}
|
||||
|
||||
for _, t := range triggers {
|
||||
if strings.Contains(content, t) {
|
||||
fmt.Fprintf(buf, `
|
||||
.text-mono-bold {
|
||||
font-family: "font-mono-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: font-mono-bold;
|
||||
src: url("%s");
|
||||
}`,
|
||||
d2fonts.FontEncodings[d2fonts.SourceCodePro.Font(0, d2fonts.FONT_STYLE_BOLD)])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
triggers = []string{
|
||||
`class="text-mono-italic"`,
|
||||
}
|
||||
|
||||
for _, t := range triggers {
|
||||
if strings.Contains(content, t) {
|
||||
fmt.Fprintf(buf, `
|
||||
.text-mono-italic {
|
||||
font-family: "font-mono-italic";
|
||||
}
|
||||
@font-face {
|
||||
font-family: font-mono-italic;
|
||||
src: url("%s");
|
||||
}`,
|
||||
d2fonts.FontEncodings[d2fonts.SourceCodePro.Font(0, d2fonts.FONT_STYLE_ITALIC)])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(`]]></style>`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -394,6 +394,56 @@ x -> a: {
|
|||
label: You don't have to know how the computer works,\njust how to work the computer.
|
||||
style.opacity: 0.4
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "sequence_diagram_self_edge_group_overlap",
|
||||
script: `
|
||||
shape: sequence_diagram
|
||||
a: A
|
||||
b: B
|
||||
c: C
|
||||
group 1: {
|
||||
a -> a
|
||||
}
|
||||
group 2: {
|
||||
a -> b
|
||||
}
|
||||
group 3: {
|
||||
a -> a.a
|
||||
}
|
||||
group 4: {
|
||||
a.a -> b
|
||||
}
|
||||
group 5: {
|
||||
b -> b
|
||||
b -> b
|
||||
}
|
||||
group 6: {
|
||||
b -> a
|
||||
}
|
||||
group 7: {
|
||||
a -> a
|
||||
}
|
||||
group 8: {
|
||||
a -> a
|
||||
}
|
||||
a -> a
|
||||
group 9: {
|
||||
a -> a
|
||||
}
|
||||
a -> a
|
||||
|
||||
b -> c
|
||||
group 10: {
|
||||
c -> c
|
||||
}
|
||||
b -> c
|
||||
group 11: {
|
||||
c -> c
|
||||
}
|
||||
b -> c
|
||||
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 350 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 350 KiB |
1490
e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/board.exp.json
generated
vendored
Normal file
62
e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/sketch.exp.svg
vendored
Normal file
|
After Width: | Height: | Size: 336 KiB |
1490
e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/elk/board.exp.json
generated
vendored
Normal file
62
e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/elk/sketch.exp.svg
vendored
Normal file
|
After Width: | Height: | Size: 336 KiB |
|
Before Width: | Height: | Size: 512 KiB After Width: | Height: | Size: 601 KiB |
|
Before Width: | Height: | Size: 512 KiB After Width: | Height: | Size: 601 KiB |
|
Before Width: | Height: | Size: 508 KiB After Width: | Height: | Size: 673 KiB |
|
Before Width: | Height: | Size: 508 KiB After Width: | Height: | Size: 673 KiB |
|
Before Width: | Height: | Size: 668 KiB After Width: | Height: | Size: 757 KiB |
|
Before Width: | Height: | Size: 668 KiB After Width: | Height: | Size: 757 KiB |
|
Before Width: | Height: | Size: 513 KiB After Width: | Height: | Size: 602 KiB |
|
Before Width: | Height: | Size: 513 KiB After Width: | Height: | Size: 602 KiB |
|
Before Width: | Height: | Size: 513 KiB After Width: | Height: | Size: 602 KiB |
|
Before Width: | Height: | Size: 513 KiB After Width: | Height: | Size: 602 KiB |
|
Before Width: | Height: | Size: 842 KiB After Width: | Height: | Size: 931 KiB |
|
Before Width: | Height: | Size: 842 KiB After Width: | Height: | Size: 931 KiB |
30
fmt.go
|
|
@ -17,26 +17,24 @@ func fmtCmd(ctx context.Context, ms *xmain.State) (err error) {
|
|||
|
||||
ms.Opts = xmain.NewOpts(ms.Env, ms.Log, ms.Opts.Flags.Args()[1:])
|
||||
if len(ms.Opts.Args) == 0 {
|
||||
return xmain.UsageErrorf("fmt must be passed the file to be formatted")
|
||||
} else if len(ms.Opts.Args) > 1 {
|
||||
return xmain.UsageErrorf("fmt accepts only one argument for the file to be formatted")
|
||||
return xmain.UsageErrorf("fmt must be passed at least one file to be formatted")
|
||||
}
|
||||
|
||||
inputPath := ms.Opts.Args[0]
|
||||
input, err := ms.ReadPath(inputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, inputPath := range ms.Opts.Args {
|
||||
input, err := ms.ReadPath(inputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := d2parser.Parse(inputPath, bytes.NewReader(input), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := d2parser.Parse(inputPath, bytes.NewReader(input), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output := []byte(d2format.Format(m))
|
||||
if !bytes.Equal(output, input) {
|
||||
return ms.WritePath(inputPath, output)
|
||||
output := []byte(d2format.Format(m))
|
||||
if !bytes.Equal(output, input) {
|
||||
return ms.WritePath(inputPath, output)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
4
help.go
|
|
@ -18,7 +18,7 @@ func help(ms *xmain.State) {
|
|||
fmt.Fprintf(ms.Stdout, `Usage:
|
||||
%[1]s [--watch=false] [--theme=0] file.d2 [file.svg | file.png]
|
||||
%[1]s layout [name]
|
||||
%[1]s fmt file.d2
|
||||
%[1]s fmt file.d2 ...
|
||||
|
||||
%[1]s compiles and renders file.d2 to file.svg | file.png
|
||||
It defaults to file.svg if an output path is not provided.
|
||||
|
|
@ -33,7 +33,7 @@ Flags:
|
|||
Subcommands:
|
||||
%[1]s layout - Lists available layout engine options with short help
|
||||
%[1]s layout [name] - Display long help for a particular layout engine, including its configuration options
|
||||
%[1]s fmt file.d2 - Format file.d2
|
||||
%[1]s fmt file.d2 ... - Format passed files
|
||||
|
||||
See more docs and the source code at https://oss.terrastruct.com/d2
|
||||
`, filepath.Base(ms.Name), ms.Opts.Defaults())
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
)
|
||||
|
||||
const TAB_SIZE = 4
|
||||
const SIZELESS_FONT_SIZE = 0
|
||||
|
||||
// ASCII is a set of all ASCII runes. These runes are codepoints from 32 to 127 inclusive.
|
||||
var ASCII []rune
|
||||
|
|
@ -135,9 +136,25 @@ func NewRuler() (*Ruler, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
func (r *Ruler) HasFontFamilyLoaded(fontFamily *d2fonts.FontFamily) bool {
|
||||
for _, fontStyle := range d2fonts.FontStyles {
|
||||
font := d2fonts.Font{
|
||||
Family: *fontFamily,
|
||||
Style: fontStyle,
|
||||
Size: SIZELESS_FONT_SIZE,
|
||||
}
|
||||
_, ok := r.ttfs[font]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *Ruler) addFontSize(font d2fonts.Font) {
|
||||
sizeless := font
|
||||
sizeless.Size = 0
|
||||
sizeless.Size = SIZELESS_FONT_SIZE
|
||||
face := truetype.NewFace(r.ttfs[sizeless], &truetype.Options{
|
||||
Size: float64(font.Size),
|
||||
})
|
||||
|
|
|
|||