Skip to content

Instantly share code, notes, and snippets.

@mooffie
Created December 1, 2015 10:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mooffie/7aa12b593e84f729ff07 to your computer and use it in GitHub Desktop.
Save mooffie/7aa12b593e84f729ff07 to your computer and use it in GitHub Desktop.
Permanent URLs for htags
#!/usr/bin/ruby
#
# Fixes htags' output so that files have fixed names. E.g., S/542.html -> D/whatever.c.h.
#
# It addresses the following problem:
#
# "Can htags create permanent addresses?"
# http://lists.gnu.org/archive/html/help-global/2015-11/msg00002.html
#
require 'fileutils'
require 'pp'
Encoding.default_external = "BINARY"
$base = '.' # Where the HTML is stored.
$verbose = false
$debug = false
$create_subdirs = false # Experimental feature. Doesn't really work.
# Bonus: highlight the target line.
$css = "
a:target {
position: absolute;
left: 0;
height: 1.35em;
width: 100%;
background: yellow;
opacity: .5;
z-index: -1000;
}
"
#
# Computes pretty names for files:
#
# '.../S/456.html' => 'S/modules/tty.c.html'
#
def prettyname(full_path, prefix, kind, nid, ext)
gist = nid
start = IO.read(full_path, 1024)
if start =~ /<title>(.*?)<\/title>/ then
gist = $1
gist.gsub!(%r{/+$}, '') # remove trailing '/'s.
if not $create_subdirs then
gist.gsub!('/', '--')
end
gist.gsub!(%r{[^a-zA-Z0-9_.,/-]}, '-') # clean special characters.
end
return kind + '/' + gist + ext
end
class Counter
class << self
def init(total)
@total = total
end
def reset()
@count = 0
end
def report()
print "[#{@count}/#{@total}]\r"
@count += 1
end
def finish()
puts
end
end
end
#
# Returns a table explaining how to rename the files. E.g.:
#
# {
# 'S/456.html' => 'S/modules/tty.c.html'
# ...
# }
#
def build_cnv_tbl()
Counter.reset()
cnv = {}
Dir[$base + '/{[A-Z],files}/*.html'].each do |full_path|
#p full_path
if full_path =~ /(.*)\/((\w+)\/(\d+)(\.\w+))$/ then
prefix = $1 # "/home/joe/.../HTML"
path = $2 # "S/323.html"
kind = $3 # "S"
nid = $4 # "323"
ext = $5 # ".html"
pretty = prettyname(full_path, prefix, kind, nid, ext)
cnv[path] = pretty
end
Counter.report()
end
Counter.finish()
return cnv
end
#
# Make all the substiutions inside the files:
#
# <a href='../S/456.html'> --> <a href='../S/modules/tty.c.html'>
# ...
#
def mksub(cnv)
Counter.reset()
Dir[$base + '/**/*.html'].each do |path|
kind = path[$base.length .. -1][/\w+/]
text = IO.read(path)
fixed = text.gsub(/(<a href='(?:..\/)?)([^'#]+)/) do |a|
prefix = $1
target = $2
if cnv[target] then
target = cnv[target]
elsif cnv[kind + '/' + target] then
# This is a relative link of the form: href='456.html'
if cnv[kind + '/' + target].match /\/(.*)/ # converts "s/whatever.html" to "whatever.html"
target = $1
end
end
prefix + target
end
# Fix a problem in Opera, where empty lines are squashed.
fixed.gsub!(%r{(<a id='L\d+' name='L\d+'></a>)\n}, "\\1 \n")
if text != fixed then
IO.write(path, fixed)
puts(path + " modified") if $debug
end
Counter.report()
end
Counter.finish()
end
#
# Rename the files.
#
def rename(cnv)
Counter.reset()
cnv.each do |a, b|
src = $base + '/' + a
trg = $base + '/' + b
if $create_subdirs then
FileUtils.mkdir_p(File.dirname(trg))
end
File.rename(src, trg)
Counter.report()
end
Counter.finish()
end
def better_css(css_path)
text = IO.read(css_path)
IO.write(css_path, text + $css)
end
def main()
if not File.exists?($base + '/help.html') then
$base += '/HTML'
if not File.exists?($base + '/help.html') then
puts "Error: This doesn't look like htags' output directory."
exit(1)
end
end
Counter.init( Dir[$base + '/**/*.html'].length )
puts "Figuring out pretty names..."
cnv = build_cnv_tbl()
pp cnv if $verbose
puts "Updating links in files..."
mksub(cnv)
puts "Renaming files..."
rename(cnv)
puts "Enhancing the css..."
better_css($base + '/style.css')
puts "Done."
end
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment