-
Notifications
You must be signed in to change notification settings - Fork 0
/
mantra.in
executable file
·143 lines (125 loc) · 4.26 KB
/
mantra.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#! /bin/sh -
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020-2021 Mateusz Piotrowski <0mp@FreeBSD.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
set -eu
err() {
local rc
rc="$1"
shift
printf 'ERROR: %s\n' "$*"
exit "$rc"
}
require() {
local cmd
cmd="$1"
if ! command -v -- "$cmd" >/dev/null; then
err 127 "Missing a dependency: $cmd"
fi
}
clean_up() {
# Kill any children of the parent process. Specifially, we want to kill
# the entr background job.
pkill -P $$
# Clean up temporary files.
rm -f -- "$generatedpage"
}
##
program="${0##*/}"
version="%%VERSION%%"
##
OPTIND=1
while getopts hv opt; do
case "$opt" in
h)
cat << USAGE
Usage: $program [-hv] file
Flags:
-h Show help message.
-v Show version.
Environment:
MANPAGER Pager to use. Overrides PAGER.
PAGER Pager to use. Default: "less -s".
TMPDIR
TMUX mantra must run in a tmux(1) session.
XDG_RUNTIME_DIR
USAGE
exit 0
;;
v)
printf '%s\n' "$version"
exit 0
;;
?)
exit 1
;;
esac
done
trap clean_up EXIT
require entr
require mandoc
require tmux
# Refuse to run outside of a tmux session.
if [ -z "${TMUX:-}" ]; then
err 1 "TMUX environment variable is empty, aborting; $program works correctly only when executed from within a tmux session"
fi
# Try to use XDG_RUNTIME_DIR as a TMPDIR if available. Otherwise, use TMPDIR if
# set. Default to /tmp if needed.
TMPDIR="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}"
if generatedpage="$(mktemp)"; then
chmod 600 "$generatedpage"
else
err 1 "Failed to create a temporary file"
fi
# Open the manual page passed as an argument. Otherwise, find a manual page in
# the current directory (files ending with a dot and a single digit).
if [ $# -gt 0 ]; then
manpage="$1"
elif manpage="$(find . -maxdepth 1 -type f -name '*.[0-9]' -print -quit)" \
&& [ -z "$manpage" ]; then
err 1 "No manual pages in the current directory to default to"
fi
# Pregenerate the manual page so that there is something to display
# to the user.
script -q "$generatedpage" mandoc -- "$manpage" >/dev/null
# Use entr to regenerate the manual page on each source code change. The -n
# flag makes sure that entr does not try to take over the TTY. -p makes entr
# wait for the first change before running the command specified via -s.
# script(1) is used instead of a simple shell redirection in order to make
# mandoc(1) think that it outputs into a TTY. Once the new manual page is
# generated, tmux sends "R" (a command which causes less(1) to redraw its
# buffer) to the tmux pane containing the pager.
printf "%s\n" "$manpage" | \
entr -n -p -s "
script -q \"$generatedpage\" mandoc -- \"$manpage\" \
&& tmux send-keys -t \"${TMUX_PANE}\" R
" >/dev/null 2>&1 &
# Open the genenerated manual page with a pager. Try to honor user's
# environment. It is not possible to just open the manual page with man(1) here
# because some man(1) implementations (e.g., the FreeBSD one) pipe the
# generated manual page into a pager. As a result, the page has no way to read
# the generated manual page again if it changes.
${MANPAGER:-${PAGER:-less -s}} -- "$generatedpage"