diff --git a/Gemfile b/Gemfile index 3ce8333751..2e9ac7e322 100644 --- a/Gemfile +++ b/Gemfile @@ -7,3 +7,4 @@ gem "rss" gem "asciidoctor", "~> 2.0.0" gem "nokogiri" gem "diffy" +gem "parslet" diff --git a/assets/sass/application.scss b/assets/sass/application.scss index 7e352c3f30..638e47bde2 100644 --- a/assets/sass/application.scss +++ b/assets/sass/application.scss @@ -29,7 +29,7 @@ $baseurl: "{{ .Site.BaseURL }}{{ if (and (ne .Site.BaseURL "/") (ne .Site.BaseUR code { display: inline; - padding: 0 5px; + padding: 0 0; } pre { diff --git a/assets/sass/typography.scss b/assets/sass/typography.scss index 5e8a840906..bd598b99e8 100644 --- a/assets/sass/typography.scss +++ b/assets/sass/typography.scss @@ -251,7 +251,6 @@ blockquote { } code { - @include border-radius(3px); display: block; padding: 10px 15px 13px; margin-bottom: 1em; @@ -260,8 +259,6 @@ code { line-height: $fixed-width-line-height; font-variant-ligatures: none; color: $orange; - background-color: #fff; - border: solid 1px #efeee6; } // Quotes diff --git a/script/asciidoctor-extensions.rb b/script/asciidoctor-extensions.rb new file mode 100644 index 0000000000..54285f6a75 --- /dev/null +++ b/script/asciidoctor-extensions.rb @@ -0,0 +1,129 @@ +require 'asciidoctor' +require 'asciidoctor/extensions' +require 'asciidoctor/converter/html5' +require 'parslet' + +module Git + module Documentation + class AdocSynopsisQuote < Parslet::Parser + # parse a string like "git add -p [--root=]" as series of tokens keywords, grammar signs and placeholders + # where placeholders are UTF-8 words separated by '-', enclosed in '<' and '>' + rule(:space) { match('[\s\t\n ]').repeat(1) } + rule(:space?) { space.maybe } + rule(:keyword) { match('[-a-zA-Z0-9:+=~@,\./_\^\$\'"\*%!{}#]').repeat(1) } + rule(:placeholder) { str('<') >> match('[[:word:]]|-').repeat(1) >> str('>') } + rule(:opt_or_alt) { match('[\[\] |()]') >> space? } + rule(:ellipsis) { str('...') >> match('\]|$').present? } + rule(:grammar) { opt_or_alt | ellipsis } + rule(:ignore) { match('[\'`]') } + + rule(:token) do + grammar.as(:grammar) | placeholder.as(:placeholder) | space.as(:grammar) | + ignore.as(:ignore) | keyword.as(:keyword) + end + rule(:tokens) { token.repeat(1) } + root(:tokens) + end + + class EscapedSynopsisQuote < Parslet::Parser + rule(:space) { match('[\s\t\n ]').repeat(1) } + rule(:space?) { space.maybe } + rule(:keyword) { match('[-a-zA-Z0-9:+=~@,\./_\^\$\'"\*%!{}#]').repeat(1) } + rule(:placeholder) { str('<') >> match('[[:word:]]|-').repeat(1) >> str('>') } + rule(:opt_or_alt) { match('[\[\] |()]') >> space? } + rule(:ellipsis) { str('...') >> match('\]|$').present? } + rule(:grammar) { opt_or_alt | ellipsis } + rule(:ignore) { match('[\'`]') } + + rule(:token) do + grammar.as(:grammar) | placeholder.as(:placeholder) | space.as(:grammar) | + ignore.as(:ignore) | keyword.as(:keyword) + end + rule(:tokens) { token.repeat(1) } + root(:tokens) + end + + class SynopsisQuoteToAdoc < Parslet::Transform + rule(grammar: simple(:grammar)) { grammar.to_s } + rule(keyword: simple(:keyword)) { "{empty}`#{keyword}`{empty}" } + rule(placeholder: simple(:placeholder)) { "__#{placeholder}__" } + rule(ignore: simple(:ignore)) { '' } + end + + class SynopsisQuoteToHtml5 < Parslet::Transform + rule(grammar: simple(:grammar)) { grammar.to_s } + rule(keyword: simple(:keyword)) { "#{keyword}" } + rule(placeholder: simple(:placeholder)) { "#{placeholder}" } + rule(ignore: simple(:ignore)) { '' } + end + + class SynopsisConverter + def convert(parslet_parser, parslet_transform, reader, logger = nil) + reader.lines.map do |l| + parslet_transform.apply(parslet_parser.parse(l)).join + end.join("\n") + rescue Parslet::ParseFailed + logger&.info "synopsis parsing failed for '#{reader.lines.join(' ')}'" + reader.lines.map do |l| + parslet_transform.apply(placeholder: l) + end.join("\n") + end + end + + class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor + use_dsl + named :synopsis + parse_content_as :simple + + def process(parent, reader, attrs) + outlines = SynopsisConverter.new.convert( + AdocSynopsisQuote.new, + SynopsisQuoteToAdoc.new, + reader, + parent.document.logger + ) + create_block parent, :verse, outlines, attrs + 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 + SynopsisConverter.new.convert( + EscapedSynopsisQuote.new, + SynopsisQuoteToHtml5.new, + node.text, + node.document.logger + ) + 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 + block Git::Documentation::SynopsisBlock +end diff --git a/script/update-docs.rb b/script/update-docs.rb index 07c168fd1a..28223891ce 100644 --- a/script/update-docs.rb +++ b/script/update-docs.rb @@ -9,6 +9,7 @@ require 'yaml' require 'diffy' require_relative "version" +require_relative 'asciidoctor-extensions' SITE_ROOT = File.join(File.expand_path(File.dirname(__FILE__)), '../') DOCS_INDEX_FILE = "#{SITE_ROOT}external/docs/content/docs/_index.html"