mdreplace
mdreplace is a tool to help you keep your markdown README/documentation current.
go get -u myitcv.io/cmd/mdreplace
(will soon be available as a vgo
module)
A common problem with non .go
documentation files is that their contents can easily become stale. For example with a
program it's common to include a "Help" section in the corresponding README.md
which typically involves a discussion
of the program's flags. The contents of the README.md
can, however, easily fall out of step with respect to the
actual flags were we to run our program with -h
(or equivalent) today.
mdreplace
helps alleviate these problems by allowing you to insert special comment blocks in your markdown files that
are replaced with command output.
For example, were we to include the following special comment block:
<!-- __TEMPLATE: echo -n "hello world" today
{{.Out -}}
-->
<!-- END -->
results in:
hello world today
To see this in action, look at the source of the
README.md
you are currently reading.
Usage
Usage:
mdreplace file1 file2 ...
mdreplace
When called with no file arguments, mdreplace works with stdin
Flags:
-debug
whether to print debug information of not
-long
run LONG blocks
-online
run ONLINE blocks
-strip
whether to strip special comments from the file
-w whether to write back to input files (cannot be used when reading from
stdin)
Code fences
Code fences can appear within templates. Hence the following special template within a markdown file:
<!-- __TEMPLATE: echo -n "hello world"
```go
package main
import "fmt"
func main() {
fmt.Println("{{.Out}}")
}
```
-->
<!-- END -->
results in:
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
The only place that special comment blocks are not interpreted by mdreplace
is within code blocks. Hence how we are
able to render the example special code blocks in this README.
Note it is not possible to nest code fences.
JSON blocks
The __JSON
block is used where the output from the command is valid JSON. This JSON is then unmarshalled and passed as
an argument to the template block. For example:
<!-- __JSON: go list -json encoding/json
Package `{{.Out.ImportPath}}` has name `{{.Out.Name}}` and the following doc string:
```
{{.Out.Doc}}
```
-->
<!-- END -->
results in :
Package encoding/json
has name json
and the following doc string:
Package json implements encoding and decoding of JSON as defined in RFC 7159.
Variable expansion
Variable expansion also works; use the special $DOLLAR
variable to expand to the literal $
sign:
<!-- __TEMPLATE: sh -c "BANANA=fruit; echo -n \"${DOLLAR}BANANA\""
{{.Out}}
-->
<!-- END -->
results in :
fruit
Template functions
Both the __TEMPLATE
and __JSON
blocks support the following template functions:
lines(string) []string
- split a string into lines
lineEllipsis(s string, n int) string)
- output at most n
lines from s
, adding ellipsis if required
trimLinePrefixWhitespace(s string, m string) string
- remove lines from s
, upto and including the line
matching m
, as well as any blank lines that follow m
- ... more to follow
TODO: move these to be an internal package that can then be automatically documented.
Implementation
This rather basic program is an implementation of the techniques proposed by Rob Pike in
his brilliant presentation Lexical Scanning in Go
(slides).