diff --git a/0.21.0-release-notes.md b/0.21.0-release-notes.md index 7b434319..70d234b4 100644 --- a/0.21.0-release-notes.md +++ b/0.21.0-release-notes.md @@ -3,6 +3,9 @@ - The `os` module has gained the following new commands: `mkdir-all`, `symlink` and `rename`. +- A new `md` module, currently containing a single function `md:show` for + rendering Markdown in the terminal. + # Notable bugfixes - The string comparison commands `s` and `>=s` (but not diff --git a/pkg/mods/doc/doc.d.elv b/pkg/mods/doc/doc.d.elv index 8f3f53be..eedc01b4 100644 --- a/pkg/mods/doc/doc.d.elv +++ b/pkg/mods/doc/doc.d.elv @@ -9,8 +9,13 @@ # the explicit `builtin:` namespace (like `builtin:put`). # # The `&width` option specifies the width to wrap the output to. If it is 0 (the -# default) or negative, `show` queries the width of the terminal and use it as -# the width, falling back to 80 if the query fails. +# default) or negative, `show` queries the terminal width of the standard output +# and use it as the width, falling back to 80 if the query fails (for example +# when the standard output is not a terminal). +# +# This command is roughly equivalent to `md:show &width=$width (doc:show +# $symbol)`, but has some extra processing of relative links to point them to +# the Elvish website. # # Examples: # @@ -24,6 +29,8 @@ # ~> doc:show doc:show # [ omitted ] # ``` +# +# See also [`md:show`](). fn show {|symbol &width=0| } # Finds symbols whose documentation contains all strings in `$queries`. diff --git a/pkg/mods/md/md.d.elv b/pkg/mods/md/md.d.elv new file mode 100644 index 00000000..81e3a635 --- /dev/null +++ b/pkg/mods/md/md.d.elv @@ -0,0 +1,20 @@ +# Renders `$markdown` in the terminal. +# +# The `&width` option specifies the width to wrap the output to. If it is 0 (the +# default) or negative, `show` queries the terminal width of the standard output +# and use it as the width, falling back to 80 if the query fails (for example +# when the standard output is not a terminal). +# +# Examples: +# +# ```elvish-transcript +# ~> md:show "#h1 heading\n- List\n- Item" +# #h1 heading +# +# • List +# +# • Item +# ``` +# +# See also [`doc:show`](). +fn show {|&width=0| markdown} diff --git a/pkg/mods/md/md.go b/pkg/mods/md/md.go new file mode 100644 index 00000000..f325dc3e --- /dev/null +++ b/pkg/mods/md/md.go @@ -0,0 +1,37 @@ +// Package md exposes functionality from src.elv.sh/pkg/md. +package md + +import ( + "src.elv.sh/pkg/elvdoc" + "src.elv.sh/pkg/eval" + "src.elv.sh/pkg/md" + "src.elv.sh/pkg/sys" +) + +// Ns is the namespace for the md: module. +var Ns = eval.BuildNsNamed("md"). + AddGoFns(map[string]any{ + "show": show, + }).Ns() + +type showOpts struct { + Width int +} + +func (*showOpts) SetDefaultOptions() {} + +func show(fm *eval.Frame, opts showOpts, markdown string) error { + width := opts.Width + if width <= 0 { + _, width = sys.WinSize(fm.Port(1).File) + if width <= 0 { + width = 80 + } + } + codec := &md.TTYCodec{ + Width: width, + HighlightCodeBlock: elvdoc.HighlightCodeBlock, + } + _, err := fm.ByteOutput().WriteString(md.RenderString(markdown, codec)) + return err +} diff --git a/pkg/mods/md/md_test.elvts b/pkg/mods/md/md_test.elvts new file mode 100644 index 00000000..d010aaa0 --- /dev/null +++ b/pkg/mods/md/md_test.elvts @@ -0,0 +1,24 @@ +//each:eval use md + +/////////// +# md:show # +/////////// + +// Transcript tests are not run with a real terminal connected to the output, so +// the width will fall back to 80. +~> md:show 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. +~> md:show "#h1 heading\n- List\n- Item" +#h1 heading + +• List + +• Item + +## explicit &width ## +~> md:show &width=40 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' +Lorem ipsum dolor sit amet, consectetur +adipiscing elit. Sed do eiusmod tempor +incididunt ut labore et dolore magna +aliqua. diff --git a/pkg/mods/md/md_test.go b/pkg/mods/md/md_test.go new file mode 100644 index 00000000..b377089f --- /dev/null +++ b/pkg/mods/md/md_test.go @@ -0,0 +1,15 @@ +package md_test + +import ( + "embed" + "testing" + + "src.elv.sh/pkg/eval/evaltest" +) + +//go:embed *.elvts +var transcripts embed.FS + +func TestTranscripts(t *testing.T) { + evaltest.TestTranscriptsInFS(t, transcripts) +} diff --git a/pkg/mods/mods.go b/pkg/mods/mods.go index 2a4399a7..5dee7b5d 100644 --- a/pkg/mods/mods.go +++ b/pkg/mods/mods.go @@ -8,6 +8,7 @@ import ( "src.elv.sh/pkg/mods/file" "src.elv.sh/pkg/mods/flag" "src.elv.sh/pkg/mods/math" + "src.elv.sh/pkg/mods/md" "src.elv.sh/pkg/mods/os" "src.elv.sh/pkg/mods/path" "src.elv.sh/pkg/mods/platform" @@ -33,6 +34,7 @@ func AddTo(ev *eval.Evaler) { ev.AddModule("flag", flag.Ns) ev.AddModule("doc", doc.Ns) ev.AddModule("os", os.Ns) + ev.AddModule("md", md.Ns) if unix.ExposeUnixNs { ev.AddModule("unix", unix.Ns) } diff --git a/website/ref/index.toml b/website/ref/index.toml index bf8e45d1..6e9e6cb7 100644 --- a/website/ref/index.toml +++ b/website/ref/index.toml @@ -44,6 +44,10 @@ title = "file: File Utilities" name = "math" title = "math: Math Utilities" +[[articles]] +name = "md" +title = "md: Markdown Utilities" + [[articles]] name = "os" title = "os: Operating system functionality" diff --git a/website/ref/md.md b/website/ref/md.md new file mode 100644 index 00000000..59e438cb --- /dev/null +++ b/website/ref/md.md @@ -0,0 +1,14 @@ + + +@module md + +# Introduction + +The `md:` module provides utilities for working with Markdown text. + +Function usages are given in the same format as in the reference doc for the +[builtin module](builtin.html). + +This module uses a custom implementation that supports +[a large subset](https://pkg.go.dev/src.elv.sh/pkg/md#hdr-Which_Markdown_variant_does_this_package_implement_) +of CommonMark.