1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-18 12:00:31 +01:00

Website: Create script to generate the HTML version of the man pages

When running the 'make website' command, it will call groff to convert the
man pages into HTML and post-process them to get them in the style of the
site, then place them in the Website Git Repository.

Signed-off-by: Christophe CURIS <christophe.curis@free.fr>
This commit is contained in:
Christophe CURIS
2021-06-20 22:59:52 +02:00
committed by Carlos R. Mafra
parent 351e05dca9
commit a2bf67f54c
4 changed files with 362 additions and 0 deletions

View File

@@ -41,6 +41,7 @@ EXTRA_DIST = TODO BUGS BUGFORM FAQ INSTALL \
script/check-cmdline-options-doc.sh \
script/check-translation-sources.sh \
script/check-wmaker-loaddef-callbacks.sh \
script/generate-html-from-man.sh \
script/generate-mapfile-from-header.sh \
script/generate-po-from-template.sh \
script/generate-txt-from-texi.sh \

View File

@@ -27,6 +27,11 @@ MOSTLYCLEANFILES = wmaker.1 wmsetbg.1
EXTRA_DIST = wmaker.in wmsetbg.in
################################################################################
# Generation of man pages that need processing
################################################################################
wmaker.1: wmaker.in Makefile $(top_builddir)/config.h
$(AM_V_GEN)$(top_srcdir)/script/replace-ac-keywords.sh \
--header "$(top_builddir)/config.h" --filter "HAVE_INOTIFY" \
@@ -40,6 +45,11 @@ wmsetbg.1: wmsetbg.in Makefile $(top_builddir)/config.h
--header "$(top_builddir)/config.h" --filter "USE_XINERAMA" \
-o "wmsetbg.1" "$(srcdir)/wmsetbg.in"
################################################################################
# Section for checking the man pages against the program's --help text
################################################################################
# Create a 'silent rule' for our make check the same way automake does
AM_V_CHKOPTS = $(am__v_CHKOPTS_$(V))
am__v_CHKOPTS_ = $(am__v_CHKOPTS_$(AM_DEFAULT_VERBOSITY))
@@ -111,3 +121,33 @@ wxpaste-args:
.PHONY: wmaker-args WPrefs-args wmagnify-args geticonset-args getstyle-args seticons-args setstyle-args \
wdread-args wdwrite-args wmgenmenu-args wmiv-args wmmenugen-args wmsetbg-args wxcopy-args wxpaste-args
################################################################################
# Section related to generating HTML version of man pages for the website
################################################################################
if WITH_WEB_REPO
# We convert all man pages except those that are a link to other man page (.so command)
website: $(MANS) website.menu
@local_pages=`echo "$^" | sed -e 's/ [^ ]*\.menu$$// ; s,[^ /]*/,,g' `; \
for man in $^; do \
[ "$$man" = "website.menu" ] && continue; \
grep -i '^\.so[ \t]' "$$man" > /dev/null && continue; \
echo " MAN2HTML $$man"; \
$(top_srcdir)/script/generate-html-from-man.sh --groff $(GROFF) \
--output $(WEB_REPO_ROOT)/docs/manpages/`echo "$$man" | sed -e 's,[^ /]*/,,g ; s/\.[^.]*$$//' `.html \
--local-pages "$$local_pages" --external-url 'http://linux.die.net/man/%s/%l' \
--with-menu "website.menu" --package '$(PACKAGE_STRING)' \
$$man || exit $$?; \
done
MOSTLYCLEANFILES += website.menu
# This menu is the icon bar to navigate on the website, which we want to keep on all man pages
# We extract it from the Template defined for all pages of the site
website.menu: $(WEB_REPO_ROOT)/_layouts/default.html
$(AM_V_GEN)sed -n -e '/<aside>/,/<\/aside>/ { s/{{ site.baseurl }}// ; s/^ // ; p }' $< > $@
endif
.PHONY: website

View File

@@ -211,6 +211,14 @@ AC_DEFUN_ONCE([WM_CHECK_WEBREPODIR],
[AC_MSG_ERROR([The path "$WEB_REPO_ROOT" is not a GIT repository, for --with-web-repo])])
AS_IF([test ! -f "$WEB_REPO_ROOT/_config.yml"],
[AC_MSG_ERROR([The path "$WEB_REPO_ROOT" does not look like Window Maker's website repository, for --with-web-repo])])
# This is used to convert MAN pages into HTML pages
AC_CACHE_CHECK([how to convert man to html], [ac_cv_path_GROFF],
[AC_PATH_PROGS_FEATURE_CHECK([GROFF], [groff],
[echo '.TH dummy 0' | $ac_path_GROFF -man -Dutf8 -Thtml > /dev/null 2> /dev/null
test $? -eq 0 && ac_cv_path_GROFF=$ac_path_GROFF ac_path_GROFF_found=:],
[AC_MSG_ERROR([no working "groff" found -- If you have "groff-base" it is not enough for HTML support])]) ])
AC_SUBST([GROFF], [$ac_cv_path_GROFF])
])
AM_CONDITIONAL([WITH_WEB_REPO], [test "x$WEB_REPO_ROOT" != "x"])
AC_SUBST([WEB_REPO_ROOT])

313
script/generate-html-from-man.sh Executable file
View File

@@ -0,0 +1,313 @@
#!/bin/sh
###########################################################################
#
# Window Maker window manager
#
# Copyright (c) 2021 Christophe CURIS
# Copyright (c) 2021 Window Maker Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
#
# generate-html-from-man.sh:
# Convert a man page into HTML using Groff, then post-process it to make
# it fit the Window Maker site's theme and install it into the website
# Git repository.
#
# The pages are generated as xhtml because that's the most convenient
# format at current time that Groff can provide. The post-processing of the
# page includes:
#
# - the basic style sheet included by groff is replaced by a call to "manpage.css";
#
# - if a menu list is provided with "--with-menu", then it is added at the
# beginning of the <body> inside an "ul" with class="menu";
#
# - the list of sections at the beginning is enclosed in a div with class="toc";
#
# - emails addresses in the form "<name@example.com>" are obfuscated (to
# not help spambots) and a mailto: link is added;
#
# - a link is added when an url of the form "http://..." is encountered;
#
# - when a man-page reference is found, in the form "name(section)", a link
# is added, either to a local page if in the "--local-pages" list or to the
# external url provided in "--external-url";
#
# - if the package name and version is provided with "--package", then a div with
# class="footer" is added at the end of the <body>.
#
###########################################################################
#
# For portability, we stick to the same sh+awk constraint as Autotools to
# limit problems, see for example:
# http://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
#
###########################################################################
# Report an error on stderr and exit with status 2 to tell make that we could
# not do what we were asked
arg_error() {
echo "`basename $0`: $@" >&2
exit 2
}
# print help and exit with success status
print_help() {
echo "$0: convert man page into HTML"
echo "Usage: $0 options... man-page-file"
echo "valid options are:"
echo " --external-url tmpl : use tmpl as URL template for non-local man pages"
echo " --groff name : name of groff binary to use"
echo " --local-pages names : list of man pages that are available locally"
echo " --output filename : name of the HTML file to generate"
echo " --with-menu code : insert the specified code to add a navigation menu"
echo " --package name : name of package, added in the footer of page"
exit 0
}
# Sets the default values
GROFF=groff
# Extract command line arguments
while [ $# -gt 0 ]; do
case $1 in
--external-url)
shift
[ "x$external_template" = "x" ] || arg_error "only 1 template for URL can be specified (option: --external-url)"
external_template=$1
;;
--groff)
shift
GROFF=$1
;;
--local-pages)
shift
local_pages="$local_pages $1 "
;;
--output)
shift
[ -z "$output_file" ] || arg_error "only 1 target file can be specified (option: --output)"
output_file="$1"
;;
--with-menu)
shift
[ -z "$menu_line" ] || arg_error "only 1 code for the menu can be specified (option: --with-menu)"
menu_line=`echo "$1" | sed -e 's/"/\\\"/g' `
;;
--package)
shift
[ -z "$package_line" ] || arg_error "package name can be specified only once (option: --package)"
package_line="$1"
;;
-h|-help|--help) print_help ;;
-*) arg_error "unknow option '$1'" ;;
*)
[ -z "$input_file" ] || arg_error "only 1 man page can be specified"
input_file=$1
;;
esac
shift
done
# Check consistency of command-line
[ -z "$input_file" ] && arg_error "no source man page given"
[ -f "$input_file" ] || arg_error "man page \"$input_file\" cannot be read"
if [ -n "$external_template" ]; then
echo "$external_template" | grep '%[plu]' > /dev/null \
|| arg_error "no marker %p, %l or %u for the page name in the URL template (option: --external-url)"
fi
# Generate the name of the output file from the man page file name
if [ -z "$output_file" ]; then
output_file=`echo "$input_file" | sed 's,^.*/,,g ; s/\.[^.]*$//' `.html
fi
###########################################################################
# Pass the configuration to the AWK script; remove the path information
awk_init="BEGIN {
external_template = \"$external_template\";
known_pages = \" $local_pages \";
menu_code = \"$menu_line\";
package_line = \"$package_line\";
source_name = \"`basename "$input_file" `\";
}"
# This AWK script is post-processing the HTML generated by Groff
awk_process_html='
/<html>/ {
print;
$0 = "<!-- This file is generated automatically by a script, do not edit -->";
}
# Groff is generating a title with the name of the command, followed by a table of content
# We detect all this and embed it into a <div> section for presentation purpose
/<h1/ {
header = gensub(/<h1[^>]*>([^<]*)<\/h1>/, "\\1", 1);
print " <div class=\"toc\">";
print " <label for=\"toc-checkbutton\">" header "</label>";
print " <input type=\"checkbox\" id=\"toc-checkbutton\" checked=\"true\">";
print " <div id=\"toc-list\">";
getline;
while (!/<hr>/) {
if (length($0) > 0) {
print " " $0;
}
getline;
}
print " <hr>";
print " <a href=\".\" class=\"return\">Return to list</a><br>";
print " </div>";
print " </div>";
print "";
$0 = "<article>";
}
# Groff is adding an horizontal line at the end of the page, we remove it;
# we take the opportunity to close the <article> that we opened after the toc
/<hr>/ {
$0 = "</article>"
}
# Groff includes a basic CSS style, we want to replace it with our own to be consitent with
# the general website style
/<style/ {
while (!/<\/style>/) {
getline;
}
print "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">";
$0 = "<link rel=\"stylesheet\" type=\"text/css\" href=\"/manpage.css\">"
}
# Detect the email address and add a link; take the opportunity to conceal it the same way it is
# done for the mailing list, to make spammers work less easy
/&lt;[^@ ]*@[^<@> ]*&gt;/ && inside_body {
line = "";
while (1) {
idx_start = match($0, /&lt;[^@ ]*@[^<@> ]*&gt;/);
if (idx_start == 0) break;
email = substr($0, idx_start + 4, RLENGTH - 8);
gsub(/@/, " (at) ", email);
gsub(/\./, " (dot) ", email);
line = line substr($0, 1, idx_start - 1) "&lt;";
line = line "<a href=\"mailto:" email "\">" email "</a>&gt;";
$0 = substr($0, idx_start + RLENGTH);
}
$0 = line $0;
}
# Detect urls and add a link
/http:\/\// && inside_body {
line = "";
while (1) {
idx_start = index($0, "http://");
if (idx_start == 0) break;
line = line substr($0, 1, idx_start - 1);
$0 = substr($0, idx_start);
idx_end = match($0, /[ \t&]/);
if (idx_end == 0) idx_end = length($0) + 1;
line = line "<a href=\"" substr($0, 1, idx_end - 1) "\">";
line = line substr($0, 1, idx_end - 1) "</a>";
$0 = substr($0, idx_end);
}
$0 = line $0;
}
# Detect references to other man pages and add a link
/<b>[A-Za-z_0-9]*<\/b>\([1-9][a-z]*\)/ {
line = "";
while (1) {
idx_start = match($0, /<b>[A-Za-z_0-9]*<\/b>\([1-9][a-z]*\)/);
if (idx_start == 0) break;
line = line substr($0, 1, idx_start - 1);
split(substr($0, idx_start + 3), elements, /<\/b>\(|\)/);
# elements[1] contains the name of the man-page
# elements[2] contains the section
$0 = substr($0, idx_start + RLENGTH);
idx_known = match(known_pages, " ([^ ]*/)*" elements[1] "\\." elements[2]);
if (idx_known == 0) {
if (external_template == "") {
print "Error: no URL provided for external man page, needed for \"" elements[1] "(" elements[2] ")\" at line " NR > "/dev/stderr";
exit(2);
}
url = gensub(/%s/, elements[2], "g", external_template);
url = gensub(/%p/, elements[1], "g", url);
url = gensub(/%l/, tolower(elements[1]), "g", url);
url = gensub(/%u/, toupper(elements[1]), "g", url);
} else {
# When it is a known page, use the data from known_pages to have possible path information
url = substr(known_pages, idx_known + 1, RLENGTH - length(elements[2]) - 2) ".html";
}
line = line "<a href=\"" url "\"><tt>" elements[1] "</tt>(" elements[2] ")</a>";
}
$0 = line $0;
}
# Detect the start of the page to insert the navigation menu code
/<body>/ {
inside_body = 1;
print;
print "<div id=\"wrapper\">";
if (menu_code) {
while (getline < menu_code) {
print;
}
}
next;
}
/<\/body>/ {
if (package_line) {
print "<div class=\"footer\">"
print " This man page is part of <div id=\"pkgname\">" package_line "</div>";
print "</div>"
}
print " <div id=\"titlebar\">";
print " <div id=\"minimize\"></div>";
print " <div id=\"titlebar-inner\">Window Maker Manual: " gensub(/\.(.*)$/, "(\\1)", 1, source_name) "</div>";
print " <div id=\"close\"></div>";
print " </div>";
print " <div id=\"resizebar\">";
print " <div id=\"resizel\"></div>";
print " <div id=\"resizebar-inner\"></div>";
print " <div id=\"resizer\"></div>";
print " </div>";
print "</div>"; # close "wrapper"
inside_body = 0;
}
{ print }
'
###########################################################################
$GROFF -man -Dutf8 -Thtml < "$input_file" | \
awk "$awk_init$awk_process_html" > "$TARGET/$output_file" \
|| exit $?