htagsfix 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #!/usr/bin/env ruby
  2. #
  3. # Fixes htags' output so that files have fixed names. E.g., S/542.html -> D/whatever.c.h.
  4. #
  5. # It addresses the following problem:
  6. #
  7. # "Can htags create permanent addresses?"
  8. # http://lists.gnu.org/archive/html/help-global/2015-11/msg00002.html
  9. #
  10. require 'fileutils'
  11. require 'pp'
  12. Encoding.default_external = "BINARY"
  13. $base = '.' # Where the HTML is stored.
  14. $verbose = false
  15. $debug = false
  16. $create_subdirs = false # Experimental feature. Doesn't really work.
  17. # Bonus: highlight the target line.
  18. $css = "
  19. a:target {
  20. position: absolute;
  21. left: 0;
  22. height: 1.35em;
  23. width: 100%;
  24. background: yellow;
  25. opacity: .5;
  26. z-index: -1000;
  27. }
  28. "
  29. #
  30. # Computes pretty names for files:
  31. #
  32. # '.../S/456.html' => 'S/modules/tty.c.html'
  33. #
  34. def prettyname(full_path, prefix, kind, nid, ext)
  35. gist = nid
  36. start = IO.read(full_path, 1024)
  37. if start =~ /<title>(.*?)<\/title>/ then
  38. gist = $1
  39. gist.gsub!(%r{/+$}, '') # remove trailing '/'s.
  40. if not $create_subdirs then
  41. gist.gsub!('/', '--')
  42. end
  43. gist.gsub!(%r{[^a-zA-Z0-9_.,/-]}, '-') # clean special characters.
  44. end
  45. return kind + '/' + gist + ext
  46. end
  47. class Counter
  48. class << self
  49. def init(total)
  50. @total = total
  51. end
  52. def reset()
  53. @count = 0
  54. end
  55. def report()
  56. print "[#{@count}/#{@total}]\r"
  57. @count += 1
  58. end
  59. def finish()
  60. puts
  61. end
  62. end
  63. end
  64. #
  65. # Returns a table explaining how to rename the files. E.g.:
  66. #
  67. # {
  68. # 'S/456.html' => 'S/modules/tty.c.html'
  69. # ...
  70. # }
  71. #
  72. def build_cnv_tbl()
  73. Counter.reset()
  74. cnv = {}
  75. Dir[$base + '/{[A-Z],files}/*.html'].each do |full_path|
  76. #p full_path
  77. if full_path =~ /(.*)\/((\w+)\/(\d+)(\.\w+))$/ then
  78. prefix = $1 # "/home/joe/.../HTML"
  79. path = $2 # "S/323.html"
  80. kind = $3 # "S"
  81. nid = $4 # "323"
  82. ext = $5 # ".html"
  83. pretty = prettyname(full_path, prefix, kind, nid, ext)
  84. cnv[path] = pretty
  85. end
  86. Counter.report()
  87. end
  88. Counter.finish()
  89. return cnv
  90. end
  91. #
  92. # Make all the substiutions inside the files:
  93. #
  94. # <a href='../S/456.html'> --> <a href='../S/modules/tty.c.html'>
  95. # ...
  96. #
  97. def mksub(cnv)
  98. Counter.reset()
  99. Dir[$base + '/**/*.html'].each do |path|
  100. kind = path[$base.length .. -1][/\w+/]
  101. text = IO.read(path)
  102. fixed = text.gsub(/(<a href='(?:..\/)?)([^'#]+)/) do |a|
  103. prefix = $1
  104. target = $2
  105. if cnv[target] then
  106. target = cnv[target]
  107. elsif cnv[kind + '/' + target] then
  108. # This is a relative link of the form: href='456.html'
  109. if cnv[kind + '/' + target].match /\/(.*)/ # converts "s/whatever.html" to "whatever.html"
  110. target = $1
  111. end
  112. end
  113. prefix + target
  114. end
  115. # Fix a problem in Opera, where empty lines are squashed.
  116. fixed.gsub!(%r{(<a id='L\d+' name='L\d+'></a>)\n}, "\\1 \n")
  117. if text != fixed then
  118. IO.write(path, fixed)
  119. puts(path + " modified") if $debug
  120. end
  121. Counter.report()
  122. end
  123. Counter.finish()
  124. end
  125. #
  126. # Rename the files.
  127. #
  128. def rename(cnv)
  129. Counter.reset()
  130. cnv.each do |a, b|
  131. src = $base + '/' + a
  132. trg = $base + '/' + b
  133. if $create_subdirs then
  134. FileUtils.mkdir_p(File.dirname(trg))
  135. end
  136. File.rename(src, trg)
  137. Counter.report()
  138. end
  139. Counter.finish()
  140. end
  141. def better_css(css_path)
  142. text = IO.read(css_path)
  143. IO.write(css_path, text + $css)
  144. end
  145. def main()
  146. if not File.exists?($base + '/help.html') then
  147. $base += '/HTML'
  148. if not File.exists?($base + '/help.html') then
  149. puts "Error: This doesn't look like htags' output directory."
  150. exit(1)
  151. end
  152. end
  153. Counter.init( Dir[$base + '/**/*.html'].length )
  154. puts "Figuring out pretty names..."
  155. cnv = build_cnv_tbl()
  156. pp cnv if $verbose
  157. puts "Updating links in files..."
  158. mksub(cnv)
  159. puts "Renaming files..."
  160. rename(cnv)
  161. puts "Enhancing the css..."
  162. better_css($base + '/style.css')
  163. puts "Done."
  164. end
  165. main()