Builds the manual without Jekyll.

This commit is contained in:
Simon Kågedal Reimer 2015-03-10 23:59:06 +01:00
parent d24eddd604
commit 0d0a1048b8
5 changed files with 232 additions and 267 deletions

View File

@ -56,6 +56,7 @@ page_title: The Ardour Manual
<div id="content-main">
<h1 class="title">{{ page.title }}</h1>
{{ content }}
{% prevnext %}
</div>
</div>
</div>

View File

@ -1,262 +0,0 @@
require 'erb'
require 'fileutils'
require 'tmpdir'
require 'pp'
module Manual
DIRECTORY_ENTRIES = {}
def self.traverse_data(entries, directory_sort = false, paths = [], key_paths = [], &block)
entries.map do |entry|
entry = entry.dup
if entry[:type] == 'directory'
entry[:children] = traverse_data(entry[:children], directory_sort, paths + [entry[:name]], key_paths + [entry[:key]], &block)
end
block_given? ? block.call(entry) : entry
end
end
def self.traverse(path, directory_sort = false, paths = [], key_paths = [], &block)
entries = Dir.glob(File.join(path,'*')).sort
entries.sort_by! { |e| File.directory?(e) ? 1 : 0 } if directory_sort
entries.map do |entry|
is_dir = File.directory?(entry)
data = extract_data(is_dir ? "#{entry}.html" : entry)
short_title = data['menu_title'] || data['title']
name = entry[/[^\/]+$/] # filename
key = name.sub(/^[0-9]+(\-|_)/,'').sub(/\.[^\.]+$/,'') # slug
my_paths = paths + [name]
my_key_paths = key_paths + [key]
url = '/' + my_key_paths.join('/') + '/'
without_extension = entry.sub(/\.[^\/\/]+$/,'')
h = {
name: name,
title: data['title'] || key,
menu_title: short_title || key,
key: key,
filename: entry,
type: is_dir ? 'directory' : 'file',
url: url
}
if is_dir
h.update \
children: traverse(entry, directory_sort, my_paths, my_key_paths, &block)
else
h.update extension: File.extname(name), has_dir: File.directory?(without_extension)
end
if is_dir
DIRECTORY_ENTRIES[url] = h
end
block_given? ? block.call(h) : h
end.compact
end
def self.extract_data(filename)
if File.exists?(filename) and !File.directory?(filename) and first3 = File.open(filename) { |fd| fd.read(3) } and first3 == '---'
blah = filename.sub(/^_manual\//,'')
page = Jekyll::Page.new(@site, '_manual', File.dirname(blah), File.basename(blah))
page.data
else
{}
end
end
class ManualPage < Jekyll::Page
def initialize(*args)
super
end
end
class ManualGenerator < Jekyll::Generator
safe true
def generate(site)
source = site.config['source']
destination = site.config['destination']
manual_dir = '_manual'
# now we need to turn our raw input files into something for jekyll to process
# everything is in a directory with it's name and all content is in index.html files
# the tmpdir gets removed at the end of this block automatically
Dir.mktmpdir do |tmpdir|
Manual.traverse manual_dir, true do |entry|
output_filename = File.join(tmpdir, entry[:url], "index#{entry[:extension]}")
FileUtils.mkdir_p File.dirname(output_filename)
next unless entry[:type] == 'file'
File.open(output_filename, 'w+') do |f|
f << File.read(entry[:filename])
end
relative_filename = File.join(entry[:url], "index#{entry[:extension]}")
site.pages << Jekyll::Page.new(site, tmpdir, File.dirname(relative_filename), File.basename(relative_filename))
end
end
end
end
class ManualChildPageTag < Liquid::Tag
def render(context)
current = context['page.url'].sub(/[^\/]+$/,'')
if entry = DIRECTORY_ENTRIES[current]
path = File.join(entry[:filename], '*')
entries = entry[:children].map do |child|
"<li><a href='#{child[:url]}'>#{child[:title]}</a></li>"
end.uniq
"<div id='subtopics'>
<h2>This chapter covers the following topics:</h2>
<ul>
#{entries.join}
</ul>
</div>
"
end
end
end
# generates a big <dl> list of the manual page stucture
class ManualTOCTag < Liquid::Tag
def process_hierarchy(items_a, items_b)
current = true
position = nil
level = -1
[items_a.length,items_b.length].max.times do |i|
a = items_a[i]
b = items_b[i]
current = false if a != b
# start incrementing this when we don't have either a or b
level += 1 if !a || !b
if a && b
return [false] if a != b
elsif a
position = :parent
elsif b
position = :child
end
end
position ? [current, position, level + 1] : [current]
end
def render(context)
@source = '_manual' #context.registers[:site].source
@@data_tree ||= Manual.traverse(@source)
@site = context.registers[:site]
current = context['page.url'].sub(/[^\/]+$/,'')
current_a = current.split('/').reject(&:empty?)
tree = Manual.traverse_data(@@data_tree) do |entry|
url = entry[:url]
url_a = url.split('/').reject(&:empty?)
depth = url_a.length
is_current, position, level = *process_hierarchy(current_a, url_a)
# this massively speeds up build time by not including the whole menu tree for each page
next if depth > 1 && current_a[0] != url_a[0]
css_classes = []
css_classes << 'active' if is_current
css_classes << position.to_s if position
css_classes << "#{position}-#{level}" if position && level
css_classes << 'other' unless is_current || position || level
css_classes << "level-#{depth}"
css_classes = css_classes.join(' ')
if entry[:type] == 'directory'
erb = ::ERB.new <<-HTML
<dt class="<%= css_classes %>">
<a href="<%= entry[:url] %>"><%= entry[:menu_title] %></a>
</dt>
<dd class="<%= css_classes %>">
<% if entry[:children].any? %>
<dl>
<%= entry[:children].join %>
</dl>
<% end %>
</dd>
HTML
erb.result(binding)
else
directory_filename = entry[:filename].sub(/\.[^\/\.]+$/,'')
unless entry[:has_dir]
erb = ::ERB.new <<-HTML
<dt class="<%= css_classes %>">
<a href="<%= entry[:url] %>"><%= entry[:menu_title] %></a>
</dt>
<dd class="<%= css_classes %>">
</dd>
HTML
erb.result(binding)
end
end
end
"<dl>#{tree.join}</dl>
<script type='text/javascript'>
//<![CDATA[
offset = document.getElementsByClassName('active')[0].offsetTop;
height = document.getElementById('tree').clientHeight;
if (offset > (height * .7)) {
tree.scrollTop = offset - height * .3;
}
//]]>
</script>"
end
end
end
Liquid::Template.register_tag('tree', Manual::ManualTOCTag)
Liquid::Template.register_tag('children', Manual::ManualChildPageTag)

231
build.rb Normal file
View File

@ -0,0 +1,231 @@
require 'pathname'
require 'fileutils'
require 'yaml'
require 'liquid'
def split_frontmatter(txt)
re = /\A---[ \t\r]*\n(?<frontmatter>.*?)^---[ \t\r]*\n(?<content>.*)\z/m
match = re.match txt
match ? [match['frontmatter'], match['content']] : nil
end
def child_url?(a, b)
a.start_with?(b) && b.count('/') + 1 == a.count('/')
end
class Site
attr_reader :pages
def initialize()
@pages = []
@config = {
'pages_dir' => '_manual',
'layouts_dir' => '_layouts',
'static_dir' => 'source',
'output_dir' => '_site'
}
@layouts = {}
end
def read_layouts()
layouts_dir = Pathname(@config['layouts_dir'])
Pathname.glob(layouts_dir + Pathname('*.html')) do |path|
next if !path.file?
layout = Layout.new(self, path)
layout.read
@layouts[path.basename('.html').to_s] = layout
end
end
def find_layout(name)
@layouts[name]
end
def read_pages()
pages_dir = Pathname.new(@config['pages_dir'])
pages_dir.find do |path|
if path.file? && path.extname == '.html'
page = Page.new(self, path)
page.read
@pages << page
end
end
end
def find_children(url)
@pages.select{ |p| child_url?(p.url, url) }.sort_by{ |p| p.path.basename }
end
def process_pages()
@pages.each {|page| page.process}
end
def copy_static()
# http://ruby-doc.org/stdlib-2.2.1/libdoc/fileutils/rdoc/index.html
end
def pages_dir()
Pathname(@config['pages_dir'])
end
def output_dir()
Pathname(@config['output_dir'])
end
def run()
#read_config()
read_layouts()
read_pages()
copy_static()
process_pages()
end
end
class Page
attr_reader :path, :out_path, :url, :sort_url
def initialize(site, path)
@site = site
@path = path
canon = canonical
@out_path = @site.output_dir + canon + Pathname("index.html")
@url = '/' + canon + '/'
@sort_url = @path.to_s.sub(/\.html$/, '')
end
def canonical()
remove_numbers = lambda {|x| x.sub(/^[0-9]*[-_]/, '') }
path = @path.relative_path_from(@site.pages_dir)
a = path.each_filename.map(&remove_numbers)
a[-1] = a[-1].sub(/\.html$/, '')
a.join('/')
end
def related_to?(p)
# should we show p in the index on selfs page?
url.start_with?(p.url) || child_url?(url, p.url)
end
def title()
if !@page_context
puts 'nil page context: ' + @path.to_s
end
@page_context['title'] || ""
end
def read()
content = @path.read
split = split_frontmatter content
split || abort("Not a Jekyll-formatted file: #{@path}")
frontmatter, @content = split
@page_context = YAML.load(frontmatter)
@template = Liquid::Template.parse(@content)
end
def find_layout()
@site.find_layout(@page_context['layout'] || 'default')
end
def children()
@site.find_children(@url)
end
def render()
registers = {page: self, site: @site}
context = {'page' => @page_context}
content = @template.render!(context, registers: registers)
find_layout.render(context.merge({'content' => content}), registers)
end
def process()
path = out_path
path.dirname.mkpath
path.write(render)
end
end
class Layout < Page
def render(context, registers)
context = context.dup
context['page'] = @page_context.merge(context['page'])
content = @template.render!(context, registers: registers)
if @page_context.has_key?('layout')
find_layout.render(context.merge({'content' => content}), registers)
else
content
end
end
end
class Tag_tree < Liquid::Tag
def join(children_html)
children_html.empty? ? "" : "<dl>\n" + children_html.join + "</dl>\n"
end
def render(context)
current = context.registers[:page]
site = context.registers[:site]
format_entry = lambda do |page|
children = page.children
css = (page == current) ? ' class="active"' : ""
children_html = current.related_to?(page) ? join(children.map(&format_entry)) : ""
%{
<dt#{css}>
<a href='#{page.url}'>#{page.title}</a>
</dt>
<dd#{css}>
#{children_html}
</dd>
}
end
join(site.find_children('/').map(&format_entry))
end
end
class Tag_children < Liquid::Tag
def render(context)
children = context.registers[:page].children
entries = children.map {|p| "<li><a href='#{p.url}'>#{p.title}</a></li>" }
"<div id='subtopics'>
<h2>This chapter covers the following topics:</h2>
<ul>
#{entries.join}
</ul>
</div>
"
end
end
class Tag_prevnext < Liquid::Tag
def render(context)
site = context.registers[:site]
current = context.registers[:page]
pages = site.pages.sort_by{ |p| p.sort_url }
ind = pages.index { |page| page == current }
return '' if !ind
lnk = lambda do |p, cls, txt|
"<li><a title='#{p.title}' href='#{p.url}' class='#{cls}'>#{txt}</a></li>"
end
prev_link = ind > 0 ? lnk.call(pages[ind-1], "previous", " &lt; Previous ") : ""
next_link = ind < pages.length-1 ? lnk.call(pages[ind+1], "next", " Next &gt; ") : ""
"<ul class='pager'>#{prev_link}#{next_link}</ul>"
end
end
Liquid::Template.register_tag('tree', Tag_tree)
Liquid::Template.register_tag('children', Tag_children)
Liquid::Template.register_tag('prevnext', Tag_prevnext)
Liquid::Template.error_mode = :strict
Site.new.run

View File

@ -1,8 +1,3 @@
---
layout: default
title: Welcome to Ardour!
---
<html>
<head>
<meta http-equiv="refresh" content="0; url=/welcome-to-ardour/"/>