doc: introduce a synopsis typesetting
In order to follow the common manpage usage, the synopsis of the commands needs to be heavily typeset. A first try was performed with using native markup, but it turned out to make the document source almost unreadable, difficult to write and prone to mistakes with unwanted Asciidoc's role attributes. In order to both simplify the writer's task and obtain a consistant typesetting in the synopsis, a custom 'synopsis' paragraph type is created and the processor for backticked text are modified. The backends of asciidoc and asciidoctor take in charge to correctly add the required typesetting. Signed-off-by: Jean-Noël Avila <jn.avila@free.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jean-Noël Avila committed
Sep 24, 2024 at 07:08 UTC
974cdca345cc51fb8623c611a25314f98b2cd3e3
4 files changed
+112
-7
Documentation/asciidoc.conf
+20
@@ -28,6 +28,10 @@ ifdef::backend-docbook[]
28
{0#<citerefentry>}
29
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
30
{0#</citerefentry>}
31
+
32
+[literal-inlinemacro]
33
+{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
34
+
35
endif::backend-docbook[]
36
37
ifdef::backend-docbook[]
@@ -56,4 +60,20 @@ ifdef::backend-xhtml11[]
60
git-relative-html-prefix=
61
[linkgit-inlinemacro]
62
<a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
63
+
64
+[literal-inlinemacro]
65
+{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'<em>\1</em>', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<code>\2</code>', re.sub(r'(\.\.\.?)([^\]$.])', r'<code>\1</code>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
66
+
67
+endif::backend-xhtml11[]
68
+
69
+ifdef::backend-docbook[]
70
+ifdef::doctype-manpage[]
71
+[paradef-default]
72
+synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!<phrase>\\0</phrase>!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1<literal>\\2</literal>!g;s!<[-a-zA-Z0-9.]\\+>!<emphasis>\\0</emphasis>!g'"
73
+endif::doctype-manpage[]
74
+endif::backend-docbook[]
75
+
76
+ifdef::backend-xhtml11[]
77
+[paradef-default]
78
+synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!<span>\\0</span>!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1<code>\\2</code>!g;s!<[-a-zA-Z0-9.]\\+>!<em>\\0</em>!g'"
79
endif::backend-xhtml11[]
Documentation/asciidoctor-extensions.rb
+87
@@ -1,5 +1,7 @@
1
require 'asciidoctor'
2
require 'asciidoctor/extensions'
3
+require 'asciidoctor/converter/docbook5'
4
+require 'asciidoctor/converter/html5'
5
6
module Git
7
module Documentation
@@ -39,10 +41,95 @@ module Git
41
output
42
end
43
end
44
+
45
+ class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor
46
+
47
+ use_dsl
48
+ named :synopsis
49
+ parse_content_as :simple
50
+
51
+ def process parent, reader, attrs
52
+ outlines = reader.lines.map do |l|
53
+ l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2')
54
+ .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}')
55
+ .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__')
56
+ .gsub(']', ']{empty}')
57
+ end
58
+ create_block parent, :verse, outlines, attrs
59
+ end
60
+ end
61
+
62
+ class GitDBConverter < Asciidoctor::Converter::DocBook5Converter
63
+
64
+ extend Asciidoctor::Converter::Config
65
+ register_for 'docbook5'
66
+
67
+ def convert_inline_quoted node
68
+ if (type = node.type) == :asciimath
69
+ # NOTE fop requires jeuclid to process mathml markup
70
+ asciimath_available? ? %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>) : %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
71
+ elsif type == :latexmath
72
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
73
+ %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
74
+ elsif type == :monospaced
75
+ node.text.gsub(/(\.\.\.?)([^\]$.])/, '<literal>\1</literal>\2')
76
+ .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<literal>\2</literal>')
77
+ .gsub(/(<[-a-zA-Z0-9.]+>)/, '<emphasis>\1</emphasis>')
78
+ else
79
+ open, close, supports_phrase = QUOTE_TAGS[type]
80
+ text = node.text
81
+ if node.role
82
+ if supports_phrase
83
+ quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
84
+ else
85
+ quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
86
+ end
87
+ else
88
+ quoted_text = %(#{open}#{text}#{close})
89
+ end
90
+ node.id ? %(<anchor#{common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
91
+ end
92
+ end
93
+ end
94
+
95
+ # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis
96
+ class GitHTMLConverter < Asciidoctor::Converter::Html5Converter
97
+
98
+ extend Asciidoctor::Converter::Config
99
+ register_for 'html5'
100
+
101
+ def convert_inline_quoted node
102
+ if node.type == :monospaced
103
+ node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2')
104
+ .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<code>\2</code>')
105
+ .gsub(/(<[-a-zA-Z0-9.]+>)/, '<em>\1</em>')
106
+
107
+ else
108
+ open, close, tag = QUOTE_TAGS[node.type]
109
+ if node.id
110
+ class_attr = node.role ? %( class="#{node.role}") : ''
111
+ if tag
112
+ %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close})
113
+ else
114
+ %(<span id="#{node.id}"#{class_attr}>#{open}#{node.text}#{close}</span>)
115
+ end
116
+ elsif node.role
117
+ if tag
118
+ %(#{open.chop} class="#{node.role}">#{node.text}#{close})
119
+ else
120
+ %(<span class="#{node.role}">#{open}#{node.text}#{close}</span>)
121
+ end
122
+ else
123
+ %(#{open}#{node.text}#{close})
124
+ end
125
+ end
126
+ end
127
+ end
128
end
129
end
130
131
Asciidoctor::Extensions.register do
132
inline_macro Git::Documentation::LinkGitProcessor, :linkgit
133
+ block Git::Documentation::SynopsisBlock
134
postprocessor Git::Documentation::DocumentPostProcessor
135
end
ci/install-dependencies.sh
+1
@@ -103,6 +103,7 @@ Documentation)
103
104
test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
105
sudo gem install --version 1.5.8 asciidoctor
106
+ sudo gem install concurrent-ruby
107
;;
108
esac
109
t/t0450-txt-doc-vs-help.sh
+4
-7
@@ -56,14 +56,11 @@ txt_to_synopsis () {
56
fi &&
57
b2t="$(builtin_to_txt "$builtin")" &&
58
sed -n \
59
- -e '/^\[verse\]$/,/^$/ {
59
+ -E '/^\[(verse|synopsis)\]$/,/^$/ {
60
/^$/d;
61
- /^\[verse\]$/d;
62
- s/_//g;
63
- s/++//g;
64
- s/`//g;
65
- s/{litdd}/--/g;
66
- s/'\''\(git[ a-z-]*\)'\''/\1/g;
61
+ /^\[(verse|synopsis)\]$/d;
62
+ s/\{litdd\}/--/g;
63
+ s/'\''(git[ a-z-]*)'\''/\1/g;
64
65
p;
66
}' \