helpline 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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
+
@@ -0,0 +1,8 @@
1
+ var glossary = {
2
+ 'delete': '(消す|消去する|削除する)',
3
+ 'display': '(表示する|見る|リストする)',
4
+ 'change': '(変更|修正|編集|更新)',
5
+ 'modified': '(変更|修正|編集|更新)(された|があった)',
6
+ 'compare': '(比較する|比べる)'
7
+ }
8
+ module.exports = glossary
@@ -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
+
@@ -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