langhelp 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: