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.
- data/Changes +2530 -0
- data/bin/mklanghelp +50 -0
- data/data/langhelp/config.sample +889 -0
- data/files +39 -0
- data/graphviz-dot.jpg +0 -0
- data/langhelp.en.html +409 -0
- data/langhelp.en.rd +390 -0
- data/langhelp.ja.html +524 -0
- data/langhelp.ja.rd +487 -0
- data/lib/el4r/emacsruby/autoload/50langhelp.rb +2 -0
- data/lib/el4r/emacsruby/langhelp.rb +864 -0
- data/lib/el4r/emacsruby/test-langhelp.rb +300 -0
- data/lib/langhelp/langhelp-base.rb +649 -0
- data/lib/langhelp/langhelp-sub.rb +1023 -0
- data/lib/langhelp/lh_lua.rb +25 -0
- data/lib/langhelp/lh_perl.rb +112 -0
- data/lib/langhelp/lh_php.rb +34 -0
- data/lib/langhelp/lh_python.rb +31 -0
- data/lib/langhelp/lh_ruby.rb +400 -0
- data/lib/langhelp/mklanghelp.rb +140 -0
- data/lib/langhelp/parse-info.rb +145 -0
- data/ri.jpg +0 -0
- data/setup.rb +1551 -0
- data/test/a_classes.lst +2 -0
- data/test/a_methods.lst +2 -0
- data/test/b_classes.lst +2 -0
- data/test/b_methods.lst +2 -0
- data/test/c_methods.lst +4 -0
- data/test/common.rb +15 -0
- data/test/d_methods.lst +4 -0
- data/test/langhelp.e +566 -0
- data/test/ruby.e +3 -0
- data/test/tagify01-before.html +11 -0
- data/test/tagify02-before.html +11 -0
- data/test/test-base.rb +538 -0
- data/test/test-command.rb +92 -0
- data/test/test-parse-info.rb +175 -0
- data/test/test-ruby.rb +242 -0
- data/test/testdoc.rd +6 -0
- metadata +84 -0
@@ -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!(/ /, ' ')
|
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
|
+
" "*@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:
|