helpline 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/Makefile +44 -0
- data/README.md +8 -0
- data/Rakefile +6 -0
- data/_config.yml +1 -0
- data/curses.rb +106 -0
- data/data.js +273 -0
- data/exe/helpline +248 -0
- data/getdata.rb +94 -0
- data/getglossary.rb +31 -0
- data/glossary.js +8 -0
- data/helpline.css +54 -0
- data/helpline.gemspec +36 -0
- data/helpline.html +18 -0
- data/helpline.js +252 -0
- data/helpline.rb +248 -0
- data/index.html +300 -0
- data/keydef.zsh +14 -0
- data/lib/helpline.rb +5 -0
- data/lib/helpline/version.rb +3 -0
- data/main.js +123 -0
- data/package.json +43 -0
- data/stylesheets/github-light.css +116 -0
- data/stylesheets/normalize.css +424 -0
- data/stylesheets/stylesheet.css +245 -0
- metadata +113 -0
data/exe/helpline
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
require 'scrapbox'
|
8
|
+
require 're_expand'
|
9
|
+
|
10
|
+
require 'io/console'
|
11
|
+
require './curses'
|
12
|
+
|
13
|
+
puts
|
14
|
+
|
15
|
+
class HelpLine
|
16
|
+
LINES = 12
|
17
|
+
|
18
|
+
def datafile
|
19
|
+
File.expand_path("~/.helpline")
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@pagedata = {}
|
24
|
+
@project = Scrapbox::Project.new("HelpLine")
|
25
|
+
end
|
26
|
+
|
27
|
+
def getdata
|
28
|
+
#
|
29
|
+
# ページデータ取得
|
30
|
+
#
|
31
|
+
puts "-----------------ページデータを取得"
|
32
|
+
@project.pages.each { |title,page|
|
33
|
+
puts "...#{title}"
|
34
|
+
@pagedata[title] = page.text.split(/\n/)
|
35
|
+
}
|
36
|
+
|
37
|
+
dumpdata = {}
|
38
|
+
dumpdata['codes'] = []
|
39
|
+
dumpdata['defs'] = []
|
40
|
+
dumpdata['pages'] = []
|
41
|
+
|
42
|
+
#
|
43
|
+
# 関数/定数を評価"
|
44
|
+
#
|
45
|
+
puts "-----------------関数/定数を取得"
|
46
|
+
@pagedata.each { |title,pagedata|
|
47
|
+
puts "...#{title}"
|
48
|
+
pagedata. each { |line|
|
49
|
+
if line =~ /code:(.*\.rb)$/ then
|
50
|
+
src = $1
|
51
|
+
puts "=========== #{src}"
|
52
|
+
page = Scrapbox::Page.new(@project,title)
|
53
|
+
dumpdata['codes'] << page.code(src)
|
54
|
+
end
|
55
|
+
}
|
56
|
+
}
|
57
|
+
puts "-----------------HelpLineデータを検出"
|
58
|
+
@pagedata.each { |title,pagedata|
|
59
|
+
puts "...#{title}"
|
60
|
+
dumpdata['pages'] << title
|
61
|
+
processing_defs = false
|
62
|
+
codeindent = nil
|
63
|
+
pagedata.each { |line|
|
64
|
+
if !codeindent
|
65
|
+
if line =~ /^(\s*)code:/
|
66
|
+
codeindent = $1.length
|
67
|
+
next
|
68
|
+
end
|
69
|
+
else
|
70
|
+
line =~ /^(\s*)/
|
71
|
+
if line.length < codeindent
|
72
|
+
codeindent = nil
|
73
|
+
else
|
74
|
+
next
|
75
|
+
end
|
76
|
+
end
|
77
|
+
if line =~ /^\s*[\$\%]/
|
78
|
+
puts line
|
79
|
+
if line =~ /^\%/ && !processing_defs
|
80
|
+
puts "'$'で始まる用例定義なしでコマンドを定義しようとしています"
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
dumpdata['defs'] << "#{line} {#{dumpdata['pages'].length-1}}"
|
84
|
+
processing_defs = true
|
85
|
+
else
|
86
|
+
processing_defs = false
|
87
|
+
end
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
File.open(datafile,"w"){ |f|
|
92
|
+
f.puts dumpdata.to_json
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def disp(list,sel)
|
97
|
+
Curses.move(0,0)
|
98
|
+
lines = list.length
|
99
|
+
lines = LINES if lines > LINES
|
100
|
+
(0...lines).each { |i|
|
101
|
+
Curses.move(i,0)
|
102
|
+
s = "[#{i}] #{list[i][0]}"
|
103
|
+
if i == sel
|
104
|
+
Curses.print_inverse s
|
105
|
+
else
|
106
|
+
Curses.print s
|
107
|
+
end
|
108
|
+
}
|
109
|
+
Curses.down
|
110
|
+
Curses.tol
|
111
|
+
end
|
112
|
+
|
113
|
+
def helpline
|
114
|
+
data = JSON.parse(File.read(datafile))
|
115
|
+
unless data['pages'] # データ型式変換があったので
|
116
|
+
getdata
|
117
|
+
data = JSON.parse(File.read(datafile))
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# 関数定義などをeval
|
122
|
+
#
|
123
|
+
data['codes'].each { |code|
|
124
|
+
eval code
|
125
|
+
}
|
126
|
+
|
127
|
+
g = ExpandRuby::Generator.new # re_expandのジェネレータ
|
128
|
+
|
129
|
+
#
|
130
|
+
# HelpLineエントリ
|
131
|
+
#
|
132
|
+
lines = []
|
133
|
+
data['defs'].each { |line|
|
134
|
+
if line =~ /^\s*\$\s*(.*)$/ # $....
|
135
|
+
lines << $1
|
136
|
+
elsif line =~ /^\s*\%\s*(.*)$/ # %....
|
137
|
+
cmd = $1
|
138
|
+
lines.each { |l|
|
139
|
+
desc = eval('"' + l + '"')
|
140
|
+
g.add desc.force_encoding('utf-8'), cmd.force_encoding('utf-8')
|
141
|
+
}
|
142
|
+
lines = []
|
143
|
+
end
|
144
|
+
}
|
145
|
+
|
146
|
+
# puts "GENERATE #{params.split('|').join(' ')} "
|
147
|
+
|
148
|
+
res = g.generate " #{ARGV.join(' ').sub(/\[/,'').sub(/\]/,'')} "
|
149
|
+
|
150
|
+
if res[0].length == 0
|
151
|
+
puts "ヘルプがみつかりません"
|
152
|
+
File.open("/tmp/helpline","w"){ |f|
|
153
|
+
f.puts ARGV.join(' ')
|
154
|
+
}
|
155
|
+
exit
|
156
|
+
end
|
157
|
+
|
158
|
+
listed = {}
|
159
|
+
list = res[0].find_all { |a| # 0 ambig
|
160
|
+
# a = ["現在の状況を表示する {56}", "git status {56}"], etc.
|
161
|
+
if listed[a[1]]
|
162
|
+
false
|
163
|
+
else
|
164
|
+
listed[a[1]] = true
|
165
|
+
end
|
166
|
+
}
|
167
|
+
|
168
|
+
#
|
169
|
+
# HelpLineメニュー表示し、カーソル移動で選択
|
170
|
+
#
|
171
|
+
|
172
|
+
help_number = {}
|
173
|
+
list.each_with_index { |entry,ind|
|
174
|
+
entry[0].sub!(/\s*{(\d*)}$/,'')
|
175
|
+
entry[1].sub!(/\s*{(\d*)}$/,'')
|
176
|
+
help_number[entry[0]] = $1.to_i
|
177
|
+
}
|
178
|
+
|
179
|
+
sel = 0
|
180
|
+
disp(list,sel)
|
181
|
+
|
182
|
+
inputchars = ''
|
183
|
+
while true
|
184
|
+
c = STDIN.getch
|
185
|
+
inputchars += c
|
186
|
+
|
187
|
+
if inputchars == "\e"
|
188
|
+
# process ESC
|
189
|
+
elsif inputchars[0] == "\e" && inputchars.length == 2
|
190
|
+
# 何もしない
|
191
|
+
elsif inputchars == "\x06" || inputchars == "\e[C"
|
192
|
+
# Curses.right
|
193
|
+
inputchars = ''
|
194
|
+
elsif inputchars == "\x02" || inputchars == "\e[D"
|
195
|
+
# Curses.left
|
196
|
+
inputchars = ''
|
197
|
+
elsif inputchars == "\x0e" || inputchars == "\e[B"
|
198
|
+
Curses.down
|
199
|
+
sel = (sel + 1) if sel < LINES-1
|
200
|
+
inputchars = ''
|
201
|
+
elsif inputchars == "\x10" || inputchars == "\e[A"
|
202
|
+
Curses.up
|
203
|
+
sel = sel - 1 if sel > 0
|
204
|
+
inputchars = ''
|
205
|
+
else
|
206
|
+
inputchars = ''
|
207
|
+
end
|
208
|
+
STDIN.flush
|
209
|
+
disp(list,sel)
|
210
|
+
|
211
|
+
exit if c== 'q' || c == "\x03"
|
212
|
+
|
213
|
+
if c == "\r" || c == "\n"
|
214
|
+
break
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
desc = list[sel.to_i][0]
|
219
|
+
cmd = list[sel][1]
|
220
|
+
|
221
|
+
Curses.print_inverse("「#{desc}」を実行")
|
222
|
+
puts " (ソース: http://scrapbox.io/HelpLine/#{data['pages'][help_number[desc]]})"
|
223
|
+
File.open("/tmp/helpline","w"){ |f|
|
224
|
+
f.puts cmd
|
225
|
+
}
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# is_repository = system 'git rev-parse --git-dir > /dev/null >& /dev/null'
|
230
|
+
# unless is_repository
|
231
|
+
# STDERR.puts "Gitレポジトリで実行して下さい"
|
232
|
+
# exit
|
233
|
+
# end
|
234
|
+
|
235
|
+
options = ARGV.getopts('u')
|
236
|
+
|
237
|
+
helpline = HelpLine.new
|
238
|
+
|
239
|
+
if !File.exist?(helpline.datafile) && !options['u']
|
240
|
+
puts "#{helpline.datafile}を作成します..."
|
241
|
+
helpline.getdata
|
242
|
+
end
|
243
|
+
|
244
|
+
if options['u'] then
|
245
|
+
helpline.getdata
|
246
|
+
else
|
247
|
+
helpline.helpline
|
248
|
+
end
|
data/getdata.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'scrapbox'
|
7
|
+
|
8
|
+
class GetData
|
9
|
+
PROJECT = "HelpLine"
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@pagedata = {}
|
13
|
+
@project = Scrapbox::Project.new(PROJECT)
|
14
|
+
end
|
15
|
+
|
16
|
+
def getdata
|
17
|
+
#
|
18
|
+
# ページデータ取得
|
19
|
+
#
|
20
|
+
STDERR.puts "-----------------#{PROJECT}のページデータを取得"
|
21
|
+
@project.pages.each { |title,page|
|
22
|
+
STDERR.puts "...#{title}"
|
23
|
+
@pagedata[title] = page.text.split(/\n/)
|
24
|
+
}
|
25
|
+
|
26
|
+
dumpdata = {}
|
27
|
+
dumpdata['codes'] = []
|
28
|
+
dumpdata['defs'] = []
|
29
|
+
dumpdata['pages'] = []
|
30
|
+
|
31
|
+
#
|
32
|
+
# 関数/定数を評価"
|
33
|
+
#
|
34
|
+
# puts "-----------------関数/定数を取得"
|
35
|
+
# @pagedata.each { |title,pagedata|
|
36
|
+
# puts "...#{title}"
|
37
|
+
# pagedata. each { |line|
|
38
|
+
# if line =~ /code:(.*\.rb)$/ then
|
39
|
+
# src = $1
|
40
|
+
# STDERR.puts "=========== #{src}"
|
41
|
+
# page = Scrapbox::Page.new(@project,title)
|
42
|
+
# dumpdata['codes'] << page.code(src)
|
43
|
+
# end
|
44
|
+
# }
|
45
|
+
# }
|
46
|
+
|
47
|
+
STDERR.puts "-----------------GitHelpデータを検出"
|
48
|
+
@pagedata.each { |title,pagedata|
|
49
|
+
STDERR.puts "...#{title}"
|
50
|
+
dumpdata['pages'] << title
|
51
|
+
processing_defs = false
|
52
|
+
codeindent = nil
|
53
|
+
pagedata.each { |line|
|
54
|
+
if !codeindent
|
55
|
+
if line =~ /^(\s*)code:/
|
56
|
+
codeindent = $1.length
|
57
|
+
next
|
58
|
+
end
|
59
|
+
else
|
60
|
+
line =~ /^(\s*)/
|
61
|
+
if line.length < codeindent
|
62
|
+
codeindent = nil
|
63
|
+
else
|
64
|
+
next
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# if line =~ /^\s*[\$\%]/
|
68
|
+
if line =~ /^[\$\%]/
|
69
|
+
STDERR.puts line
|
70
|
+
if line =~ /^\%/ && !processing_defs
|
71
|
+
STDERR.puts "'$'で始まる用例定義なしでコマンドを定義しようとしています"
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
dumpdata['defs'] << "#{line} {#{dumpdata['pages'].length-1}}"
|
75
|
+
processing_defs = true
|
76
|
+
else
|
77
|
+
processing_defs = false
|
78
|
+
end
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
File.open("/tmp/tmp.json","w"){ |f|
|
83
|
+
f.puts dumpdata.to_json
|
84
|
+
}
|
85
|
+
system "jq . < /tmp/tmp.json > /tmp/tmp1.json"
|
86
|
+
|
87
|
+
puts "var data = "
|
88
|
+
puts File.read("/tmp/tmp1.json")
|
89
|
+
puts "module.exports = data"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
getdata = GetData.new
|
94
|
+
getdata.getdata
|
data/getglossary.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'scrapbox'
|
5
|
+
|
6
|
+
PROJECT = "HelpLine"
|
7
|
+
|
8
|
+
project = Scrapbox::Project.new(PROJECT)
|
9
|
+
page = Scrapbox::Page.new(project,'Glossary')
|
10
|
+
data = {}
|
11
|
+
page.text.split(/\n/).each { |line|
|
12
|
+
line.chomp!
|
13
|
+
if line =~ /^(\S+):\s*(.*)$/
|
14
|
+
if $1 != 'code' # code: は除く
|
15
|
+
data[$1] = $2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
}
|
19
|
+
|
20
|
+
defs = []
|
21
|
+
puts "var glossary = {"
|
22
|
+
data.each { |key,val|
|
23
|
+
defs << " '#{key}': '#{val}'"
|
24
|
+
}
|
25
|
+
puts defs.join(",\n")
|
26
|
+
puts "}"
|
27
|
+
puts "module.exports = glossary"
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
data/glossary.js
ADDED
data/helpline.css
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
/*
|
2
|
+
CommandLineHelp候補表示ウィンドウ
|
3
|
+
*/
|
4
|
+
body {
|
5
|
+
margin:0;
|
6
|
+
padding:2px;
|
7
|
+
background-color: #eee;
|
8
|
+
}
|
9
|
+
.icon {
|
10
|
+
width:16pt;
|
11
|
+
vertical-align:bottom;
|
12
|
+
}
|
13
|
+
code {
|
14
|
+
display:inline-block;
|
15
|
+
font-size:10pt;
|
16
|
+
color: #fff;
|
17
|
+
background-color: #444;
|
18
|
+
margin:2px 2px 2px 0px;
|
19
|
+
padding: 4px;
|
20
|
+
border-radius:4px;
|
21
|
+
box-shadow: 1px 1px 1px 1px rgba(0,0,0,0.4);
|
22
|
+
}
|
23
|
+
code:hover {
|
24
|
+
background-color: #777;
|
25
|
+
}
|
26
|
+
span.title {
|
27
|
+
font-family:'Lucida Grande', 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', Meiryo, メイリオ, sans-serif;
|
28
|
+
font-size: 10pt;
|
29
|
+
font-weight: bold;
|
30
|
+
color: #000;
|
31
|
+
background-color: #fff;
|
32
|
+
margin: 5px 0px 5px 0px;
|
33
|
+
padding: 4px;
|
34
|
+
}
|
35
|
+
span.title:hover {
|
36
|
+
background-color: #ccc;
|
37
|
+
}
|
38
|
+
#query {
|
39
|
+
font-size: 12pt;
|
40
|
+
margin: 3pt;
|
41
|
+
}
|
42
|
+
#candidates {
|
43
|
+
padding: 1px;
|
44
|
+
}
|
45
|
+
.entry {
|
46
|
+
background-color: #fff;
|
47
|
+
margin: 2pt;
|
48
|
+
padding: 2pt;
|
49
|
+
}
|
50
|
+
.entry:hover {
|
51
|
+
background-color: #008;
|
52
|
+
}
|
53
|
+
|
54
|
+
|
data/helpline.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "helpline/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "helpline"
|
8
|
+
spec.version = Helpline::VERSION
|
9
|
+
spec.authors = ["Toshiyuki Masui"]
|
10
|
+
spec.email = ["masui@pitecan.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{HelpLine - show command help menu from keywords.}
|
13
|
+
spec.description = %q{HelpLine - show command help menu from keywords, using ExpandHelp.}
|
14
|
+
spec.homepage = "https://masui.github.io/HelpLine/"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
#if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
+
#else
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
# "public gem pushes."
|
24
|
+
#end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features)/})
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
36
|
+
end
|