From 9516939c7deb85a660819edd1fc9b9571f1a35aa Mon Sep 17 00:00:00 2001 From: Johan Fagerberg Date: Tue, 3 Mar 2026 14:19:57 +0100 Subject: [PATCH] feat: add support for --content-appearance --- README.md | 1 + main.go | 2 +- metadata/metadata.go | 18 ++++++++++++------ metadata/metadata_test.go | 29 +++++++++++++++++++++++++++++ page/link.go | 2 +- util/cli.go | 2 +- util/cli_test.go | 26 +++++++++++++++++++++++++- util/flags.go | 28 ++++++++++++++++++++++++++-- 8 files changed, 96 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e9ff468..911e274 100644 --- a/README.md +++ b/README.md @@ -838,6 +838,7 @@ GLOBAL OPTIONS: --space string use specified space key. If the space key is not specified, it must be set in the page metadata. [$MARK_SPACE] --parents string A list containing the parents of the document separated by parents-delimiter (default: '/'). These will be prepended to the ones defined in the document itself. [$MARK_PARENTS] --parents-delimiter string The delimiter used for the parents list (default: "/") [$MARK_PARENTS_DELIMITER] + --content-appearance string default content appearance for pages without a Content-Appearance header. Possible values: full-width, fixed. [$MARK_CONTENT_APPEARANCE] --mermaid-scale float defines the scaling factor for mermaid renderings. (default: 1) [$MARK_MERMAID_SCALE] --include-path string Path for shared includes, used as a fallback if the include doesn't exist in the current directory. [$MARK_INCLUDE_PATH] --changes-only Avoids re-uploading pages that haven't changed since the last run. [$MARK_CHANGES_ONLY] diff --git a/main.go b/main.go index 5967b6c..1c4d5e5 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,7 @@ func main() { Flags: util.Flags, EnableShellCompletion: true, HideHelpCommand: true, - Before: util.CheckMutuallyExclusiveTitleFlags, + Before: util.CheckFlags, Action: util.RunMark, } diff --git a/metadata/metadata.go b/metadata/metadata.go index 7eeced6..b70edb1 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -51,7 +51,7 @@ var ( reHeaderPatternMacro = regexp.MustCompile(`\n\n\nbody\n") + + meta, _, err := ExtractMeta(data, "", false, false, "", nil, false, FixedContentAppearance) + assert.NoError(t, err) + assert.NotNil(t, meta) + assert.Equal(t, FixedContentAppearance, meta.ContentAppearance) + }) + + t.Run("header takes precedence over default", func(t *testing.T) { + data := []byte("\n\n\n\nbody\n") + + meta, _, err := ExtractMeta(data, "", false, false, "", nil, false, FixedContentAppearance) + assert.NoError(t, err) + assert.NotNil(t, meta) + assert.Equal(t, FullWidthContentAppearance, meta.ContentAppearance) + }) + + t.Run("falls back to full-width when default isn't set", func(t *testing.T) { + data := []byte("\n\n\nbody\n") + + meta, _, err := ExtractMeta(data, "", false, false, "", nil, false, "") + assert.NoError(t, err) + assert.NotNil(t, meta) + assert.Equal(t, FullWidthContentAppearance, meta.ContentAppearance) + }) +} diff --git a/page/link.go b/page/link.go index c4ceab2..0035a8f 100644 --- a/page/link.go +++ b/page/link.go @@ -122,7 +122,7 @@ func resolveLink( // This helps to determine if found link points to file that's // not markdown or have mark required metadata - linkMeta, _, err := metadata.ExtractMeta(linkContents, spaceForLinks, titleFromH1, titleFromFilename, filepath, parents, titleAppendGeneratedHash) + linkMeta, _, err := metadata.ExtractMeta(linkContents, spaceForLinks, titleFromH1, titleFromFilename, filepath, parents, titleAppendGeneratedHash, "") if err != nil { log.Errorf( err, diff --git a/util/cli.go b/util/cli.go index 55e1a86..d90cd79 100644 --- a/util/cli.go +++ b/util/cli.go @@ -116,7 +116,7 @@ func processFile( parents := strings.Split(cmd.String("parents"), cmd.String("parents-delimiter")) - meta, markdown, err := metadata.ExtractMeta(markdown, cmd.String("space"), cmd.Bool("title-from-h1"), cmd.Bool("title-from-filename"), file, parents, cmd.Bool("title-append-generated-hash")) + meta, markdown, err := metadata.ExtractMeta(markdown, cmd.String("space"), cmd.Bool("title-from-h1"), cmd.Bool("title-from-filename"), file, parents, cmd.Bool("title-append-generated-hash"), cmd.String("content-appearance")) if err != nil { fatalErrorHandler.Handle(err, "unable to extract metadata from file %q", file) return nil diff --git a/util/cli_test.go b/util/cli_test.go index 2f2ea9f..cf5a8d0 100644 --- a/util/cli_test.go +++ b/util/cli_test.go @@ -12,8 +12,9 @@ func runWithArgs(args []string) error { Flags: []cli.Flag{ &cli.BoolFlag{Name: "title-from-h1"}, &cli.BoolFlag{Name: "title-from-filename"}, + &cli.StringFlag{Name: "content-appearance"}, }, - Before: CheckMutuallyExclusiveTitleFlags, + Before: CheckFlags, Action: func(ctx context.Context, cmd *cli.Command) error { return nil }, @@ -50,3 +51,26 @@ func TestCheckMutuallyExclusiveTitleFlags(t *testing.T) { } }) } + +func TestContentAppearanceFlagValidation(t *testing.T) { + t.Run("fixed is accepted", func(t *testing.T) { + err := runWithArgs([]string{"cmd", "--content-appearance", "fixed"}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + + t.Run("full-width is accepted", func(t *testing.T) { + err := runWithArgs([]string{"cmd", "--content-appearance", "full-width"}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + + t.Run("invalid value is rejected", func(t *testing.T) { + err := runWithArgs([]string{"cmd", "--content-appearance", "nope"}) + if err == nil { + t.Errorf("expected error, got nil") + } + }) +} diff --git a/util/flags.go b/util/flags.go index c10a7cc..0d41f92 100644 --- a/util/flags.go +++ b/util/flags.go @@ -3,6 +3,7 @@ package util import ( "context" "errors" + "fmt" altsrc "github.com/urfave/cli-altsrc/v3" altsrctoml "github.com/urfave/cli-altsrc/v3/toml" @@ -164,6 +165,15 @@ var Flags = []cli.Flag{ Usage: "The delimiter used for the parents list", Sources: cli.NewValueSourceChain(cli.EnvVar("MARK_PARENTS_DELIMITER"), altsrctoml.TOML("parents-delimiter", altsrc.NewStringPtrSourcer(&filename))), }, + &cli.StringFlag{ + Name: "content-appearance", + Value: "", + Usage: "default content appearance for pages without a Content-Appearance header. Possible values: full-width, fixed.", + Sources: cli.NewValueSourceChain( + cli.EnvVar("MARK_CONTENT_APPEARANCE"), + altsrctoml.TOML("content-appearance", altsrc.NewStringPtrSourcer(&filename)), + ), + }, &cli.FloatFlag{ Name: "mermaid-scale", Value: 1.0, @@ -204,10 +214,24 @@ var Flags = []cli.Flag{ }, } -// CheckMutuallyExclusiveTitleFlags checks if both title-from-h1 and title-from-filename are set -func CheckMutuallyExclusiveTitleFlags(context context.Context, command *cli.Command) (context.Context, error) { +// CheckFlags validates combinations and values of global flags. +func CheckFlags(context context.Context, command *cli.Command) (context.Context, error) { if command.Bool("title-from-h1") && command.Bool("title-from-filename") { return context, errors.New("flags --title-from-h1 and --title-from-filename are mutually exclusive. Please specify only one") } + + contentAppearance := command.String("content-appearance") + if contentAppearance != "" { + switch contentAppearance { + case "full-width", "fixed": + // ok + default: + return context, fmt.Errorf( + "invalid value for --content-appearance: %q (expected: full-width or fixed)", + contentAppearance, + ) + } + } + return context, nil }