git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 1/3] doc: introduce a synopsis typesetting

From
Jean-Noël Avila via GitGitGadget <gitgitgadget@gmail.com>
Date
Sep 5, 2024, 21:52 UTC
Message-ID
<c09968d7ccbaa22b36daf0f3f8e88eb3e154c654.1725573126.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1766.v4.git.1725573126.gitgitgadget@gmail.com>
From: =?UTF-8?q?Jean-No=C3=ABl=20Avila?= <jn.avila@free.fr>

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>
---
 Documentation/asciidoc.conf             | 20 ++++++
 Documentation/asciidoctor-extensions.rb | 87 +++++++++++++++++++++++++
 ci/install-dependencies.sh              |  1 +
 t/t0450-txt-doc-vs-help.sh              | 11 ++--
 4 files changed, 112 insertions(+), 7 deletions(-)
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 60f76f43eda..75ae9f3da92 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -28,6 +28,10 @@ ifdef::backend-docbook[]
 {0#<citerefentry>}
 {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
 {0#</citerefentry>}
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-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])))}
+
 endif::backend-docbook[]
 
 ifdef::backend-docbook[]
@@ -56,4 +60,20 @@ ifdef::backend-xhtml11[]
 git-relative-html-prefix=
 [linkgit-inlinemacro]
 <a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<em>\1</em>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-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])))}
+
+endif::backend-xhtml11[]
+
+ifdef::backend-docbook[]
+ifdef::doctype-manpage[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed -E 's!([\[ |()>]|^|\])(\.?[-=a-zA-Z0-9:+@,\/_^\$]+\.?+)!\\1<literal>\\2</literal>!g;s!&lt;[-a-zA-Z0-9.]+&gt;!<emphasis>\\0</emphasis>!g'"
+endif::doctype-manpage[]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed -E 's!([\[ |()>]|^|\])(\.?[-=a-zA-Z0-9:+@,\/_^\$]+\.?)!\\1<code>\\2</code>!g;s!&lt;[-a-zA-Z0-9.]+&gt;!<em>\\0</em>!g'"
 endif::backend-xhtml11[]
diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb
index d906a008039..cb24480b63d 100644
--- a/Documentation/asciidoctor-extensions.rb
+++ b/Documentation/asciidoctor-extensions.rb
@@ -1,5 +1,7 @@
 require 'asciidoctor'
 require 'asciidoctor/extensions'
+require 'asciidoctor/converter/docbook5'
+require 'asciidoctor/converter/html5'
 
 module Git
   module Documentation
@@ -39,10 +41,95 @@ module Git
         output
       end
     end
+
+    class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor
+
+      use_dsl
+      named :synopsis
+      parse_content_as :simple
+
+      def process parent, reader, attrs
+        outlines = reader.lines.map do |l|
+          l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2')
+           .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}')
+           .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__')
+           .gsub(']', ']{empty}')
+        end
+        create_block parent, :verse, outlines, attrs
+      end
+    end
+
+    class GitDBConverter < Asciidoctor::Converter::DocBook5Converter
+
+      extend Asciidoctor::Converter::Config
+      register_for 'docbook5'
+
+      def convert_inline_quoted node
+        if (type = node.type) == :asciimath
+          # NOTE fop requires jeuclid to process mathml markup
+          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>)
+        elsif type == :latexmath
+          # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
+          %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
+        elsif type == :monospaced
+          node.text.gsub(/(\.\.\.?)([^\]$.])/, '<literal>\1</literal>\2')
+              .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<literal>\2</literal>')
+              .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<emphasis>\1</emphasis>')
+        else
+          open, close, supports_phrase = QUOTE_TAGS[type]
+          text = node.text
+          if node.role
+            if supports_phrase
+              quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
+            else
+              quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
+            end
+          else
+            quoted_text = %(#{open}#{text}#{close})
+          end
+          node.id ? %(<anchor#{common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
+        end
+      end
+    end
+
+    # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis
+    class GitHTMLConverter < Asciidoctor::Converter::Html5Converter
+
+      extend Asciidoctor::Converter::Config
+      register_for 'html5'
+
+      def convert_inline_quoted node
+        if node.type == :monospaced
+          node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2')
+              .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<code>\2</code>')
+              .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<em>\1</em>')
+
+        else
+          open, close, tag = QUOTE_TAGS[node.type]
+          if node.id
+            class_attr = node.role ? %( class="#{node.role}") : ''
+            if tag
+              %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close})
+            else
+              %(<span id="#{node.id}"#{class_attr}>#{open}#{node.text}#{close}</span>)
+            end
+          elsif node.role
+            if tag
+              %(#{open.chop} class="#{node.role}">#{node.text}#{close})
+            else
+              %(<span class="#{node.role}">#{open}#{node.text}#{close}</span>)
+            end
+          else
+            %(#{open}#{node.text}#{close})
+          end
+        end
+      end
+    end
   end
 end
 
 Asciidoctor::Extensions.register do
   inline_macro Git::Documentation::LinkGitProcessor, :linkgit
+  block Git::Documentation::SynopsisBlock
   postprocessor Git::Documentation::DocumentPostProcessor
 end
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 4781cd20bb0..3e3ae39cbb1 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -107,6 +107,7 @@ Documentation)
 
 	test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
 	sudo gem install --version 1.5.8 asciidoctor
+	sudo gem install concurrent-ruby
 	;;
 esac
 
diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh
index 69917d7b845..f99a69ae1b7 100755
--- a/t/t0450-txt-doc-vs-help.sh
+++ b/t/t0450-txt-doc-vs-help.sh
@@ -56,14 +56,11 @@ txt_to_synopsis () {
 	fi &&
 	b2t="$(builtin_to_txt "$builtin")" &&
 	sed -n \
-		-e '/^\[verse\]$/,/^$/ {
+		-E '/^\[(verse|synopsis)\]$/,/^$/ {
 			/^$/d;
-			/^\[verse\]$/d;
-			s/_//g;
-			s/++//g;
-			s/`//g;
-			s/{litdd}/--/g;
-			s/'\''\(git[ a-z-]*\)'\''/\1/g;
+			/^\[(verse|synopsis)\]$/d;
+			s/\{litdd\}/--/g;
+			s/'\''(git[ a-z-]*)'\''/\1/g;
 
 			p;
 		}' \
-- 
gitgitgadget
Previous: Jean-Noël Avila via GitGitGadgetNext: Jean-Noël Avila via GitGitGadget
Message 25 of 45 in “doc: introducing synopsis para”
  1. 0/3 doc: introducing synopsis paraJean-Noël Avila via GitGitGadget, Jul 23, 2024
  2. 1/3 doc: introduce a synopsis custom paragraph attributeJean-Noël Avila via GitGitGadget, Jul 23, 2024
  3. Junio C HamanoJul 23, 2024
  4. 2/3 doc: update the guidelines to reflect the current formatting rulesJean-Noël Avila via GitGitGadget, Jul 23, 2024
  5. Junio C HamanoJul 23, 2024
  6. 3/3 doc: apply synopsis simplification on git-clone and git-initJean-Noël Avila via GitGitGadget, Jul 23, 2024
  7. Jean-Noël AVILAJul 23, 2024
  8. 0/3 doc: introducing synopsis paraJean-Noël Avila via GitGitGadget, Jul 24, 2024
  9. 1/3 doc: introduce a synopsis custom paragraph attributeJean-Noël Avila via GitGitGadget, Jul 24, 2024
  10. 2/3 doc: update the guidelines to reflect the current formatting rulesJean-Noël Avila via GitGitGadget, Jul 24, 2024
  11. 3/3 doc: apply synopsis simplification on git-clone and git-initJean-Noël Avila via GitGitGadget, Jul 24, 2024
  12. Junio C HamanoJul 24, 2024
  13. Jean-Noël AVILAJul 25, 2024
  14. Junio C HamanoJul 25, 2024
  15. 0/3 doc: introducing synopsis paraJean-Noël Avila via GitGitGadget, Aug 11, 2024
  16. 1/3 doc: introduce a synopsis custom paragraph attributeJean-Noël Avila via GitGitGadget, Aug 11, 2024
  17. 2/3 doc: update the guidelines to reflect the current formatting rulesJean-Noël Avila via GitGitGadget, Aug 11, 2024
  18. Eric SunshineAug 11, 2024
  19. Jean-Noël AvilaAug 12, 2024
  20. 3/3 doc: apply synopsis simplification on git-clone and git-initJean-Noël Avila via GitGitGadget, Aug 11, 2024
  21. Junio C HamanoAug 19, 2024
  22. Jean-Noël AVILAAug 21, 2024
  23. Junio C HamanoAug 30, 2024
  24. 0/3 doc: introducing synopsis paraJean-Noël Avila via GitGitGadget, Sep 5, 2024
  25. 1/3 doc: introduce a synopsis typesettingJean-Noël Avila via GitGitGadget, Sep 5, 2024
  26. 2/3 doc: update the guidelines to reflect the current formatting rulesJean-Noël Avila via GitGitGadget, Sep 5, 2024
  27. 3/3 doc: apply synopsis simplification on git-clone and git-initJean-Noël Avila via GitGitGadget, Sep 5, 2024
  28. Junio C HamanoSep 13, 2024
  29. Josh SteadmonSep 20, 2024
  30. Junio C HamanoSep 21, 2024
  31. Junio C HamanoSep 21, 2024
  32. Junio C HamanoSep 21, 2024
  33. Chris TorekSep 21, 2024
  34. Junio C HamanoSep 23, 2024
  35. 0/3 doc: introducing synopsis paraJean-Noël Avila via GitGitGadget, Sep 24, 2024
  36. 1/3 doc: introduce a synopsis typesettingJean-Noël Avila via GitGitGadget, Sep 24, 2024
  37. 2/3 doc: update the guidelines to reflect the current formatting rulesJean-Noël Avila via GitGitGadget, Sep 24, 2024
  38. 3/3 doc: apply synopsis simplification on git-clone and git-initJean-Noël Avila via GitGitGadget, Sep 24, 2024
  39. Junio C HamanoSep 24, 2024
  40. Torsten BögershausenSep 24, 2024
  41. Junio C HamanoSep 24, 2024
  42. Josh SteadmonOct 2, 2024
  43. Junio C HamanoOct 2, 2024
  44. Josh SteadmonSep 24, 2024
  45. Junio C HamanoSep 24, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.