Unverified Commit d7920ff9 authored by Viktor Söderqvist's avatar Viktor Söderqvist Committed by GitHub
Browse files

Modules API docs: Sections and links (#8442)

* Modules API docs: Link API function names to their definitions

Occurrences of API functions are linked to their definition.

A function index with links to all functions is added on the bottom
of the page.

Comment blocks in module.c starting with a markdown h2 heading are
used as sections. A table of contents is generated from these
headings.

The functions names are changed from h2 to h3, since they are now
rendered as sub-headings within each section.

Existing sections in module.c are used with some minor changes.
Some documentation text is added or sligtly modified.

The markdown renderer will add IDs which may clash with our
generated IDs. By prefixing section IDs with "section-" we make
them different.

Replace double dashes with a unicode long ndash
parent c6cd1e59
This diff is collapsed.
# coding: utf-8
# gendoc.rb -- Converts the top-comments inside module.c to modules API # gendoc.rb -- Converts the top-comments inside module.c to modules API
# reference documentation in markdown format. # reference documentation in markdown format.
...@@ -21,15 +22,48 @@ def markdown(s) ...@@ -21,15 +22,48 @@ def markdown(s)
l = l.gsub(/(?<![`A-z])[a-z_]+\(\)/, '`\0`') l = l.gsub(/(?<![`A-z])[a-z_]+\(\)/, '`\0`')
# Add backquotes around macro and var names containing underscores. # Add backquotes around macro and var names containing underscores.
l = l.gsub(/(?<![`A-z\*])[A-Za-z]+_[A-Za-z0-9_]+/){|x| "`#{x}`"} l = l.gsub(/(?<![`A-z\*])[A-Za-z]+_[A-Za-z0-9_]+/){|x| "`#{x}`"}
# Link URLs preceded by space (i.e. when not already linked) # Link URLs preceded by space or newline (not already linked)
l = l.gsub(/ (https?:\/\/[A-Za-z0-9_\/\.\-]+[A-Za-z0-9\/])/, l = l.gsub(/((?:^| )https?:\/\/[A-Za-z0-9_\/\.\-]+[A-Za-z0-9\/])/,
' [\1](\1)') '[\1](\1)')
# Replace double-dash with unicode ndash
l = l.gsub(/ -- /, ' – ')
end end
# Link function names to their definition within the page
l = l.gsub(/`(RedisModule_[A-z0-9]+)[()]*`/) {|x|
$index[$1] ? "[#{x}](\##{$1})" : x
}
newlines << l newlines << l
} }
return newlines.join("\n") return newlines.join("\n")
end end
# Linebreak a prototype longer than 80 characters on the commas, but only
# between balanced parentheses so that we don't linebreak args which are
# function pointers, and then aligning each arg under each other.
def linebreak_proto(proto, indent)
if proto.bytesize <= 80
return proto
end
parts = proto.split(/,\s*/);
if parts.length == 1
return proto;
end
align_pos = proto.index("(") + 1;
align = " " * align_pos
result = parts.shift;
bracket_balance = 0;
parts.each{|part|
if bracket_balance == 0
result += ",\n" + indent + align
else
result += ", "
end
result += part
bracket_balance += part.count("(") - part.count(")")
}
return result;
end
# Given the source code array and the index at which an exported symbol was # Given the source code array and the index at which an exported symbol was
# detected, extracts and outputs the documentation. # detected, extracts and outputs the documentation.
def docufy(src,i) def docufy(src,i)
...@@ -38,7 +72,11 @@ def docufy(src,i) ...@@ -38,7 +72,11 @@ def docufy(src,i)
name = name.sub("RM_","RedisModule_") name = name.sub("RM_","RedisModule_")
proto = src[i].sub("{","").strip+";\n" proto = src[i].sub("{","").strip+";\n"
proto = proto.sub("RM_","RedisModule_") proto = proto.sub("RM_","RedisModule_")
puts "## `#{name}`\n\n" proto = linebreak_proto(proto, " ");
# Add a link target with the function name. (We don't trust the exact id of
# the generated one, which depends on the Markdown implementation.)
puts "<span id=\"#{name}\"></span>\n\n"
puts "### `#{name}`\n\n"
puts " #{proto}\n" puts " #{proto}\n"
comment = "" comment = ""
while true while true
...@@ -50,13 +88,87 @@ def docufy(src,i) ...@@ -50,13 +88,87 @@ def docufy(src,i)
puts comment+"\n\n" puts comment+"\n\n"
end end
# Print a comment from line until */ is found, as markdown.
def section_doc(src, i)
name = get_section_heading(src, i)
comment = "<span id=\"#{section_name_to_id(name)}\"></span>\n\n"
while true
# append line, except if it's a horizontal divider
comment = comment + src[i] if src[i] !~ /^[\/ ]?\*{1,2} ?-{50,}/
break if src[i] =~ /\*\//
i = i+1
end
comment = markdown(comment)
puts comment+"\n\n"
end
# generates an id suitable for links within the page
def section_name_to_id(name)
return "section-" +
name.strip.downcase.gsub(/[^a-z0-9]+/, '-').gsub(/^-+|-+$/, '')
end
# Returns the name of the first section heading in the comment block for which
# is_section_doc(src, i) is true
def get_section_heading(src, i)
if src[i] =~ /^\/\*\*? \#+ *(.*)/
heading = $1
elsif src[i+1] =~ /^ ?\* \#+ *(.*)/
heading = $1
end
return heading.gsub(' -- ', ' – ')
end
# Returns true if the line is the start of a generic documentation section. Such
# section must start with the # symbol, i.e. a markdown heading, on the first or
# the second line.
def is_section_doc(src, i)
return src[i] =~ /^\/\*\*? \#/ ||
(src[i] =~ /^\/\*/ && src[i+1] =~ /^ ?\* \#/)
end
def is_func_line(src, i)
line = src[i]
return line =~ /RM_/ &&
line[0] != ' ' && line[0] != '#' && line[0] != '/' &&
src[i-1] =~ /\*\//
end
puts "# Modules API reference\n\n" puts "# Modules API reference\n\n"
puts "<!-- This file is generated from module.c using gendoc.rb -->\n\n" puts "<!-- This file is generated from module.c using gendoc.rb -->\n\n"
src = File.open("../module.c").to_a src = File.open(File.dirname(__FILE__) ++ "/../module.c").to_a
src.each_with_index{|line,i|
if line =~ /RM_/ && line[0] != ' ' && line[0] != '#' && line[0] != '/' # Build function index
if src[i-1] =~ /\*\// $index = {}
docufy(src,i) src.each_with_index do |line,i|
end if is_func_line(src, i)
line =~ /RM_([A-z0-9]+)/
name = "RedisModule_#{$1}"
$index[name] = true
end end
} end
# Print TOC
puts "## Sections\n\n"
src.each_with_index do |_line,i|
if is_section_doc(src, i)
name = get_section_heading(src, i)
puts "* [#{name}](\##{section_name_to_id(name)})\n"
end
end
puts "* [Function index](#section-function-index)\n\n"
# Docufy: Print function prototype and markdown docs
src.each_with_index do |_line,i|
if is_func_line(src, i)
docufy(src, i)
elsif is_section_doc(src, i)
section_doc(src, i)
end
end
# Print function index
puts "<span id=\"section-function-index\"></span>\n\n"
puts "## Function index\n\n"
$index.keys.sort.each{|x| puts "* [`#{x}`](\##{x})\n"}
puts "\n"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment