Executable Markdown cheatsheets. Write readable docs, run interactive commands.
go install github.com/gubarz/cheatmd/cmd/cheatmd@latestcheatmd # Browse current directory
cheatmd ~/cheats # Browse specific directory
cheatmd -q "docker" # Start with search queryeval "$(cheatmd widget bash)" # Add to ~/.bashrc
eval "$(cheatmd widget zsh)" # Add to ~/.zshrcPress Ctrl+G to open the selector. The chosen command is inserted into your
shell prompt; press Enter again to run it. Change the trigger key by setting
key_widget: "\\C-g" (or any readline keyspec) in your config.
Add to ~/.tmux.conf:
bind-key -n C-n split-window "$SHELL --login -i -c 'cheatmd --print | tr -d \"\\r\\n\" | tmux load-buffer -b tmp - ; tmux paste-buffer -t {last} -b tmp -d'"Press Ctrl+n to open cheatmd in a split; the chosen command is pasted into
the previous pane.
Add to your Zellij config:
bind "Ctrl n" {
Run "sh" "-c" "content=$(cheatmd --print); zellij action toggle-floating-panes; zellij action write-chars \"$content\"" {
floating true
close_on_exit true
};
}Press Ctrl+n to open cheatmd in a floating pane.
## Docker: list containers
` ` `sh title:"Show all running containers"
docker ps
` ` `## Docker: exec into container
` ` `sh title:"Execute shell in container"
docker exec -it $container /bin/sh
` ` `
<!-- cheat
var container = docker ps --format "{{.Names}}" --- --header "Select container"
-->Variables are populated from shell command output:
- 0 lines → manual input prompt
- 1 line → pre-filled, confirm with Enter
- 2+ lines → selection list
By default only $name is recognized as a variable reference and undeclared
references are silently skipped. Two config knobs relax that:
var_syntax: which variable syntax cheatmd recognizes in commands.dollar(default): only$nameangle: only<name>both: accept both, mixed in one command resolves to the same variable
allow_undeclared_vars: true: prompt for any referenced variable that has no<!-- cheat -->declaration, instead of skipping it.
With var_syntax: both and allow_undeclared_vars: true, this cheat works
with no metadata block:
## SSH
` ` `sh title:"SSH to a host"
ssh $user@<host> -p $port
` ` `The user is prompted for user, host, and port in order. Strict defaults
are kept so existing cheats stay backwards compatible.
Export reusable variables:
<!-- cheat
export docker_container
var container = docker ps --format "{{.Names}}" --- --header "Select container"
-->Import them elsewhere:
## Docker: view logs
` ` `sh title:"Follow container logs"
docker logs -f $container
` ` `
<!-- cheat
import docker_container
-->~/.config/cheatmd/cheatmd.yaml:
path: ~/cheats
output: print # print, copy, exec
shell: /bin/bash
require_cheat_block: false
auto_continue: false # Auto-accept env vars without prompting
# Substitute search (while resolving a variable, press Ctrl-T to fuzzy-search
# environment variables and shell history for a value to insert)
key_substitute: "ctrl+t"
substitute_sources: ["env", "history"] # set to [] to disableWhen a cheat asks for a variable (say $host), press Ctrl-T to open a
fuzzy-search picker over your environment variables and any assignments
(VAR=value, export VAR=value, declare -x VAR=value, leading inline
assignments) found in shell history. Plain commands in history are ignored.
Pick a row, its value is loaded into the prompt; press Enter to accept or
edit it first. Esc cancels back to the var prompt. History is read from
$HISTFILE, falling back to ~/.bash_history or ~/.zsh_history.
var <name> # Prompt user for a value
var <name> = <shell> # Populate from shell output
var <name> = <shell> --- <opts> # With selector options (see below)
var <name> := <value> # Literal value (with $var substitution)
export <name> # Make module importable
import <name> # Use an exported module
if $var == value # Conditional block (any var form works inside)
var <name> := <value>
fi
--- --header "..." works on both = and :=. Lines beginning with # inside
a <!-- cheat --> block are comments.
--header "Title" # Picker header text
--delimiter "\t" # Split lines by delimiter
--column 2 # Show this column in the picker
--select-column 1 # Return this column as the value
--map "cmd" # Pipe selected value through a shell command
Full reference: docs/dsl.md. Patterns and copy-pasteable examples: docs/recipes.md.
Cheats are searchable by tag. Tags can come from five places: the folder/file
path, YAML front matter, a hashtag or YAML block at the end of the file, an
inline #tag in prose under a cheat, or the heading itself.
---
tags: [aws, cloud]
---
# AWS
## list buckets
#s3
\`\`\`sh title:"List S3 buckets"
aws s3 ls
\`\`\`
---
#quickref #productionTags are merged, lowercased, and folded into the regular search index; type any of them in the picker. Full details: docs/tags.md.
MIT
