langhelp 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,300 @@
1
+
2
+ require 'fileutils'
3
+
4
+ class Object
5
+ def writef(filename)
6
+ open(File.expand_path(filename.to_s), "w"){|f| f.write(self.to_s)}
7
+ end
8
+ end
9
+
10
+
11
+
12
+ class TestLangHelp < Test::Unit::TestCase
13
+ load('langhelp.rb')
14
+
15
+ # User Setting Area
16
+ $w3m_el_path = "/usr/local/share/emacs/site-lisp/w3m/"
17
+ el_load "~/emacs/init.d/00init.el"
18
+ # /User Setting Area
19
+
20
+ add_to_list :load_path, $w3m_el_path
21
+ el_require :w3m
22
+
23
+ include LangHelp
24
+ def setup
25
+ @header = "/tmp/langhelpheader"
26
+ open(@header, "w"){}
27
+
28
+ @langhelp_home = File.expand_path("../../../test", File.dirname(File.expand_path(__FILE__)))
29
+ @langhelprc = Tempfile.path(<<-EOR)
30
+ # -*- ruby -*-
31
+ @LANGHELP_HOME = #{@langhelp_home.dump}
32
+ @HTML2TXT = "w3m -dump -T text/html"
33
+ @lang = {}
34
+ @aliases = {}
35
+ @lang["ruby"] = [
36
+ {:Ri => true},
37
+ ]
38
+ @aliases["ruby"] = %w[el4r]
39
+ @lang["hoge"] = {:HogeHelp => true, :cmd=>"echo"}
40
+ @lang["echo"] = {:Echo => true}
41
+ @lang["test-test0"] = {:Test0 => true}
42
+ @lang["concat"] = [ "hoge", "echo" ]
43
+
44
+ @occur_by_grep = true
45
+ EOR
46
+
47
+ # *.e must exist!
48
+
49
+ el4r.instance_eval do
50
+ def ruby_mode(*x) elvar.major_mode = :ruby_mode end
51
+ def el4r_mode(*x) elvar.major_mode = :el4r_mode end
52
+ def test_test0_mode(*x) elvar.major_mode = :test_test0_mode end
53
+ def concat_mode(*x) elvar.major_mode = :concat_mode end
54
+ def isearch_forward(*x) end
55
+ def winconf_push(*x) end
56
+ end
57
+
58
+ # *langhelp:x* buffer is empty in this test
59
+ # So ee-anchor-format must be set!
60
+ elvar.ee_anchor_format = "<<<%s>>>"
61
+
62
+ @x = LangHelp.run(:langhelprc=>@langhelprc)
63
+ end
64
+
65
+ def teardown
66
+ File.unlink(@header)
67
+ end
68
+
69
+ # TODO
70
+ # def test_concat
71
+ # Dir.chdir(@langhelp_home) do
72
+ # begin
73
+ # hoge = "content of hoge.e\n"
74
+ # echo = "content of echo.e\n"
75
+ # hoge.writef "hoge.e"
76
+ # echo.writef "echo.e"
77
+ # newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { concat_mode}
78
+ # langhelp
79
+ # assert_equal(hoge + echo, buffer_string)
80
+ # ensure
81
+ # FileUtils.rm_f %w[hoge.e echo.e]
82
+ # end
83
+ # end
84
+ # end
85
+
86
+ def test_newer
87
+ @x = LangHelpInternal.new(:major_mode=>"ruby", :datadir=>@langhelp_home)
88
+ @x.create_buffer
89
+ now = Time.now
90
+
91
+ # Header is older.
92
+ File.utime(now, now-100, @header)
93
+ assert_equal(false, @x.header_is_newer_than_buffer(@header))
94
+
95
+ # Header is newer.
96
+ File.utime(now, now+100, @header)
97
+ assert_equal(true, @x.header_is_newer_than_buffer(@header))
98
+ end
99
+
100
+ def assert_search(str)
101
+ goto_char 1
102
+ assert( search_forward(str, nil, true) )
103
+ end
104
+
105
+ def test_ruby
106
+ assert_instance_of(LangHelp, @x)
107
+
108
+ newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { ruby_mode}
109
+ langhelp
110
+ assert_equal("*langhelp:ruby*", buffer_name)
111
+ assert_search "lh-ri"
112
+
113
+ assert( fboundp(:lh_ri) )
114
+ assert( fboundp(:lh_hogehelp) )
115
+ end
116
+
117
+ def test_el4r
118
+ # alias test
119
+ assert_instance_of(LangHelp, @x)
120
+
121
+ newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { el4r_mode}
122
+ langhelp
123
+ assert_equal("*langhelp:ruby*", buffer_name)
124
+ assert_search "lh-ri"
125
+
126
+ assert( fboundp(:lh_ri) )
127
+ assert( fboundp(:lh_hogehelp) )
128
+ end
129
+
130
+
131
+ def test_test_test0
132
+ begin
133
+ e_file = File.join(@langhelp_home, "test-test0.e")
134
+ open(e_file,"w"){}
135
+ newbuf(:name=>"test0", :contents=>"", :display=>:pop) { test_test0_mode}
136
+ langhelp
137
+ assert_equal("*langhelp:test-test0*", buffer_name)
138
+
139
+ ensure
140
+ FileUtils.rm_f e_file
141
+ end
142
+
143
+ end
144
+
145
+ def test_lh_xxx
146
+ set_buffer lh_hogehelp("x")
147
+ assert_equal(`echo x`, buffer_string)
148
+
149
+ # default CMD == class.to_s.downcase
150
+ assert( fboundp :lh_echo )
151
+ set_buffer lh_echo("y")
152
+ assert_equal(`echo y`, buffer_string)
153
+
154
+ set_buffer lh_test0("z")
155
+ assert_equal("0\n", buffer_string)
156
+
157
+ end
158
+
159
+ def test_occur
160
+ newbuf(:name=>"*langhelp:hoge*", :contents=>"abc\ndef\nabc\n", :display=>:only)
161
+ langhelp_menu_mode
162
+ langhelp_occur "abc"
163
+ assert_equal "*langhelp occur /abc/*", buffer_name
164
+ assert_equal "abc\nabc\n", buffer_string
165
+ end
166
+
167
+ def test_index_buffer
168
+ langhelp_switch_to_index_buffer
169
+ assert_equal("*langhelp index*", buffer_name)
170
+ assert_search "lh-language-index"
171
+ end
172
+
173
+ def test_revert_buffer
174
+ newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { ruby_mode}
175
+ langhelp
176
+ assert_equal("*langhelp:ruby*", buffer_name)
177
+ assert_search "lh-ri"
178
+ let(:buffer_read_only, nil){ erase_buffer }
179
+ assert_equal 0, buffer_size
180
+ langhelp_revert_buffer
181
+ assert_search "lh-ri"
182
+ end
183
+
184
+ def xtest_face
185
+ # Because font-lock-mode is off at batch mode, this test fails.
186
+ # (view-efile "font-lock.el" " (when (or noninteractive")
187
+ let(:noninteractive, nil) do
188
+ newbuf(:name=>"yyyy", :contents=>"# (lh-foo \"\")\n", :display=>:only, :point=>6)
189
+ langhelp_menu_mode
190
+ font_lock_mode 1
191
+ assert_equal :langhelp_sexp_face, get_char_property(5, :face)
192
+
193
+ end
194
+ end
195
+
196
+ def test_default
197
+ assert get_buffer("*langhelp index*")
198
+ newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { fundamental_mode }
199
+ langhelp
200
+ assert_equal "*langhelp index*", buffer_name
201
+ end
202
+
203
+ def test_C_u
204
+ newbuf(:name=>"xxxx", :contents=>"", :display=>:pop) { ruby_mode }
205
+ langhelp 4
206
+ assert_equal "*langhelp index*", buffer_name
207
+ end
208
+
209
+ def test_info
210
+ lh_info "Distribution", "(emacs)Distrib"
211
+ with(:with_current_buffer, "*info*<langhelp>") do
212
+ assert_equal "Distrib", elvar.Info_current_node
213
+ assert_match /emacs$/, elvar.Info_current_file
214
+ end
215
+ end
216
+
217
+ # (lh-w3m nil "file:///home/rubikitch/src/langhelp/langhelp.en.html#Title:")
218
+ # (lh-w3m nil "file:///home/rubikitch/src/langhelp/langhelp.en.html#1")
219
+ def test_w3m_label
220
+ begin
221
+ html = File.expand_path "../../../langhelp.en.html", Dir.scriptdir
222
+ url = "file://#{html}#Title:"
223
+ lh_w3m nil, url
224
+ with(:with_current_buffer, "*w3m*") do
225
+ assert_match /Title:/, thing_at_point(:line)
226
+ end
227
+
228
+ # reuse the *w3m* buffer when URL is same
229
+ url = "file://#{html}#1"
230
+ lh_w3m nil, url
231
+ with(:with_current_buffer, "*w3m*") do
232
+ assert_match /1 /, thing_at_point(:line)
233
+ end
234
+
235
+ assert_equal 1, length(w3m_list_buffers)
236
+
237
+ ensure
238
+ kill_buffer "*w3m*"
239
+ end
240
+
241
+ end
242
+
243
+ def test_lh_to
244
+ contents = <<XXX
245
+
246
+ == Foo ==
247
+ foo
248
+ == Bar ==
249
+ bar
250
+ XXX
251
+ newbuf(:name=>"xxxx", :contents=>contents) do
252
+ make_local_variable :ee_anchor_format
253
+ elvar.ee_anchor_format = "== %s =="
254
+ lh_to "Bar"
255
+ beginning_of_line
256
+ assert looking_at("^== Bar ==")
257
+ end
258
+
259
+ end
260
+
261
+ def _test_langhelp_narrow_to_section(line, result, contents)
262
+ newbuf(:name=>"xxxx", :contents=>contents) do
263
+ goto_line line
264
+ langhelp_narrow_to_section
265
+ assert_equal result, buffer_string
266
+ end
267
+ end
268
+
269
+ def test_langhelp_narrow_to_section
270
+ contents = <<XXX
271
+ <<< zero >>>
272
+ <<< one >>>
273
+ ONE
274
+ <<< two >>>
275
+ TWO
276
+ XXX
277
+
278
+ zero = <<XXX
279
+ <<< zero >>>
280
+ XXX
281
+
282
+ one = <<XXX
283
+ <<< one >>>
284
+ ONE
285
+ XXX
286
+
287
+ two = <<XXX
288
+ <<< two >>>
289
+ TWO
290
+ XXX
291
+
292
+ _test_langhelp_narrow_to_section 1, zero, contents
293
+ _test_langhelp_narrow_to_section 2, one, contents
294
+ _test_langhelp_narrow_to_section 3, one, contents
295
+ _test_langhelp_narrow_to_section 4, two, contents
296
+ _test_langhelp_narrow_to_section 5, two, contents
297
+
298
+ end
299
+
300
+ end
@@ -0,0 +1,649 @@
1
+ #
2
+ # langhelp-base.rb - Create langhelp index of various languages
3
+ # Copyright (C) 2005 rubikitch <rubikitch@ruby-lang.org>
4
+ # Version: $Id: langhelp-base.rb 1383 2006-09-21 07:24:26Z rubikitch $
5
+
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require 'fileutils'
19
+ require 'tempfile'
20
+ require 'uri'
21
+ require 'cgi'
22
+ require 'kconv'
23
+ require 'zlib'
24
+
25
+ # begin require 'rubygems'; rescue LoadError; 0 end
26
+ # require 'hpricot'
27
+
28
+ module LocalVariables
29
+ ANCHOR_BEGIN = "<<<"
30
+ ANCHOR_END = ">>>"
31
+
32
+ def insert_local_variables(out)
33
+ out << "Local" << " Variables:\n"
34
+ out << "mode: langhelp-menu\n"
35
+ out << "truncate-lines: t\n"
36
+ out << "tab-width: 75\n"
37
+ out << "ee-anchor-format: \"#{ANCHOR_BEGIN}%s#{ANCHOR_END}\"\n"
38
+ out << "End:\n"
39
+ end
40
+ end
41
+
42
+ Zlib::GZIP_MAGIC = "\037\213"
43
+ def File.zread(file)
44
+ Object.module_eval do
45
+ open(file) do |f|
46
+ magic = f.read(2)
47
+ if magic == Zlib::GZIP_MAGIC
48
+ f.rewind
49
+ gz = Zlib::GzipReader.new(f)
50
+ begin
51
+ gz.read
52
+ ensure
53
+ gz.close
54
+ end
55
+ else
56
+ magic + f.read
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ module FilenameString
63
+ # Expand filenames
64
+ def normalize_filename!(*filenames)
65
+ if $langhelp_home
66
+ filenames.each do |filename|
67
+ filename.replace File.expand_path(filename, $langhelp_home)
68
+ end
69
+ end
70
+ end
71
+
72
+ def abbreviate_filename!(filename)
73
+ if $langhelp_home
74
+ re = Regexp.new("^"+Regexp.quote($langhelp_home)+"/?")
75
+ filename.sub!(re, '')
76
+ end
77
+ filename
78
+ end
79
+
80
+ def abbreviate_filename(filename)
81
+ abbreviate_filename!(filename.dup)
82
+ end
83
+
84
+ end
85
+
86
+ module EmacsLispString
87
+ def lisp_dump_string(string)
88
+ dumped = string.dup
89
+ # \ -> \\
90
+ dumped.gsub! %r"\\" do '\\\\' end
91
+ # " -> \"
92
+ dumped.gsub! %r'"' do '\\"' end
93
+ # (zero byte) -> \0
94
+ dumped.gsub! %r'\0' do "\\\0" end
95
+ %Q'"#{dumped}"'
96
+ end
97
+ end
98
+
99
+ module GeneratedMessage
100
+ include FilenameString
101
+
102
+ def processing(lang)
103
+ $stderr.puts "Processing #{lang} ..."
104
+ end
105
+
106
+ def generated(filename)
107
+ $stderr.puts "Generated #{abbreviate_filename(filename)} (size=#{File.size(filename)})"
108
+ end
109
+ end
110
+
111
+ module KanjiConverter
112
+ KCONVERTERS = {
113
+ :none => lambda{|s| s},
114
+ :euc_jp => lambda{|s| $KCODE='e'; s.toeuc },
115
+ :sjis => lambda{|s| $KCODE='s'; s.tosjis },
116
+ :utf8 => lambda{|s| $KCODE='u'; s.toutf8 },
117
+ }
118
+
119
+
120
+ def encoding
121
+ conf ? conf[:ENCODING] : :none
122
+ end
123
+
124
+ # Convert kanji code according to encoding()
125
+ def kconv(&block)
126
+ KCONVERTERS[encoding()][yield]
127
+ end
128
+ end
129
+
130
+ module MkArray
131
+ # Make an Array
132
+ def mkarray(obj)
133
+ if Array === obj
134
+ obj
135
+ else
136
+ [obj]
137
+ end
138
+ end
139
+ end
140
+
141
+ # Abstract class of information index
142
+ class AbstractIndex
143
+ SPACES = "\t"
144
+
145
+ include EmacsLispString
146
+
147
+ def initialize(x={})
148
+ @title = x[:title]
149
+ @arg1 = x[self.class.to_s.intern]
150
+ @conf = x[:conf]
151
+ init x
152
+ end
153
+
154
+ # Initialize for subclass.
155
+ # Do not process files! only do initialization.
156
+ def init(x={})
157
+ end
158
+
159
+ # 1st parameter ie. the key is a symbol of class name
160
+ attr :arg1
161
+
162
+ # Hash specified by configuration file.
163
+ attr_accessor :conf
164
+
165
+ # The title of the index.
166
+ attr_accessor :title
167
+
168
+ include MkArray
169
+ include KanjiConverter
170
+ include FilenameString
171
+ include LocalVariables
172
+ def output_title(io)
173
+ if title
174
+ io.puts "#### #{ANCHOR_BEGIN}#{title}#{ANCHOR_END} ####"
175
+ end
176
+ end
177
+
178
+ # Dump into e-script
179
+ def to_e(io)
180
+ end
181
+ end
182
+
183
+ # Abstract class of a hyperlink to a file.
184
+ class AbstractLink < AbstractIndex
185
+ def init(x={})
186
+ @src = arg1
187
+ @label = x[:label]
188
+ end
189
+
190
+ # Hyperlink EmacsLisp function. ie. lh-xxx
191
+ def func
192
+ end
193
+
194
+ # Dump into e-script
195
+ def to_e(io)
196
+ label = @label ? (@label + SPACES) : ""
197
+ io << %Q!# #{label}(#{func} nil #{lisp_dump_string(@src)})\n!
198
+ end
199
+ end
200
+
201
+ # A lh-view hyperlink to a file
202
+ class ViewLink < AbstractLink
203
+ def func() "lh-view" end
204
+ end
205
+
206
+ # A lh-w3m hyperlink to an HTML file.
207
+ class W3MLink < AbstractLink
208
+ def func() "lh-w3m" end
209
+ end
210
+
211
+ module StripTags
212
+ Q = /[\"\']?/
213
+ NQ = /[^\"\'> ]+/
214
+ ALT = /[^\"\'>]+/
215
+
216
+ def html2txt!(s)
217
+ s.gsub!(/<img .*?alt=#{Q}(#{ALT})#{Q}.*?>/imo, '\1')
218
+ s.gsub!(/<[^>]+>/,'')
219
+ s.gsub!(/&nbsp;/, ' ')
220
+ s.replace CGI.unescapeHTML(s)
221
+ s.gsub!(/\r?\n/,' ')
222
+ s.gsub!(/\s+/, ' ')
223
+ s
224
+ end
225
+
226
+ end
227
+
228
+ # Extract links from an HTML file, and create lh-w3m hyperlinks.
229
+ class W3MExtractLinks < AbstractIndex
230
+ def init(x={})
231
+ @html = arg1
232
+ normalize_filename! @html
233
+ @base = URI.parse("file://#{x[:base] || @html}")
234
+ @exclude_label = mkarray(x[:exclude_label])
235
+ @exclude_url = mkarray(x[:exclude_url])
236
+ end
237
+
238
+ Link = Struct.new :href, :label
239
+
240
+ include StripTags
241
+
242
+ def links
243
+ src = kconv{ File.read @html }
244
+ src.scan(%r!<a .*?href=#{Q}(#{NQ})#{Q}.*?>(.+?)</a>!imo).map {|href,label|
245
+ uri = @base.merge href
246
+ url = uri.to_s
247
+ path = uri.path
248
+ html2txt! label
249
+ next if @exclude_label.any?{|exclude| exclude === label}
250
+ next if @exclude_url.any?{|exclude| exclude === href}
251
+ abbreviate_filename! path
252
+ url = path if uri.scheme == 'file'
253
+ Link.new(url,label)
254
+ }.compact
255
+ end
256
+
257
+ def to_e(out)
258
+ links.each{|link|
259
+ out << %Q!# #{link.label}#{SPACES}(lh-w3m nil #{lisp_dump_string(link.href)})\n!
260
+ }
261
+
262
+ end
263
+ end
264
+
265
+ # Information index class by man
266
+ class Manpage < AbstractIndex
267
+ def init(x={})
268
+ if x[:manpath]
269
+ @manpath = x[:manpath]
270
+ @sections = arg1
271
+ @glob = x[:glob] || '*'
272
+ normalize_filename! *@manpath
273
+ extend Manpages
274
+ else
275
+ @section = x[:section].to_s
276
+ @name = arg1
277
+ @default_regexp = /^\S|^\s+\-/
278
+ @additional_regexp = x[:regexp]
279
+ extend ManpageIndex
280
+ end
281
+ end
282
+
283
+ # manipulate single manpage
284
+ module ManpageIndex
285
+ def man_contents
286
+ ENV['PAGER'] = 'cat'
287
+ kconv{ `man #{@section} #{@name} 2> /dev/null`.strip }
288
+ end
289
+
290
+ LINK = Struct.new :line
291
+ def links
292
+ man_contents()[1..-2].find_all{|line|
293
+ line =~ @default_regexp or (@additional_regexp and line =~ @additional_regexp)
294
+ }.map{|line|
295
+ LINK.new(line.chomp)
296
+ }
297
+ end
298
+
299
+ def to_e(io)
300
+ links.each{|link|
301
+ io << %Q!# (lh-man* #{lisp_dump_string(link.line)}\t"#{@section} #{@name}")\n!
302
+ }
303
+ end
304
+ end
305
+
306
+ # manipulate multiple manpages (It does not read manpage contents.)
307
+ module Manpages
308
+ Man = Struct.new :section, :man
309
+
310
+ def manpages
311
+ @sections.map {|section|
312
+ sectdir = "man#{section}"
313
+ @manpath.map {|dir|
314
+ if File.directory? dir
315
+ Dir[File.join(dir,sectdir,@glob)].map {|file|
316
+ man = File.basename(file).sub(/\.\d\w*(\.gz)?$/,'')
317
+ Man.new section, man
318
+ }
319
+ end
320
+ }
321
+ }.flatten.compact
322
+ end
323
+
324
+
325
+ def to_e(io)
326
+ manpages.each do |man|
327
+ io << %Q!# (lh-man "#{man.section} #{man.man}")\n!
328
+ end
329
+ end
330
+
331
+ end
332
+
333
+ end
334
+
335
+ # Common initialization of Grep/W3MGrep class.
336
+ module GrepInit
337
+ def init(x={})
338
+ if x[:regexp] # new version
339
+ @regexp = x[:regexp]
340
+ @src = arg1
341
+ else # deprecated
342
+ @regexp = arg1
343
+ @src = x[:src]
344
+ end
345
+ @exclude = mkarray(x[:exclude])
346
+ normalize_filename! @src
347
+ end
348
+ end
349
+
350
+ # Information index class by grep
351
+ class Grep < AbstractIndex
352
+ include GrepInit
353
+
354
+ # Dump into e-script
355
+ def to_e(io)
356
+ src = abbreviate_filename(@src)
357
+ kconv{ File.zread(@src) }.grep(@regexp).map{|line|
358
+ line.chomp!
359
+ next if @exclude.any?{|exclude| exclude === line }
360
+ io << %Q!# (lh-view #{lisp_dump_string(line)}#{SPACES}#{lisp_dump_string(src)})\n!
361
+ }
362
+ end
363
+ end
364
+
365
+ # Information index class by grep with w3m
366
+ class W3MGrep < AbstractIndex
367
+ include GrepInit
368
+
369
+ # Dump into e-script
370
+ def to_e(io)
371
+ # `#{conf[:HTML2TXT]} #{f.path}`.grep(@regexp).map{|line|
372
+ src = abbreviate_filename(@src)
373
+ kconv{ `w3m -dump #{@src.dump}` }.grep(@regexp).map{|line|
374
+ io << %Q!# (lh-w3m #{lisp_dump_string(line.chomp)}#{SPACES}#{lisp_dump_string(src)})\n!
375
+ }
376
+ end
377
+ end
378
+
379
+
380
+ # Information index class by HTML source
381
+ class HTMLIndex < AbstractIndex
382
+ def init(x={})
383
+ @spaces = x[:spaces] || 20
384
+ init_filename x
385
+ end
386
+
387
+ def init_filename(x)
388
+ if arg1 =~ /\.html$/
389
+ @index_page = arg1
390
+ @dir = File.dirname(@index_page)
391
+ else
392
+ @dir = x[:dir]
393
+ @index_page = x[:index_page]
394
+ end
395
+
396
+ normalize_filename! @dir, @index_page
397
+ end
398
+
399
+ def find_index
400
+ end
401
+ private :find_index
402
+
403
+ # number of spaces between label and sexp
404
+ def space
405
+ "&nbsp;"*@spaces
406
+ end
407
+
408
+ # overridden by subclass
409
+ def pre_process(html_src)
410
+ html_src
411
+ end
412
+
413
+ # overridden by subclass
414
+ def post_process(es_src)
415
+ es_src
416
+ end
417
+
418
+ # Dump into e-script
419
+ # pre_process -> HTML2TXT -> post_process
420
+ def to_e(out)
421
+ find_index unless @index_page
422
+ f = Tempfile.new("lh")
423
+
424
+ f.puts(pre_process(kconv{ File.read(@index_page) }))
425
+ f.close
426
+ out << post_process(kconv{ `#{conf[:HTML2TXT]} #{f.path}` })
427
+ end
428
+ end
429
+
430
+ class HTML < AbstractIndex
431
+
432
+ class Tag < Struct.new(:filename, :no, :content, :element)
433
+ def url
434
+ url = "file://" + File.expand_path(filename)
435
+ url << "##{no}" if no
436
+ url
437
+ end
438
+
439
+ include StripTags
440
+
441
+ def label
442
+ self.content = content.dup
443
+ html2txt! content
444
+ content.gsub! /\r?\n/, ' '
445
+ if element =~ /^<h([1-6])/i
446
+ header = " " + "="*$1.to_i + " "
447
+ elsif element =~ /^<dt/i
448
+ header = " : "
449
+ elsif element =~ /^<title/i
450
+ header = "Title: "
451
+ else
452
+ raise "cannot happen"
453
+ end
454
+ header + content
455
+ end
456
+ end
457
+
458
+ class Converter
459
+ include KanjiConverter
460
+ def initialize(x={})
461
+ @filename = x[:tagify_html]
462
+ @noconv = x[:noconv]
463
+ @recursive = x[:recursive]
464
+
465
+ @html_obj = x[:html_obj]
466
+ @conf = x[:conf]
467
+ end
468
+ attr :tags
469
+ attr :conf
470
+
471
+ # Chop meta-charset tag to avoid mojibake
472
+ def chop_meta_charset!(html)
473
+ html.sub!(/<meta[^>]*charset[^>]+>/mi,'')
474
+ end
475
+
476
+ include StripTags
477
+ def treat_recursive(html)
478
+ if @recursive == :next
479
+ if html =~ /<link[^>]*rel=#{Q}next#{Q}[^>]*href=#{Q}(#{NQ})#{Q}/o
480
+ uri = URI.parse("file://"+@original_filename)
481
+ return if $1 == ''
482
+ href = uri.merge($1)
483
+ @html_obj.add_html href.path
484
+ end
485
+ end
486
+ end
487
+
488
+ def _tagify(html)
489
+ no = "0001"
490
+ @tags = []
491
+
492
+ if @noconv
493
+ after = html.dup
494
+ else
495
+ after = html.toeuc
496
+ chop_meta_charset! after
497
+ end
498
+
499
+ treat_recursive after
500
+
501
+ if after =~ /(<title[^>]*>)(.+)<\/title>/
502
+ @tags << Tag.new(@filename, nil, $2, $1)
503
+ end
504
+
505
+ after.gsub!(%r!(<h[1-6][^>]*>)(.+?)(</h[1-6]>)|(<dt[^>]*>)(.+?)(</dt>|<dd)!im) {
506
+ hn, content_hn, hn_close, dt, content_dt, dt_close = Regexp.last_match.captures
507
+ begin
508
+ no_tag = %Q!<a name="#{no}"></a>!
509
+ if hn
510
+ @tags << Tag.new(@filename, no, content_hn, hn)
511
+ hn + no_tag + content_hn + hn_close
512
+ elsif dt
513
+ @tags << Tag.new(@filename, no, content_dt, dt)
514
+ dt + no_tag + content_dt + dt_close
515
+ else
516
+ raise "cannot happen!"
517
+ end
518
+ ensure
519
+ no = no.succ
520
+ end
521
+ }
522
+
523
+ if html =~ /\A<!-- Tagified by langhelp -->/
524
+ html
525
+ else
526
+ "<!-- Tagified by langhelp -->\n" + after
527
+ end
528
+ end
529
+ private :_tagify
530
+
531
+ def copy_and_set_filename_unless_writable
532
+ @original_filename = @filename
533
+ unless File.writable? @filename
534
+ newfile = "#{$langhelp_home}#{@filename}"
535
+ FileUtils.mkdir_p File.dirname(newfile)
536
+ FileUtils.rm_f newfile
537
+ FileUtils.cp @filename, newfile
538
+ FileUtils.chmod 0644, newfile
539
+ @filename = newfile
540
+ end
541
+ end
542
+
543
+
544
+ def tagify
545
+ # $stderr.puts "Tagifying #{@filename}..."
546
+ copy_and_set_filename_unless_writable
547
+ open(@filename, "rb+") do |f|
548
+ after = _tagify(kconv{ f.read })
549
+ f.rewind
550
+ f.write(after)
551
+ end
552
+ end
553
+ end
554
+
555
+ class SingleHTML < AbstractIndex
556
+ def init(x={})
557
+ @tagify_html = x[:tagify_html]
558
+ normalize_filename! @tagify_html
559
+ @converter = Converter.new x
560
+ end
561
+ attr :tagify_html
562
+
563
+ def tagify
564
+ @converter.tagify
565
+ end
566
+
567
+ def to_e(out)
568
+ tagify
569
+ @converter.tags.each do |tag|
570
+ out << %Q!# #{tag.label}#{SPACES}(lh-w3m nil "#{tag.url}")\n!
571
+ end
572
+ end
573
+
574
+ def ==(other)
575
+ return false if self.class != other.class
576
+ @tagify_html == other.tagify_html
577
+ end
578
+ end
579
+
580
+ def init(x={})
581
+ @x = x
582
+ @basedir = x[:basedir]
583
+ @recursive = x[:recursive]
584
+ @single_htmls = mkarray(x[:HTML]).flatten.map{|html|
585
+ html = File.join(@basedir, html) if @basedir
586
+ normalize_filename! html
587
+ Dir[html]
588
+ }.flatten.map{|html|
589
+ single_html_factory html
590
+ }
591
+ @additional_htmls = []
592
+ end
593
+
594
+ def single_html_factory(tagify_html)
595
+ SingleHTML.new @x.update(:tagify_html=>tagify_html, :html_obj=>self, :conf=>conf)
596
+ end
597
+ private :single_html_factory
598
+
599
+ def add_html(html)
600
+ obj = single_html_factory(html)
601
+ @additional_htmls << obj unless @additional_htmls.include? obj
602
+ end
603
+
604
+ def each_html(&block)
605
+ @single_htmls.each &block
606
+ @additional_htmls.each &block
607
+ end
608
+
609
+ def tagify
610
+ each_html {|single| single.tagify }
611
+ end
612
+
613
+ def to_e(out)
614
+ each_html {|single| single.to_e out }
615
+ end
616
+
617
+ end
618
+
619
+ # Composite: collects information indexes.
620
+ class Suite
621
+
622
+ def initialize(x={})
623
+ @debug_mode = x[:debug_mode]
624
+ @indexes = []
625
+ end
626
+
627
+ # Add a index to suite.
628
+ def <<(index)
629
+ @indexes << index
630
+ end
631
+
632
+ # Dump into e-script
633
+ def to_e(io)
634
+ @indexes.each do |index|
635
+ begin
636
+ index.output_title(io)
637
+ index.to_e(io)
638
+ rescue
639
+ $stderr.puts $!
640
+ $stderr.puts $@ if @debug_mode
641
+ $stderr.puts "Failed to write `#{index.title}'."
642
+ end
643
+ end
644
+ end
645
+ end
646
+
647
+ # Local Variables:
648
+ # test-script: "../../test/test-base.rb"
649
+ # End: