From 974cdca345cc51fb8623c611a25314f98b2cd3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Avila?= Date: Tue, 24 Sep 2024 07:08:48 +0000 Subject: [PATCH 1/3] doc: introduce a synopsis typesetting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- 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 60f76f43ed..f6da6d1fbd 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -28,6 +28,10 @@ ifdef::backend-docbook[] {0#} {0#{target}{0}} {0#} + +[literal-inlinemacro] +{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\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] {target}{0?({0})} + +[literal-inlinemacro] +{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\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 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" +endif::doctype-manpage[] +endif::backend-docbook[] + +ifdef::backend-xhtml11[] +[paradef-default] +synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" endif::backend-xhtml11[] diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb index d906a00803..cb24480b63 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? ? %(#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}) : %() + elsif type == :latexmath + # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math + %() + elsif type == :monospaced + node.text.gsub(/(\.\.\.?)([^\]$.])/, '\1\2') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') + .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') + else + open, close, supports_phrase = QUOTE_TAGS[type] + text = node.text + if node.role + if supports_phrase + quoted_text = %(#{open}#{text}#{close}) + else + quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close}) + end + else + quoted_text = %(#{open}#{text}#{close}) + end + node.id ? %(#{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(/(\.\.\.?)([^\]$.])/, '\1\2') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') + .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') + + 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 + %(#{open}#{node.text}#{close}) + end + elsif node.role + if tag + %(#{open.chop} class="#{node.role}">#{node.text}#{close}) + else + %(#{open}#{node.text}#{close}) + 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 6ec0f85972..87d1596b79 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -103,6 +103,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 69917d7b84..f99a69ae1b 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; }' \ From 029eff9e34fcb622b6eabe9e695fa502a714df4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Avila?= Date: Tue, 24 Sep 2024 07:08:49 +0000 Subject: [PATCH 2/3] doc: update the guidelines to reflect the current formatting rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-Noël Avila Signed-off-by: Junio C Hamano --- Documentation/CodingGuidelines | 58 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 1d92b2da03..d1e3e4017d 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -738,78 +738,80 @@ Markup: __ __ - A placeholder is not enclosed in backticks, as it is not a literal. - When needed, use a distinctive identifier for placeholders, usually made of a qualification and a type: __ __ - When literal and placeholders are mixed, each markup is applied for - each sub-entity. If they are stuck, a special markup, called - unconstrained formatting is required. - Unconstrained formating for placeholders is ____ - Unconstrained formatting for literal formatting is ++like this++ - `--jobs` __ - ++--sort=++____ - ____++/.git++ - ++remote.++____++.mirror++ + Git's Asciidoc processor has been tailored to treat backticked text + as complex synopsis. When literal and placeholders are mixed, you can + use the backtick notation which will take care of correctly typesetting + the content. + `--jobs ` + `--sort=` + `/.git` + `remote..mirror` + `ssh://[@][:]/` - caveat: ++ unconstrained format is not verbatim and may expand - content. Use Asciidoc escapes inside them. +As a side effect, backquoted placeholders are correctly typeset, but +this style is not recommended. Synopsis Syntax - Syntax grammar is formatted neither as literal nor as placeholder. + The synopsis (a paragraph with [synopsis] attribute) is automatically + formatted by the toolchain and does not need typesetting. A few commented examples follow to provide reference when writing or modifying command usage strings and synopsis sections in the manual pages: Possibility of multiple occurrences is indicated by three dots: - __... + ... (One or more of .) Optional parts are enclosed in square brackets: - [__...] + [...] (Zero or more of .) - ++--exec-path++[++=++____] + An optional parameter needs to be typeset with unconstrained pairs + [] + + --exec-path[=] (Option with an optional argument. Note that the "=" is inside the brackets.) - [__...] + [...] (Zero or more of . Note that the dots are inside, not outside the brackets.) Multiple alternatives are indicated with vertical bars: - [`-q` | `--quiet`] - [`--utf8` | `--no-utf8`] + [-q | --quiet] + [--utf8 | --no-utf8] Use spacing around "|" token(s), but not immediately after opening or before closing a [] or () pair: - Do: [`-q` | `--quiet`] - Don't: [`-q`|`--quiet`] + Do: [-q | --quiet] + Don't: [-q|--quiet] Don't use spacing around "|" tokens when they're used to separate the alternate arguments of an option: - Do: ++--track++[++=++(`direct`|`inherit`)]` - Don't: ++--track++[++=++(`direct` | `inherit`)] + Do: --track[=(direct|inherit)] + Don't: --track[=(direct | inherit)] Parentheses are used for grouping: - [(__ | __)...] + [(|)...] (Any number of either or . Parens are needed to make it clear that "..." pertains to both and .) - [(`-p` __)...] + [(-p )...] (Any number of option -p, each with one argument.) - `git remote set-head` __ (`-a` | `-d` | __) + git remote set-head (-a|-d|) (One and only one of "-a", "-d" or "" _must_ (no square brackets) be provided.) And a somewhat more contrived example: - `--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]` + --diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]] Here "=" is outside the brackets, because "--diff-filter=" is a valid usage. "*" has its own pair of brackets, because it can (optionally) be specified only when one or more of the letters is From 22293895c000e89997b2197a7b2b17cdf3a36369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Avila?= Date: Tue, 24 Sep 2024 07:08:50 +0000 Subject: [PATCH 3/3] doc: apply synopsis simplification on git-clone and git-init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the new synopsis formatting backend, no special asciidoc markup is needed. Signed-off-by: Jean-Noël Avila Signed-off-by: Junio C Hamano --- Documentation/git-clone.txt | 78 ++++++++++++++++++------------------- Documentation/git-init.txt | 35 +++++++---------- Documentation/urls.txt | 26 ++++++------- 3 files changed, 67 insertions(+), 72 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 8e925db7e9..9c13f847da 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -8,16 +8,16 @@ git-clone - Clone a repository into a new directory SYNOPSIS -------- -[verse] -`git clone` [++--template=++____] - [`-l`] [`-s`] [`--no-hardlinks`] [`-q`] [`-n`] [`--bare`] [`--mirror`] - [`-o` __] [`-b` __] [`-u` __] [`--reference` __] - [`--dissociate`] [`--separate-git-dir` __] - [`--depth` __] [`--`[`no-`]{empty}`single-branch`] [`--no-tags`] - [++--recurse-submodules++[++=++____]] [++--++[++no-++]{empty}++shallow-submodules++] - [`--`[`no-`]{empty}`remote-submodules`] [`--jobs` __] [`--sparse`] [`--`[`no-`]{empty}`reject-shallow`] - [++--filter=++____] [`--also-filter-submodules`]] [`--`] __ - [__] +[synopsis] +git clone [--template=] + [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] + [-o ] [-b ] [-u ] [--reference ] + [--dissociate] [--separate-git-dir ] + [--depth ] [--[no-]single-branch] [--no-tags] + [--recurse-submodules[=]] [--[no-]shallow-submodules] + [--[no-]remote-submodules] [--jobs ] [--sparse] [--[no-]reject-shallow] + [--filter=] [--also-filter-submodules]] [--] + [] DESCRIPTION ----------- @@ -52,7 +52,7 @@ OPTIONS to save space when possible. + If the repository is specified as a local path (e.g., `/path/to/repo`), -this is the default, and --local is essentially a no-op. If the +this is the default, and `--local` is essentially a no-op. If the repository is specified as a URL, then this flag is ignored (and we never use the local optimizations). Specifying `--no-local` will override the default when `/path/to/repo` is given, using the regular @@ -64,8 +64,8 @@ prevent the unintentional copying of files by dereferencing the symbolic links. + *NOTE*: this operation can race with concurrent modification to the -source repository, similar to running `cp -r src dst` while modifying -`src`. +source repository, similar to running `cp -r ` while modifying +__. `--no-hardlinks`:: Force the cloning process from a repository on a local @@ -101,7 +101,7 @@ If you want to break the dependency of a repository cloned with `--shared` on its source repository, you can simply run `git repack -a` to copy all objects from the source repository into a pack in the cloned repository. -`--reference`[`-if-able`] __:: +`--reference[-if-able] `:: If the reference __ is on the local machine, automatically setup `.git/objects/info/alternates` to obtain objects from the reference __. Using @@ -142,17 +142,17 @@ objects from the source repository into a pack in the cloned repository. is specified. This flag forces progress status even if the standard error stream is not directed to a terminal. -++--server-option=++__