Login  Register

Re: Extensions of useful macros for software documentation

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options Options
Embed post
Permalink
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: Extensions of useful macros for software documentation

mojavelinux
Administrator
The only thing I would suggest is to avoid using the Preprocessor unless there is absolutely no other way to do it. A preprocessor has really nasty side effects that can prevent other features in Asciidoctor from working properly unless the preprocessing is done very carefully. This is a strong recommendation.

From the looks of it, you should be able to use the custom block and inline macros (name::target[attrlist] or name:target[attrlist]) to do most of what you want to do. For example, var::[] can be a block macro (or, if you want to use it inline, it would be var:[])

Cheers,

-Dan

On Tue, Feb 19, 2019 at 12:36 AM Dan Allen <[hidden email]> wrote:
[hidden email]
@mariocup,

I'm excited to see that you are developing extensions. Now you're really tapping into the power of Asciidoctor.

I encourage you to set up a project on GitHub to share these extensions and even package and publish them as a RubyGem for others to use (and yourself). You certainly don't need permission from me or anyone else to set up an extensions project. It will also provide the best opportunity to collect feedback from others and improve the code. Just go for it, then let us know where to find it ;)

Cheers,

-Dan


On Mon, Feb 18, 2019 at 3:10 PM mariocup [via Asciidoctor :: Discussion] <[hidden email]> wrote:
Dear Asciidoctor community,

I am using Asciidoc to write documentation for software and I tried to write some macros to cover the following requirements.

opt::[] to format a string as option e.g. used to describe command line tools
var::[] format a variable as parameter by adding <parameter>
file::[] format a string in the text as file e.g. to mention a header file etc.

optentry: a list environment (role=optentry) which renders the list entry as option.

fcntenry: create a list environment (role=fcnentry) which renders the list entry with rouge syntax highlighting.

I consider this functionality also useful for other users and I would be more than happy if the functionality could be added to the extension lab after review and maintained by the community.

I collected my extensions in a file (can be passed by Asciidoctor option e.g. -r myextensions.rb).

```
RUBY_ENGINE == 'opal' ? (require 'variable-preprocessor/extension') : (require_relative 'variable-preprocessor/extension')
RUBY_ENGINE == 'opal' ? (require 'opt-preprocessor/extension') : (require_relative 'opt-preprocessor/extension')
RUBY_ENGINE == 'opal' ? (require 'file-preprocessor/extension') : (require_relative 'file-preprocessor/extension')
RUBY_ENGINE == 'opal' ? (require 'optentry-treeprocessor/extension') : (require_relative 'optentry-treeprocessor/extension')
RUBY_ENGINE == 'opal' ? (require 'fcnentry-treeprocessor/extension') : (require_relative 'fcnentry-treeprocessor/extension')


Extensions.register do
#  preprocessor  GitMetadataPreprocessor
  preprocessor  VariablePreprocessor
  preprocessor  FilePreprocessor
  preprocessor  OptPreprocessor
  treeprocessor OptEntryTreeProcessor
  treeprocessor FcnEntryTreeProcessor
end
```

The code looks like

# fcnentry

```
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
require 'asciidoctor-pdf'
require 'asciidoctor-pdf/rouge_ext'

include Asciidoctor

module RawTerm
  def text
    @text
  end

  def text= text
    @text = text
  end
end

class FcnEntryTreeProcessor < Extensions::Treeprocessor
  def process doc
    (doc.find_by context: :dlist, role: 'fcnentry').each do |dlist|
      dlist.items.each do |dlist_entry|
        terms, description = dlist_entry
        term_0 = terms[0]
        term_0.extend RawTerm
        lexer = Rouge::Lexer.find 'c'
        formatter = if doc.backend == "html5"
          Rouge::Formatters::HTML.new(Rouge::Theme.find(doc.attr('rouge-style', 'github')).new)
        else
          Rouge::Formatters::HTMLInline.new(Rouge::Theme.find(doc.attr('rouge-style', 'github')).new)
        end
        newText = formatter.format(lexer.lex(term_0.text))
        term_0.text = newText
      end
    end
  end
end
````

# opentry

```
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'

include Asciidoctor

def convert_to_opt block
    newText = "`" << block.text << "`"
    ListItem.new(block.parent, newText)
  end

class OptEntryTreeProcessor < Extensions::Treeprocessor
  def process doc
    (doc.find_by context: :dlist, role: 'optentry').each do |dlist|
      dlist.items.each.with_index do |dlist_entry, index|
        #puts dlist_entry.inspect, index
        terms, description = dlist_entry
        terms[0] = convert_to_opt terms[0]
      end
    end
  end
end
```

# variable

```
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'

include ::Asciidoctor

class VariablePreprocessor < Extensions::Preprocessor
  def process document, reader
    lines = []
    while reader.has_more_lines?
      lines << reader.read_line
    end
    lines.map do |line|
      while ((startIndex = line.index("var::")))
        if match = /(\w*-*(<\w*\s*\w*>)*)*/.match(line[(startIndex + 5)..-1])[0]
          line.insert(startIndex + 5 + match.length, ">")
          line[startIndex..startIndex+4] = "<"
        end
      end
    end
    Asciidoctor::Reader.new lines
  end
end
```

# opt

```
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'

include ::Asciidoctor

class OptPreprocessor < Extensions::Preprocessor
  def process document, reader
    lines = []
    while reader.has_more_lines?
      lines << reader.read_line
    end
    lines.map do |line|
      while ((startIndex = line.index("opt::")))
        if match = /(\w*-*(<\w*\s*\w*>)*)*/.match(line[(startIndex + 5)..-1])[0]
          line.insert(startIndex + 5 + match.length, "`")
          line[startIndex..startIndex+4] = "`-"
        end
      end
    end
    Asciidoctor::Reader.new lines
  end
end
```

# file

```
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'

include ::Asciidoctor

class FilePreprocessor < Extensions::Preprocessor
  def process document, reader
    lines = []
    while reader.has_more_lines?
      lines << reader.read_line
    end
    lines.map do |line|
      while ((startIndex = line.index("file::")))
        if match = /([[:punct:]]|\w)*\.\w+/.match(line[(startIndex + 6)..-1])[0]
          line.insert(startIndex + 6 + match.length, "`")
          line[startIndex..startIndex+5] = "`"
        end
      end
    end
    Asciidoctor::Reader.new lines
  end
end
```

Any feedback is welcome.



If you reply to this email, your message will be added to the discussion below:
http://discuss.asciidoctor.org/Extensions-of-useful-macros-for-software-documentation-tp6753.html
To start a new topic under Asciidoctor :: Discussion, email [hidden email]
To unsubscribe from Asciidoctor :: Discussion, click here.
NAML


--
Dan Allen | @mojavelinux | https://twitter.com/mojavelinux


--
Dan Allen | @mojavelinux | https://twitter.com/mojavelinux
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: Extensions of useful macros for software documentation

mariocup
Hi Dan,

I want to use the macro like

```
file::name.o
```

instead of

```
file::name.o[]
```

I was not able to achieve it with a block macro file::target[attrlist].  Only file::name.o[] seem to work.

Some of the macros have been rewritten in a way that they work also with hierarchical include directives. This was a problem before I switched to the Preprocessor.

In addition I am facing some issues with the current implementation of the opt and file macro.

```
    lines.map do |line|
      while ((startIndex = line.index("opt::")))
        if match = /(\w*-*(<\w*\s*\w*>)*)*/.match(line[(startIndex + 5)..-1])[0]
          line.insert(startIndex + 5 + match.length, "`")
          line[startIndex..startIndex+4] = "`-"
        end
      end
    end
```

and file

```
    lines.map do |line|
      while ((startIndex = line.index("file::")))
        if match = /([[:punct:]]|\w)*\.\w+/.match(line[(startIndex + 6)..-1])[0]
          line.insert(startIndex + 6 + match.length, "`")
          line[startIndex..startIndex+5] = "`"
        end
```

As debugging of macros is no fun I would be very happy for any hints how to use the macros correctly.