d2/d2cli/help.go

166 lines
4.4 KiB
Go
Raw Permalink Normal View History

package d2cli
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
2022-12-01 19:19:39 +00:00
"oss.terrastruct.com/util-go/xmain"
"oss.terrastruct.com/d2/d2plugin"
2023-02-05 08:34:43 +00:00
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
2023-06-12 08:18:45 +00:00
"oss.terrastruct.com/d2/lib/version"
)
func help(ms *xmain.State) {
2023-06-12 08:18:45 +00:00
fmt.Fprintf(ms.Stdout, `%[1]s %[2]s
Usage:
%[1]s [--watch=false] [--theme=0] file.d2 [file.svg | file.png]
%[1]s layout [name]
%[1]s fmt file.d2 ...
2024-12-11 01:04:27 +00:00
%[1]s play [--theme=0] [--sketch] file.d2
2025-03-10 17:22:51 +00:00
%[1]s validate file.d2
2022-11-30 11:01:13 +00:00
%[1]s compiles and renders file.d2 to file.svg | file.png
It defaults to file.svg if an output path is not provided.
Use - to have d2 read from stdin or write to stdout.
2022-12-01 05:14:38 +00:00
See man d2 for more detailed docs.
2022-11-30 11:01:13 +00:00
Flags:
2023-06-12 08:18:45 +00:00
%[3]s
Subcommands:
%[1]s layout - Lists available layout engine options with short help
2022-12-30 21:22:45 +00:00
%[1]s layout [name] - Display long help for a particular layout engine, including its configuration options
2023-02-05 08:34:43 +00:00
%[1]s themes - Lists available themes
%[1]s fmt file.d2 ... - Format passed files
2025-02-04 13:40:08 +00:00
%[1]s play file.d2 - Opens the file in playground, an online web viewer (https://play.d2lang.com)
2025-03-10 19:18:43 +00:00
%[1]s validate file.d2 - Validates file.d2
2023-02-05 08:19:14 +00:00
See more docs and the source code at https://oss.terrastruct.com/d2.
Hosted icons at https://icons.terrastruct.com.
Playground runner at https://play.d2lang.com.
2023-06-12 08:18:45 +00:00
`, filepath.Base(ms.Name), version.Version, ms.Opts.Defaults())
}
func layoutCmd(ctx context.Context, ms *xmain.State, ps []d2plugin.Plugin) error {
2022-11-17 00:48:19 +00:00
if len(ms.Opts.Flags.Args()) == 1 {
return shortLayoutHelp(ctx, ms, ps)
2022-11-17 00:48:19 +00:00
} else if len(ms.Opts.Flags.Args()) == 2 {
return longLayoutHelp(ctx, ms, ps)
} else {
return pluginSubcommand(ctx, ms, ps)
}
}
func themesCmd(_ context.Context, ms *xmain.State) {
2023-02-05 08:34:43 +00:00
fmt.Fprintf(ms.Stdout, "Available themes:\n%s", d2themescatalog.CLIString())
}
func shortLayoutHelp(ctx context.Context, ms *xmain.State, ps []d2plugin.Plugin) error {
var pluginLines []string
pinfos, err := d2plugin.ListPluginInfos(ctx, ps)
if err != nil {
return err
}
for _, p := range pinfos {
var l string
if p.Type == "bundled" {
l = fmt.Sprintf("%s (bundled) - %s", p.Name, p.ShortHelp)
} else {
l = fmt.Sprintf("%s (%s) - %s", p.Name, humanPath(p.Path), p.ShortHelp)
}
pluginLines = append(pluginLines, l)
}
fmt.Fprintf(ms.Stdout, `Available layout engines found:
%s
Usage:
2022-11-15 00:35:22 +00:00
To use a particular layout engine, set the environment variable D2_LAYOUT=[name] or flag --layout=[name].
Example:
D2_LAYOUT=dagre d2 in.d2 out.svg
Subcommands:
2022-12-30 21:22:45 +00:00
%s layout [layout name] - Display long help for a particular layout engine, including its configuration options
2023-02-05 08:41:00 +00:00
See more docs at https://d2lang.com/tour/layouts
`, strings.Join(pluginLines, "\n"), ms.Name)
return nil
}
func longLayoutHelp(ctx context.Context, ms *xmain.State, ps []d2plugin.Plugin) error {
2022-11-17 00:48:19 +00:00
layout := ms.Opts.Flags.Arg(1)
plugin, err := d2plugin.FindPlugin(ctx, ps, layout)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
return layoutNotFound(ctx, ps, layout)
}
return err
}
pinfo, err := plugin.Info(ctx)
if err != nil {
return err
}
plocation := pinfo.Type
if pinfo.Type == "binary" {
plocation = fmt.Sprintf("executable plugin at %s", humanPath(pinfo.Path))
}
if !strings.HasSuffix(pinfo.LongHelp, "\n") {
pinfo.LongHelp += "\n"
}
fmt.Fprintf(ms.Stdout, `%s (%s):
%s`, pinfo.Name, plocation, pinfo.LongHelp)
return nil
}
func layoutNotFound(ctx context.Context, ps []d2plugin.Plugin, layout string) error {
pinfos, err := d2plugin.ListPluginInfos(ctx, ps)
if err != nil {
return err
}
var names []string
for _, p := range pinfos {
names = append(names, p.Name)
}
return xmain.UsageErrorf(`D2_LAYOUT "%s" is not bundled and could not be found in your $PATH.
The available options are: %s. For details on each option, run "d2 layout".
For more information on setup, please visit https://github.com/terrastruct/d2.`,
layout, strings.Join(names, ", "))
}
func pluginSubcommand(ctx context.Context, ms *xmain.State, ps []d2plugin.Plugin) error {
2022-11-17 00:48:19 +00:00
layout := ms.Opts.Flags.Arg(1)
plugin, err := d2plugin.FindPlugin(ctx, ps, layout)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
return layoutNotFound(ctx, ps, layout)
}
return err
}
2022-11-17 00:48:19 +00:00
ms.Opts.Args = ms.Opts.Flags.Args()[2:]
return d2plugin.Serve(plugin)(ctx, ms)
}
func humanPath(fp string) string {
if strings.HasPrefix(fp, os.Getenv("HOME")) {
return filepath.Join("~", strings.TrimPrefix(fp, os.Getenv("HOME")))
}
return fp
}