Skip to content

Commit

Permalink
Alternative web build with separated sections
Browse files Browse the repository at this point in the history
This patch adds the HTML version of the book. The initial version was
created by Edgard Schmidt based on the existing epub version. The work
was then refined and squashed into a single commit by Norman Feske.

- There is a dedicated section splitting tool with sed & sh
  (located at www/splitter/)
- A dummy chapter is added to each section, which is removed again
  during HTML generation
- The CSS adapts the content to all usual screen sizes and dimensions
- Images are linked
- Separate figure names and captions
- There is a generated main table of contents as well as a table of
  contents for each chapter
- Navigation bar on the top of each chapter and section
- API references are just links to header files instead of prettily
  formatted API descriptions

Issue #4
  • Loading branch information
3dik authored and nfeske committed May 22, 2019
1 parent 2566aef commit 072971c
Show file tree
Hide file tree
Showing 10 changed files with 740 additions and 34 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ manual/manual.pdf
manual/spec/repos
manual/spec/classes
manual/spec/class_index.mk
manual/www/chapters/
manual/www/html/
manual/www/img/
manual/www/sections/
manual/www/xrefs
manual/www/class_index
24 changes: 2 additions & 22 deletions manual/epub/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,7 @@ default: $(TARGET_EPUB)

$(HTML): xrefs

#
# Rules for converting TikZ figures to PNG images, invoked by 'epub_html.gosh'
#

img/%.tikz: ../img/%.tikz
cd img; ln -s ../../img/$*.tikz

img/%.pdf: img/%.tikz
make -C img $*.pdf

GS_DPI := 200

img/%-unscaled.png: img/%.pdf
gs -dNOPAUSE -dBATCH -sDEVICE=pngalpha -r$(GS_DPI) -sOutputFile=$@ $<

img/%.png: img/%-unscaled.png
convert -filter lanczos -resize 80% $< $@
include img.mk

#
# Rules for generating the table of contents
Expand Down Expand Up @@ -94,11 +78,7 @@ $(TARGET_EPUB): $(HTML) $(EPUB_SRC) Makefile
GENERATED_IMGS_LOG := $(wildcard img/*.log)
GENERATED_IMGS := $(GENERATED_IMGS_LOG:.log=)

clean_generated_imgs:
rm -f $(foreach suffix,.png .log .tikz .aux,$(addsuffix $(suffix),$(GENERATED_IMGS)))

clean: clean_generated_imgs
clean:
rm -f $(HTML)
rm -f $(TARGET_EPUB)
rm -f toc.ncx

280 changes: 268 additions & 12 deletions manual/epub/epub_html.gosh
Original file line number Diff line number Diff line change
@@ -1,22 +1,234 @@
source [get_style_file html]

set web_build [regexp {\--web-build} $argv dummy]
set basepath ""
regexp -- {\--basepath\s+([^\s]+)} $argv dummy basepath
set stylesheet ""
regexp -- {\--stylesheet\s+([^\s]+)} $argv dummy stylesheet
set main_index [regexp {\--main-index} $argv dummy]

#'unique-name' must be the name of the xref entry for the current document.
#
#The comparison is case-insensitive because we don't extract the exact names of
#chapters in the makefile. Thus, we abuse the filename structure of the
#original chapter txt files, whose filenames match their xref entry names when
#compared case-insensitively and when all spaces are replaced with underscores.
#So all spaces of a (pseudo) xref entry name must be replaced with underscores
#before it is passed to argument 'unique-name'.
#We get 'unique-name' from an argument instead of extracting it from the input
#filename in order to allow generic filenames or even process substitution.
set unique_name ""
regexp -- {\--unique-name\s+([^\s]+)} $argv dummy unique_name
set unique_name [string tolower $unique_name]

set repo_url ""
regexp -- {\--repo-url\s+([^\s]+)} $argv dummy repo_url

#stolen from xrefs code, compare html.gosh
set code_refs {}
if {[regexp -- {\--code-refs\s+([^\s]+)} $argv dummy code_refs_file]} {
set code_refs [split [exec cat $code_refs_file] "\n"]
}

proc print_html_label {label} {
printline "<a id=\"[label_html $label]\"></a>"
}


#find the first item in the list with the given nesting level
#If an item with a lower nesting level is found first or if no item with the
#wanted level is found at all, -1 is returned
proc first_with_level {list level} {
for {set i 0} {$i < [llength $list]} {incr i} {
set cur_level [nesting_level [lindex [lindex $list $i] 1]]
if {$cur_level == $level} {
return $i
}
if {$cur_level < $level} {
break
}
}
return -1
}


proc produce_xrefi_link { index } {
global html_xrefs basepath
set name [lindex [lindex $html_xrefs $index] 0]
set src [lindex [lindex $html_xrefs $index] 2]
puts "<a href=\"$basepath$src\">$name</a>"
}


#return the position of the currect document within $html_xrefs
proc get_doc_index {} {
global unique_name html_xrefs

set doc_index -1
for {set i 0} {$i < [llength $html_xrefs]} {incr i} {
set name [lindex [lindex $html_xrefs $i] 0]
set name [string map {" " "_"} [string tolower $name]]
if {$name == $unique_name} {
set doc_index $i
break
}
}
if {-1 == $doc_index} {
error "couldn't found: $unique_name"
}
return $doc_index
}


proc produce_navbar {} {
global html_xrefs basepath

set doc_index [get_doc_index]
set level [nesting_level [lindex [lindex $html_xrefs $doc_index] 1]]

puts "<nav class=\"arrow-bar\">"

set left [lrange $html_xrefs 0 [expr $doc_index - 1]]
set left_reversed [lreverse $left]
set previous [first_with_level $left_reversed $level]
if {-1 != $previous} {
puts "<span class=\"previous\">Previous:"
produce_xrefi_link [expr $doc_index - $previous - 1]
puts "</span>"
}

set right [lrange $html_xrefs [expr $doc_index + 1] end]
set next [first_with_level $right $level]
if {-1 != $next} {
puts "<span class=\"next\">Next:"
produce_xrefi_link [expr $doc_index + $next + 1]
puts "</span>"
}

set top [first_with_level $left_reversed [expr $level - 1]]
puts "<span class=\"top\">Top:"
if {-1 != $top} {
produce_xrefi_link [expr $doc_index - $top - 1]
} else {
set index "index.html"
puts "<a href='$basepath$index'>Table of Contents</a>"
}

puts </span></nav>
}


### WRITE HEADER OF HTML FILE ###
proc produce_head_html {} {
global title authors references toc_refs config_html_toc
global title authors references toc_refs config_html_toc basepath stylesheet
global web_build main_index html_xrefs

printline {<?xml version="1.0" encoding="UTF-8"?>}
printline {<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"}
printline { "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">}

printline {<html xmlns="http://www.w3.org/1999/xhtml">}
printline {<head><title>Genode OS Framework Foundations</title></head>}
set title "Genode OS Framework Foundations"
if {$web_build} {
set current "Table of contents"
if {!$main_index} {
set current [lindex $html_xrefs [get_doc_index] 0]
}
set title "$current - $title"
}
printline "<head><title>$title</title>"
if {"" != $stylesheet} {
set path "$basepath$stylesheet"
printline "<link rel=\"stylesheet\" type=\"text/css\" href=\"$path\"/>"
}
printline {</head>}
printline {<body>}
if { $web_build && !$main_index } {
produce_navbar
}
}


proc produce_tail_html {} {
global main_index html_xrefs web_build

if {!$web_build} {
} elseif {0 != $main_index} {
printline {<h1>Genode OS Framework Foundations</h1>}
printline {<h2>Table of Contents:</h2>}

produce_xrefs_linklist $html_xrefs "main-toc"
} else {
set content_list [lrange $html_xrefs [get_doc_index] end]
set level [nesting_level [lindex $content_list 0 1]]
if {0 eq $level} {
set content_list [lrange $content_list 1 end]
set last [first_with_level $content_list 0]
if {-1 ne $last} {
incr last -1
} else {
#0 is the lowest level. So -1 always implies that it's the last chapter
set last end
}
set content_list [lrange $content_list 0 $last]

puts "<h2>Content:</h2>"
produce_xrefs_linklist $content_list "chapter-toc"
}
}
printline {</body></html>}
}


proc nesting_level { name } {
set levels {"chapter" "section" "subsection"}
set level [lsearch $levels $name]
if { -1 eq $level } {
error "invalid level: $name"
}
return $level
}


proc produce_xrefs_linklist { list class } {
global basepath

set level -1
set initial_level -1

printline "<ol class=\"toc $class\">"
foreach xref $list {
set ref_name [lindex $xref 0]
set ref_type [lindex $xref 1]
set ref_target [lindex $xref 2]
set new_level [nesting_level $ref_type]
if {-1 == $level} {
set level $new_level
set initial_level $level
}

close_levels $level $new_level

if {0 < [expr $new_level - $level]} {
error "can't indent twice"
}
set url "$basepath$ref_target"
printline "<li><a class='$ref_type' href='$url'>$ref_name</a>"

#To simplify the loop, we always indent after each item so that we don't
#have to know if the current item has children.
puts "<ol>"
set level [expr $new_level + 1]
}
close_levels $level $initial_level
printline "</ol>"
}


proc close_levels {old new} {
for {set indent $old} {$indent > $new} {incr indent -1} {
puts "</ol></li>"
}
}


Expand All @@ -32,6 +244,7 @@ proc generate_png_from_tikz { tikz_name } {

### TIKZ IMAGE ###
proc process_tikz_html {txtblock} {
global basepath references

regexp {\[(tikz \w+.*)\]} [lindex $txtblock 0] dummy tikz_info
if {$tikz_info == ""} return
Expand All @@ -50,28 +263,71 @@ proc process_tikz_html {txtblock} {

#
# If no caption is provided, we insert the tikz image as is. If a caption
# is provided, we host the image along with its caption in a table.
# is provided, we host the image along with its caption in a fieldset. We use
# fieldset because its legend allows a pretty separation between the name and
# the caption of a figure.
#
set src "$basepath$tikz_name.png"
set image "<a href='$src'><img src='$src' alt='$tikz_name' /></a>"
if {$tikz_cap == ""} {
printline "<p><img src=\"$tikz_name.png\" alt=\"$tikz_name\"/></p>"
printline "<p class='direct-img'>$image</p>"
} else {
printline "<table class=\"captionedimage\"><tr><td>"
printline " <a id=\"[label_html $tikz_name]\"></a>"
printline " <img src=\"$tikz_name.png\" alt=\"$tikz_name\" />"
printline "</td></tr><tr><td>"
printline " <div class=\"caption\">$tikz_cap</div>"
printline "</td></tr></table>"
printline " <fieldset class='figure' id='[label_html $tikz_name]'>"
printline " <legend>Figure $references($tikz_name,index)</legend>"
printline " $image"
printline " <div class='caption'>$tikz_cap</div>"
printline " </fieldset>"
}
}

proc produce_code_ref { name path } {
global repo_url

puts "<p class='code-ref'><a href='$repo_url/$path'>$name</a></p>"
}

### RAW INCLUDE ###
proc process_rawinclude_html {txtblock} {
global code_refs

regexp {\[(raw \w+.*)\]} [lindex $txtblock 0] dummy raw_info
if {$raw_info == ""} return
set raw_name [lindex $raw_info 1]
if {![regexp {^spec/(.*)$} [lindex $raw_info 1] dummy spec_id]} {
error "only spec/ raw refs are supported"
}

if {[regexp {^(.*)\.overview$} $spec_id dummy path]} {
produce_code_ref $path $path
return
}

puts [exec cat $raw_name.html]
if {-1 ne [lsearch -exact {"clearpage" "nopagebreak"} $spec_id]} return
foreach ref $code_refs {
set id [lindex $ref 0]
set path [lindex $ref 1]
set name [lindex $ref 2]
if {$spec_id == "classes/$id/description"} {
produce_code_ref $name $path
return
}
}
error "could not found code ref: $spec_id"
}

#update base path for xref links
foreach xref $html_xrefs {
set ref_name [lindex $xref 0]
set ref_target [lindex $xref 2]

set references($ref_name,target) $basepath$ref_target
}

#By setting the ref type to 'image', the linktext of each tikz ref will be a
#simple index instead of the path to the PNG file, which improves the
#readability.
foreach ref [array names references -regex type$] {
if { "tikz" == $references($ref) } {
regexp {^([^,]+),} $ref dummy name
set references($name,type) image
}
}

0 comments on commit 072971c

Please sign in to comment.