hackercli 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 75c4a562ea1421cb25e6e931f248fe548dca1455
4
- data.tar.gz: 5eae9a7fae225f5466ce8c3e821cc3a438d72fad
3
+ metadata.gz: 0c4b0da9c2d3080b4e089e3e6cd067932ec532b2
4
+ data.tar.gz: 3eed3f9cb25b8d34123d2f5f3b243ca28b6d0c20
5
5
  SHA512:
6
- metadata.gz: ecaef63610e4e8337bd71b3073c71f979c50b00e2629c3528125844ca2c3bf4b0fc5dd7744b63855ec4315e8ac937f831cb1b48764dcd5e96289eca07a080648
7
- data.tar.gz: 0016e69972886d8ec5ed937019b48e326b2f56cfa3105bb31014ceab1c4e9b7d3538b5ef39e7402e90f5d843daabaab259b59d2329520f406e3589ab27afe837
6
+ metadata.gz: ba88a33dbf30d7a59a7b68a4edc88e8497bea305e96dc70d6f0faec143ba3b90407d7c26af92e2d6bce8937da7602343973c9dae963f08e9fa851ec02f466bea
7
+ data.tar.gz: 846fef7529f021b205d55165014eb75efb3e36ed50d30f43d90dd9b4d9fce8945ffcc16d24f364ea3c2f2bb5ee8f47ac6c683752588d227a1c23098beb8fd19c
@@ -42,6 +42,7 @@ class Bigrss
42
42
 
43
43
  resp = []
44
44
  filename = @options[:url]
45
+ ymlpath = @options[:ymlpath]
45
46
  page[:page_url] = filename
46
47
  now = Time.now
47
48
  page[:create_time_seconds] = now.to_i
@@ -55,6 +56,8 @@ class Bigrss
55
56
  content.gsub!(''',"'")
56
57
  content.gsub!('4','"')
57
58
  content = CGI.unescapeHTML(content)
59
+ # next line dirties current dir, does not respect path of yml
60
+ outfile = File.join(ymlpath, outfile) if ymlpath
58
61
  File.open("#{outfile}.rss","w") {|ff| ff.write(content) }
59
62
  items = content.scan(/<item>(.*?)<\/item>/)
60
63
  items.each_with_index do |e,i|
@@ -183,6 +186,7 @@ Usage: #{$0} [options]
183
186
  end
184
187
  opts.on("-y yml path", String,"--yml-path", "save as YML file") do |v|
185
188
  ymlfile = v
189
+ options[:ymlpath] = File.dirname(v)
186
190
  end
187
191
  #opts.on("-s SUBREDDIT", String,"--subreddit", "Get articles from subreddit named SUBREDDIT") do |v|
188
192
  #options[:subreddit] = v
@@ -5,7 +5,7 @@
5
5
  # Author: j kepler http://github.com/mare-imbrium/canis/
6
6
  # Date: 2014-08-09 - 10:12
7
7
  # License: MIT
8
- # Last update: 2014-08-11 21:30
8
+ # Last update: 2014-09-08 19:45
9
9
  # ----------------------------------------------------------------------------- #
10
10
  # hackman.rb Copyright (C) 2012-2014 j kepler
11
11
  # encoding: utf-8
@@ -13,401 +13,606 @@ require 'canis/core/util/app'
13
13
  require 'canis/core/util/rcommandwindow'
14
14
  require 'fileutils'
15
15
  require 'pathname'
16
+ require 'open3'
16
17
  require 'canis/core/include/defaultfilerenderer'
17
18
  require 'canis/core/include/appmethods'
18
19
 
19
20
  # TODO :
20
- # - add to forum list, remove, save
21
+ # - Make this a standard for other similar command line ncurses apps, like rigel. we can use
22
+ # this as a template for others.
23
+ # - make the menu a little more like the mc usermenu
24
+ # x change location of data cache, hacker-cli to also use the same for rss file saving
25
+ # x make color schemes into a hash 'name' => scheme, and each scheme should have named colors such as
26
+ # header-bg, body-bg body-fg, status etc, so it is clear. load from config file so user can change.
27
+ # x maybe instead of diong each binding we should be ablde to pass a hash to form
28
+ # or give it a method which it will invoke to handle keys. Form or window may have a keyhandler ??
29
+ # TODO
30
+ # x create a class and put stuff in there, these methods are going into global, and can conflict
31
+ # x put one url per lne of detail, put comments with comment url, and time with other.
32
+ # x fix update help_text
33
+ # x need to trap the output of hackercli in case of error.
34
+ # x some case URL not showing in Open menu - maybe too large the window. check max size
35
+ # x add to forum list, remove, save
21
36
  # - specify gui browser and text browser, and on commandline use same keys as corvus
22
- # - create a class and put stuff in there, these methods are going into global, and can conflict
23
- # - we should have same mechanism for key bindings as corvus, something that can even be loaded?
24
37
  #
25
- # - Use ' as bookmark etc just as in cetus and corvus, keep to same keys
26
- # - multibuffers so user can backspace and do M-n etc
38
+ # ? Use ' as bookmark etc just as in cetus and corvus, keep to same keys
39
+ # ? multibuffers so user can backspace and do M-n etc
27
40
  #
28
- VERSION="0.0.2"
29
- COLOR_SCHEMES=[
30
- [20,19,17, 18, :white], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status, 4 fg color body
31
- [17,19,18, 20, :white], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
32
- [236,236,232, 234,:white], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
33
- [236,236,244, 234, :black] # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
34
- ]
35
- $color_scheme = COLOR_SCHEMES[0]
36
- $toggle_titles_only = false
37
- $fg = :white
38
- $forumlist = %w{ hacker ruby programming scifi science haskell java scala cpp c_programming d_language golang vim emacs unix linux bash zsh commandline vimplugins python ars slashdot }
39
- def choose_forum
40
- # scrollable filterable list
41
- str = display_list $forumlist, :title => "Select a forum"
42
- return unless str
43
- return if str == ""
44
- $current_forum = str
45
- forum = str
46
- get_data forum if forum
47
- end
48
- def next_forum
49
- index = $forumlist.index($current_forum)
50
- index = index >= $forumlist.count - 1 ? 0 : index + 1
51
- get_data $forumlist[index]
52
- end
53
- def prev_forum
54
- index = $forumlist.index($current_forum)
55
- index = index == 0? $forumlist.count - 1 : index - 1
56
- get_data $forumlist[index]
57
- end
58
- # if components have some commands, can we find a way of passing the command to them
59
- # method_missing gave a stack overflow.
60
- def execute_this(meth, *args)
61
- alert " #{meth} not found ! "
62
- $log.debug "app email got #{meth} " if $log.debug?
63
- cc = @form.get_current_field
64
- [cc].each do |c|
65
- if c.respond_to?(meth, true)
66
- c.send(meth, *args)
67
- return true
68
- end
69
- end
70
- false
71
- end
72
- def open_url url
73
- shell_out "elinks #{url}"
74
- #Window.refresh_all
75
- end
76
-
77
- ##
78
- # Menu creator which displays a menu and executes methods based on keys.
79
- # In some cases, we call this and then do a case statement on either key or binding.
80
- # @param String title
81
- # @param hash of keys and methods to call
82
- # @return key pressed, and binding (if found, and responded)
41
+ module HackerCli
42
+ VERSION="0.0.3"
43
+ CONFIG_FILE="~/.hackman.yml"
44
+ # in grey version, cannot see the other links.
45
+ OLDCOLOR_SCHEMES=[
46
+ [20,19,17, 18, :white, :green], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status, 4 fg color body, detail color (url and comment count)
47
+ [17,19,18, 20, :white, :green], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
48
+ [236,236,0, 232,:white, :green], # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
49
+ [236,236,244, 250, :black, :green] # 0 band in header, 1 - menu bgcolor. 2 - bgcolor of main screen, 3 - status
50
+ ]
51
+ # put all methods and data into this class, so we don't pollute global space. Or get mixed into App's space.
83
52
  #
84
- def menu title, hash, config={}, &block
85
- raise ArgumentError, "Nil hash received by menu" unless hash
86
- list = []
87
- hash.each_pair { |k, v| list << " #[fg=yellow, bold] #{k} #[/end] #[fg=green] #{v} #[/end]" }
88
- # s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
89
- config[:title] = title
90
- config[:width] = hash.values.max_by(&:length).length + 13
91
- ch = padpopup list, config, &block
92
- return unless ch
93
- if ch.size > 1
94
- # could be a string due to pressing enter
95
- # but what if we format into multiple columns
96
- ch = ch.strip[0]
97
- end
98
-
99
- binding = hash[ch]
100
- binding = hash[ch.to_sym] unless binding
101
- if binding
102
- if respond_to?(binding, true)
103
- send(binding)
53
+ class Hackman
54
+ def initialize app, options
55
+ @app = app
56
+ @options = options
57
+ @form = app.form
58
+ @hash = nil
59
+ @cache_path = "."
60
+ @toggle_titles_only = false
61
+ @toggle_offline = false
62
+ @logger = @app.logger
63
+
64
+ @fg = :white
65
+ @_forumlist = %w{ hacker ruby programming scifi science haskell java scala cpp c_programming d_language golang vim emacs unix linux bash zsh commandline vimplugins python ars slashdot }
66
+ @browser_mode = options[:browser_mode] || 'text'
67
+ @browser_text = options[:browser_text] || 'elinks'
68
+ @browser_gui = options[:browser_gui] || 'open'
69
+ @cache_path = options[:cache_path] || "."
70
+ config_file = options[:config_file]
71
+ config_read config_file
72
+ @binding ||= default_bindings
73
+ @color_schemes ||= default_color_schemes
74
+ # we should actually pick the fist, since the name could have changed
75
+ @color_scheme = @color_schemes.values.first
76
+ @forumlist ||= (options[:list] || @_forumlist)
77
+ handle_keys @binding
78
+ #form_bind @binding
79
+ @cache_path = File.expand_path(@cache_path)
80
+ end
81
+ def config_read config_file=nil
82
+ config_file ||= CONFIG_FILE
83
+ config_file = File.expand_path(config_file)
84
+ if config_file
85
+ if File.exists? config_file
86
+ #eval(File.open(File.expand_path(config_file)).read)
87
+ obj = YAML::load( File.open( config_file ) )
88
+ #%w{ :binding :forumlist :cache_path}.each do |e|
89
+ #if obj[e]
90
+ obj.keys.each do |e|
91
+ instance_variable_set("@#{e}", obj[e])
92
+ end
93
+ else
94
+ alert "NOT EXISTS config file #{config_file} "
95
+ end
104
96
  end
105
97
  end
106
- return ch, binding
107
- end
108
- # pops up a list, taking a single key and returning if it is in range of 33 and 126
109
- # Called by menu, print_help, show_marks etc
110
- # You may pass valid chars or ints so it only returns on pressing those.
111
- #
112
- # @param Array of lines to print which may be formatted using :tmux format
113
- # @return character pressed (ch.chr)
114
- # @return nil if escape or C-q pressed
115
- #
116
- def padpopup list, config={}, &block
117
- max_visible_items = config[:max_visible_items]
118
- row = config[:row] || 5
119
- col = config[:col] || 5
120
- # format options are :ansi :tmux :none
121
- fmt = config[:format] || :tmux
122
- config.delete :format
123
- relative_to = config[:relative_to]
124
- if relative_to
125
- layout = relative_to.form.window.layout
126
- row += layout[:top]
127
- col += layout[:left]
128
- end
129
- config.delete :relative_to
130
- # still has the formatting in the string so length is wrong.
131
- #longest = list.max_by(&:length)
132
- width = config[:width] || 60
133
- if config[:title]
134
- width = config[:title].size + 2 if width < config[:title].size
135
- end
136
- height = config[:height]
137
- height ||= [max_visible_items || 25, list.length+2].min
138
- #layout(1+height, width+4, row, col)
139
- layout = { :height => 0+height, :width => 0+width, :top => row, :left => col }
140
- window = Canis::Window.new(layout)
141
- form = Canis::Form.new window
142
-
143
- ## added 2013-03-13 - 18:07 so caller can be more specific on what is to be returned
144
- valid_keys_int = config.delete :valid_keys_int
145
- valid_keys_char = config.delete :valid_keys_char
146
-
147
- listconfig = config[:listconfig] || {}
148
- #listconfig[:list] = list
149
- listconfig[:width] = width
150
- listconfig[:height] = height
151
- listconfig[:bgcolor] = $color_scheme[1]
152
- #listconfig[:selection_mode] ||= :single
153
- listconfig.merge!(config)
154
- listconfig.delete(:row);
155
- listconfig.delete(:col);
156
- # trying to pass populists block to listbox
157
- lb = Canis::TextPad.new form, listconfig, &block
158
- if fmt == :none
159
- lb.text(list)
160
- else
161
- lb.text(list, fmt)
98
+ # save current config to a yml file, so user can modify it
99
+ # This is included since its a bit difficult to create this file if you don't remember YML format.
100
+ def save_config filename=nil
101
+ unless filename
102
+ filename = get_string "Enter filename to save configuration to:"
103
+ return unless filename
104
+ end
105
+ xx = {}
106
+ [:binding, :forumlist, :browser_gui, :browser_text, :cache_path, :color_schemes, :color_scheme].each do |e|
107
+ xx[e] = instance_variable_get "@#{e}"
108
+ end
109
+ File.open(filename, 'w' ) do |f|
110
+ f << YAML::dump(xx)
111
+ end
112
+ @app.message "Config saved to #{filename} in YML format"
113
+ end
114
+ def default_color_schemes
115
+ @color_schemes={}
116
+ @color_schemes['deep blue'] = { :header_bg => 20, :menu_bg => 19, :body_bg => 17, :status_bg => 18, :body_fg => :white,
117
+ :body_detail => :green }
118
+ @color_schemes['medium blue'] = { :header_bg => 17, :menu_bg => 19, :body_bg => 18, :status_bg => 20, :body_fg => :white,
119
+ :body_detail => :green }
120
+ @color_schemes['black body'] = { :header_bg => 236, :menu_bg => 236, :body_bg => 0, :status_bg => 232, :body_fg => :white,
121
+ :body_detail => :green }
122
+ @color_schemes['grey body'] = { :header_bg => 236, :menu_bg => 236, :body_bg => 244, :status_bg => 250, :body_fg => :black,
123
+ :body_detail => :green }
124
+ return @color_schemes
125
+ end
126
+ def articles
127
+ @hash[:articles]
128
+ end
129
+ # return current color scheme
130
+ def color_scheme
131
+ @color_scheme
132
+ end
133
+ def forumlist
134
+ @forumlist
135
+ end
136
+ def default_bindings
137
+ @binding = {
138
+ "`" => "main_menu",
139
+ "=" => "toggle_menu",
140
+ ">" => "next_forum",
141
+ "<" => "prev_forum",
142
+ "z" => "goto_article",
143
+ "o" => "display_links",
144
+ "<CR>" => "display_links",
145
+ "<C-f>" => "display_links",
146
+ "<F2>" => "choose_forum"
147
+ }
162
148
  end
149
+
150
+
151
+ # prompt user to select a forum, and fetch data for it.
152
+ def choose_forum
153
+ # scrollable filterable list
154
+ str = display_list @forumlist, :title => "Select a forum"
155
+ return unless str
156
+ return if str == ""
157
+ @current_forum = str
158
+ forum = str
159
+ get_data forum if forum
160
+ end
161
+ # add a forum at runtime, by default this will be a reddit subforum
162
+ def add_forum forum=nil
163
+ unless forum
164
+ forum = get_string "Add a reddit subforum: "
165
+ return if forum.nil? or forum == ""
166
+ end
167
+ @forumlist << forum
168
+ get_data forum
169
+ end
170
+ def remove_forum forum=nil
171
+ unless forum
172
+ forum = display_list @forumlist, :title => "Select a forum"
173
+ return if forum.nil? or forum == ""
174
+ end
175
+ @forumlist.delete forum
176
+ end
177
+ def next_forum
178
+ index = @forumlist.index(@current_forum)
179
+ index = index >= @forumlist.count - 1 ? 0 : index + 1
180
+ get_data @forumlist[index]
181
+ end
182
+ def prev_forum
183
+ index = @forumlist.index(@current_forum)
184
+ index = index == 0? @forumlist.count - 1 : index - 1
185
+ get_data @forumlist[index]
186
+ end
187
+ # if components have some commands, can we find a way of passing the command to them
188
+ # method_missing gave a stack overflow.
189
+ def execute_this(meth, *args)
190
+ alert " #{meth} not found ! "
191
+ $log.debug "app email got #{meth} " if $log.debug?
192
+ cc = @form.get_current_field
193
+ [cc].each do |c|
194
+ if c.respond_to?(meth, true)
195
+ c.send(meth, *args)
196
+ return true
197
+ end
198
+ end
199
+ false
200
+ end
201
+ def open_url url, app
202
+ #shell_out "elinks #{url}"
203
+ shell_out "#{app} #{url}"
204
+ #Window.refresh_all
205
+ end
206
+
207
+ ##
208
+ # Menu creator which displays a menu and executes methods based on keys.
209
+ # In some cases, we call this and then do a case statement on either key or binding.
210
+ # @param String title
211
+ # @param hash of keys and methods to call
212
+ # @return key pressed, and binding (if found, and responded). Can return NIL nil if esc pressed
163
213
  #
164
- #window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
165
- form.repaint
166
- Ncurses::Panel.update_panels
167
- if valid_keys_int.nil? && valid_keys_char.nil?
168
- # changed 32 to 33 so space can scroll list
169
- valid_keys_int = (33..126)
170
- end
171
-
172
- begin
173
- while((ch = window.getchar()) != 999 )
174
-
175
- # if a char range or array has been sent, check if the key is in it and send back
176
- # else just stay here
177
- if valid_keys_char
178
- if ch > 32 && ch < 127
179
- chr = ch.chr
180
- return chr if valid_keys_char.include? chr
181
- end
214
+ def menu title, hash, config={}, &block
215
+ raise ArgumentError, "Nil hash received by menu" unless hash
216
+ list = []
217
+ list << config[:subtitle] if config[:subtitle]
218
+ config.delete(:subtitle)
219
+ hash.each_pair { |k, v| list << " #[fg=yellow, bold] #{k} #[/end] #[fg=green] #{v} #[/end]" }
220
+ # s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
221
+ config[:title] = title
222
+ config[:width] = hash.values.max_by(&:length).length + 13
223
+ # need to have a proper check, which takes +left+ / column into account
224
+ config[:width] = FFI::NCurses.COLS - 10 if config[:width] > FFI::NCurses.COLS
225
+ ch = padpopup list, config, &block
226
+ return unless ch
227
+ if ch.size > 1
228
+ # could be a string due to pressing enter
229
+ # but what if we format into multiple columns
230
+ ch = ch.strip[0]
231
+ end
232
+
233
+ binding = hash[ch]
234
+ binding = hash[ch.to_sym] unless binding
235
+ if binding
236
+ if respond_to?(binding, true)
237
+ send(binding)
182
238
  end
239
+ end
240
+ return ch, binding
241
+ end
242
+ # pops up a list, taking a single key and returning if it is in range of 33 and 126
243
+ # Called by menu, print_help, show_marks etc
244
+ # You may pass valid chars or ints so it only returns on pressing those.
245
+ #
246
+ # @param Array of lines to print which may be formatted using :tmux format
247
+ # @return character pressed (ch.chr)
248
+ # @return nil if escape or C-q pressed
249
+ #
250
+ def padpopup list, config={}, &block
251
+ max_visible_items = config[:max_visible_items]
252
+ row = config[:row] || 1
253
+ col = config[:col] || 1
254
+ # format options are :ansi :tmux :none
255
+ fmt = config[:format] || :tmux
256
+ config.delete :format
257
+ relative_to = config[:relative_to]
258
+ if relative_to
259
+ layout = relative_to.form.window.layout
260
+ row += layout[:top]
261
+ col += layout[:left]
262
+ end
263
+ config.delete :relative_to
264
+ # still has the formatting in the string so length is wrong.
265
+ #longest = list.max_by(&:length)
266
+ width = config[:width] || 60
267
+ if config[:title]
268
+ width = config[:title].size + 2 if width < config[:title].size
269
+ end
270
+ height = config[:height]
271
+ height ||= [max_visible_items || 25, list.length+2].min
272
+ #layout(1+height, width+4, row, col)
273
+ layout = { :height => 0+height, :width => 0+width, :top => row, :left => col }
274
+ window = Canis::Window.new(layout)
275
+ form = Canis::Form.new window
183
276
 
184
- # if the user specified an array or range of ints check against that
185
- # therwise use the range of 33 .. 126
186
- return ch.chr if valid_keys_int.include? ch
277
+ ## added 2013-03-13 - 18:07 so caller can be more specific on what is to be returned
278
+ valid_keys_int = config.delete :valid_keys_int
279
+ valid_keys_char = config.delete :valid_keys_char
187
280
 
188
- case ch
189
- when ?\C-q.getbyte(0)
190
- break
191
- else
192
- if ch == 13 || ch == 10
193
- s = lb.current_value.to_s # .strip #if lb.selection_mode != :multiple
194
- return s
281
+ listconfig = config[:listconfig] || {}
282
+ #listconfig[:list] = list
283
+ listconfig[:width] = width
284
+ listconfig[:height] = height
285
+ # pass this in config so less dependences
286
+ listconfig[:bgcolor] = @color_scheme[:menu_bg]
287
+ #listconfig[:selection_mode] ||= :single
288
+ listconfig.merge!(config)
289
+ listconfig.delete(:row);
290
+ listconfig.delete(:col);
291
+ #listconfig[:row] = 1
292
+ #listconfig[:col] = 1
293
+ # trying to pass populists block to listbox
294
+ lb = Canis::TextPad.new form, listconfig, &block
295
+ if fmt == :none
296
+ lb.text(list)
297
+ else
298
+ lb.text(list, fmt)
299
+ end
300
+ #
301
+ #window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
302
+ form.repaint
303
+ Ncurses::Panel.update_panels
304
+ if valid_keys_int.nil? && valid_keys_char.nil?
305
+ # changed 32 to 33 so space can scroll list
306
+ valid_keys_int = (33..126)
307
+ end
308
+
309
+ begin
310
+ while((ch = window.getchar()) != 999 )
311
+
312
+ # if a char range or array has been sent, check if the key is in it and send back
313
+ # else just stay here
314
+ if valid_keys_char
315
+ if ch > 32 && ch < 127
316
+ chr = ch.chr
317
+ return chr if valid_keys_char.include? chr
318
+ end
195
319
  end
196
- # close if escape or double escape
197
- if ch == 27 || ch == 2727
198
- return nil
320
+
321
+ # if the user specified an array or range of ints check against that
322
+ # therwise use the range of 33 .. 126
323
+ return ch.chr if valid_keys_int.include? ch
324
+
325
+ case ch
326
+ when ?\C-q.getbyte(0)
327
+ break
328
+ else
329
+ if ch == 13 || ch == 10
330
+ s = lb.current_value.to_s # .strip #if lb.selection_mode != :multiple
331
+ return s
332
+ end
333
+ # close if escape or double escape
334
+ if ch == 27 || ch == 2727
335
+ return nil
336
+ end
337
+ lb.handle_key ch
338
+ form.repaint
199
339
  end
200
- lb.handle_key ch
201
- form.repaint
202
340
  end
341
+ ensure
342
+ window.destroy
203
343
  end
204
- ensure
205
- window.destroy
344
+ return nil
206
345
  end
207
- return nil
208
- end
209
- # main options, invokable on backtick.
210
- # TODO add selection of browser
211
- def main_menu
212
- h = {
213
- :f => :choose_forum,
214
- :c => :color_scheme_select,
215
- :s => :sort_menu,
216
- :F => :filter_menu,
217
- :x => :extras
218
- }
219
- ch, binding = menu "Main Menu", h
220
- #alert "Menu got #{ch}, #{binding}" if ch
221
- end
222
- def toggle_menu
223
- h = {
224
- "t" => :toggle_titles_only,
225
- :x => :extras
226
- }
227
- ch, binding = menu "Main Menu", h
228
- #alert "Menu got #{ch}, #{binding}" if ch
229
- end
230
- def color_scheme_select ch=nil
231
- unless ch
232
- h = {
233
- "0" => 'dark blue body',
234
- "1" => 'medium blue body',
235
- "2" => 'black body',
236
- "3" => 'grey body',
237
- "b" => 'change body color',
238
- "f" => 'change body fg color',
239
- "c" => 'cycle body color'
240
- }
241
- ch, binding = menu "Color Menu", h
242
- end
243
- case ch
244
- when "1", "2", "0", "3"
245
- $color_scheme = COLOR_SCHEMES[ch.to_i] || COLOR_SCHEMES.first
246
- $fg = $color_scheme[4]
247
- when "b"
248
- n = get_string "Enter a number for background color (0..255): "
249
- n = n.to_i
250
- $color_scheme[2] = n
251
- when "4", "f"
252
- n = get_string "Enter a number for fg color (0..255) : "
253
- $fg = n.to_i
254
- when "c"
255
- # increment bg color
256
- n = $color_scheme[2]
257
- n += 1
258
- n = 0 if n > 255
259
- $color_scheme[2] = n
260
- when "C"
261
- # decrement bg color
262
- n = $color_scheme[2]
263
- n -= 1
264
- n = 255 if n < 0
265
- $color_scheme[2] = n
266
- end
267
-
268
- h = @form.by_name["header"]
269
- tv = @form.by_name["tv"]
270
- sl = @form.by_name["sl"]
271
- tv.bgcolor = $color_scheme[2]
272
- #tv.color = 255
273
- tv.color = $fg
274
- sl.color = $color_scheme[3]
275
- h.bgcolor = $color_scheme[0]
276
- message "bgcolor is #{$color_scheme[2]}. :: #{$color_scheme.join(",")}, CP:#{tv.color_pair}=#{tv.color} / #{tv.bgcolor} "
277
- refresh
278
- end
279
- def refresh
280
- show $current_file
281
- end
282
-
283
- def toggle_titles_only
284
- $toggle_titles_only = !$toggle_titles_only
285
- show $current_file
286
- end
287
- App.new do
288
- @startdir ||= File.expand_path("..")
289
- @hash = nil
290
- def get_item_for_line line
291
- index = (line - @hash[:first]) / @hash[:diff]
292
- @hash[:articles][index]
293
- end
294
- def title_right text
295
- w = @form.by_name["header"]
296
- w.text_right text
297
- end
298
- def title text
299
- w = @form.by_name["header"]
300
- w.text_center text
301
- end
302
- def color_line(fg,bg,attr,text)
303
- a = "#["
304
- a = []
305
- a << "fg=#{fg}" if fg
306
- a << "bg=#{bg}" if bg
307
- a << "#{attr}" if attr
308
- str = "#[" + a.join(",") + "]#{text}#[end]"
309
- end
310
- def goto_article n=$multiplier
311
- i = ((n-1) * @hash[:diff]) + @hash[:first]
312
- w = @form.by_name["tv"]
313
- w.goto_line i
314
- end
315
-
316
- def OLDshow file
317
- w = @form.by_name["tv"]
318
- if File.directory? file
319
- lines = Dir.entries(file)
320
- w.text lines
321
- w.title "[ #{file} ]"
322
- elsif File.exists? file
323
- lines = File.open(file,'r').readlines
324
- w.text lines
325
- w.title "[ #{file} ]"
346
+ # main options, invokable on backtick.
347
+ # TODO add selection of browser
348
+ # r for reload
349
+ # 1,2 a c view article, comments
350
+ def main_menu
351
+ h = {
352
+ :f => :choose_forum,
353
+ :c => :color_scheme_select,
354
+ #:s => :sort_menu,
355
+ #:F => :filter_menu,
356
+ :a => :add_forum,
357
+ :d => :remove_forum,
358
+ :x => :extras
359
+ }
360
+ ch, binding = menu "Main Menu", h
361
+ #alert "Menu got #{ch}, #{binding}" if ch
326
362
  end
327
- end
328
- # display the given yml file.
329
- # Converts the yml object to an array for textpad
330
- def display_yml file
331
- w = @form.by_name["tv"]
332
-
333
- obj = YAML::load( File.open( file ) )
334
- lines = Array.new
335
- url = obj[:page_url]
336
- host = nil
337
- if url.index("reddit")
338
- host = "reddit"
339
- elsif url.index("ycombinator")
340
- host = "hacker"
341
- elsif url.index("ars")
342
- host = "ars"
343
- elsif url.index("slashdot")
344
- host = "slashdot"
345
- else
346
- alert "Host not known: #{url} "
347
- end
348
- articles = obj[:articles]
349
- count = articles.count
350
- #lines << color_line(:red,COLOR_SCHEME[1],nil,"#{file} #{obj[:page_url]} | #{count} articles | fetched #{obj[:create_time]}")
351
- #lines << ("-" * lines.last.size )
352
- @hash = Hash.new
353
- @hash[:first] = lines.size
354
- @hash[:articles] = articles
355
-
356
- articles.each_with_index do |a, i|
357
- bg = i
358
- bg = 0 if i > 255
359
- line = "%3s %s " % [i+1 , a[:title] ]
360
- #lines << color_line($fg, bg, nil, line)
361
- lines << line
362
- if !$toggle_titles_only
363
- url = a[:article_url] || a[:url]
364
- l = " %s | %s" % [url, a[:comments_url] ]
365
- l = "#[fg=green, underline]" + l + "#[end]"
366
- lines << l
367
- detail = []
368
- if a.key? :comment_count
369
- detail << a[:comment_count]
363
+ # TODO uses text browser t, use gui browser g
364
+ # l - long list (what is currently t)
365
+ def toggle_menu
366
+ h = {
367
+ "t" => :toggle_titles_only,
368
+ "O" => :toggle_offline
369
+ #:x => :extras
370
+ }
371
+ ch, binding = menu "Main Menu", h
372
+ #alert "Menu got #{ch}, #{binding}" if ch
373
+ end
374
+ def color_scheme_select ch=nil
375
+ unless ch
376
+ h = {}
377
+ ctr = 0
378
+ @color_schemes.each_pair do |k,v|
379
+ ctr += 1
380
+ h[ctr.to_s] = k
370
381
  end
371
- if a.key? :pubdate
372
- detail << a[:pubdate]
382
+
383
+ h = h.merge({
384
+ #"0" => 'dark blue body',
385
+ #"1" => 'medium blue body',
386
+ #"2" => 'black body',
387
+ #"3" => 'grey body',
388
+ "b" => 'change body color',
389
+ "f" => 'change body fg color',
390
+ "d" => 'change body detail color',
391
+ "c" => 'cycle body color'
392
+ })
393
+ ch, binding = menu "Color Menu", h
394
+ end
395
+ case ch
396
+ when "1", "2", "0", "3","4","5","6"
397
+ @color_scheme = @color_schemes[binding]
398
+ @fg = @color_scheme[:body_fg]
399
+ when "b"
400
+ n = get_string "Enter a number for background color (0..255): "
401
+ unless n =~ /^\d+$/
402
+ n = Canis::ColorMap.colors.index(n.to_sym)
403
+ return unless n
373
404
  end
374
- unless detail.empty?
375
- l = "#[fg=green]" + " " + detail.join(" | ") + "#[end]"
376
- lines << l
405
+ n = n.to_i
406
+ @color_scheme[:body_bg] = n
407
+ when "f"
408
+ n = get_string "Enter a number for fg color (0..255) : "
409
+ unless n =~ /^\d+$/
410
+ n = Canis::ColorMap.colors.index(n.to_sym)
411
+ return unless n
377
412
  end
413
+ @fg = n.to_i
414
+ @color_scheme[:body_fg] = n.to_i
415
+ when "d"
416
+ n = get_string "Enter a number for detail line color (0..255): "
417
+ unless n =~ /^\d+$/
418
+ n = Canis::ColorMap.colors.index(n.to_sym)
419
+ return unless n
420
+ end
421
+ n = n.to_i
422
+ @color_scheme[:body_detail] = n
423
+ when "c"
424
+ # increment bg color
425
+ n = @color_scheme[:body_bg]
426
+ n += 1
427
+ n = 0 if n > 255
428
+ @color_scheme[:body_bg] = n
429
+ when "C"
430
+ # decrement bg color
431
+ n = @color_scheme[:body_bg]
432
+ n -= 1
433
+ n = 255 if n < 0
434
+ @color_scheme[:body_bg] = n
378
435
  end
379
- @hash[:diff] ||= lines.size - @hash[:first]
436
+
437
+ h = @form.by_name["header"]
438
+ tv = @form.by_name["tv"]
439
+ sl = @form.by_name["sl"]
440
+ tv.bgcolor = @color_scheme[:body_bg]
441
+ #tv.color = 255
442
+ tv.color = @fg
443
+ sl.color = @color_scheme[:status_bg]
444
+ h.bgcolor = @color_scheme[:header_bg]
445
+ #@app.message "bgcolor is #{@color_scheme[:body_bg]}. :: #{@color_scheme.join(",")}, CP:#{tv.color_pair}=#{tv.color} / #{tv.bgcolor} "
446
+ refresh
447
+ end
448
+ def extras
449
+ h = {
450
+ "s" => :save_config
451
+ }
452
+ ch, binding = menu "Extras ", h
453
+ end
454
+ def refresh
455
+ display_yml @current_file
380
456
  end
381
- w.text(lines, :content_type => :tmux)
382
- w.title "[ #{file} ]"
383
457
 
384
- i = @hash[:first] || 1
385
- w.goto_line i
386
- $current_file = file
387
- $current_forum = file.sub(File.extname(file),"")
388
- title "#{$current_forum} (#{count} articles) "
389
- title_right obj[:create_time]
390
- end
391
- alias :show :display_yml
392
- def get_data forum
393
- file = forum + ".yml"
394
- if File.exists? file and fresh(file)
395
- else
396
- progress_dialog :color_pair => $reversecolor do |sw|
397
- #sw.printstring 0,1, "Fetching #{forum} ..."
398
- sw.print "Fetching #{forum} ..."
399
- system("hackercli.rb -y #{forum}.yml #{forum}")
458
+ def toggle_titles_only
459
+ @toggle_titles_only = !@toggle_titles_only
460
+ show @current_file
461
+ end
462
+ def toggle_offline
463
+ @toggle_offline = !@toggle_offline
464
+ end
465
+ # moved from inside App
466
+ #
467
+ def get_item_for_line line
468
+ index = (line - @hash[:first]) / @hash[:diff]
469
+ @hash[:articles][index]
470
+ end
471
+ def title_right text
472
+ w = @form.by_name["header"]
473
+ w.text_right text
474
+ end
475
+ def title text
476
+ w = @form.by_name["header"]
477
+ w.text_center text
478
+ end
479
+ def color_line(fg,bg,attr,text)
480
+ a = "#["
481
+ a = []
482
+ a << "fg=#{fg}" if fg
483
+ a << "bg=#{bg}" if bg
484
+ a << "#{attr}" if attr
485
+ str = "#[" + a.join(",") + "]#{text}#[end]"
486
+ end
487
+ def goto_article n=$multiplier
488
+ i = ((n-1) * @hash[:diff]) + @hash[:first]
489
+ w = @form.by_name["tv"]
490
+ w.goto_line i
491
+ end
492
+ def display_links
493
+ # if multiplier is 0, use current line
494
+ art = self.articles[$multiplier - 1]
495
+ if $multiplier == 0
496
+ tv = @form.by_name["tv"]
497
+ index = tv.current_index
498
+ art = get_item_for_line index
400
499
  end
500
+ show_links art
401
501
  end
402
- display_yml file
403
- end
404
- # return true if younger than one hour
405
- def fresh file
406
- f = File.stat(file)
407
- now = Time.now
408
- return (( now - f.mtime) < 7200)
409
- end
410
- def show_links art
502
+
503
+ # display the given yml file.
504
+ # Converts the yml object to an array for textpad
505
+ def display_yml file
506
+ w = @form.by_name["tv"]
507
+
508
+ obj = YAML::load( File.open( file ) )
509
+ lines = Array.new
510
+ url = obj[:page_url]
511
+ host = nil
512
+ if url.index("reddit")
513
+ host = "reddit"
514
+ elsif url.index("ycombinator")
515
+ host = "hacker"
516
+ elsif url.index("ars")
517
+ host = "ars"
518
+ elsif url.index("slashdot")
519
+ host = "slashdot"
520
+ else
521
+ alert "Host not known: #{url} "
522
+ end
523
+ articles = obj[:articles]
524
+ count = articles.count
525
+ #lines << color_line(:red,COLOR_SCHEME[1],nil,"#{file} #{obj[:page_url]} | #{count} articles | fetched #{obj[:create_time]}")
526
+ #lines << ("-" * lines.last.size )
527
+ @hash = Hash.new
528
+ @hash[:first] = lines.size
529
+ @hash[:articles] = articles
530
+ dc = @color_scheme[:body_detail]
531
+
532
+ articles.each_with_index do |a, i|
533
+ bg = i
534
+ bg = 0 if i > 255
535
+ line = "%3s %s " % [i+1 , a[:title] ]
536
+ #lines << color_line(@fg, bg, nil, line)
537
+ lines << line
538
+ if !@toggle_titles_only
539
+ line1 = []
540
+ line2 = []
541
+ url = a[:article_url] || a[:url]
542
+ line1 << url
543
+ #l = " %s | %s" % [url, a[:comments_url] ]
544
+ line2 << a[:comments_url] if a[:comments_url]
545
+ #l = "#[fg=#{dc}, underline]" + l + "#[end]"
546
+ #lines << l
547
+ #detail = []
548
+ if a.key? :comment_count
549
+ #detail << a[:comment_count]
550
+ line1 << a[:comment_count]
551
+ end
552
+ if a.key? :pubdate
553
+ #detail << a[:pubdate]
554
+ line2 << a[:pubdate]
555
+ end
556
+ #unless detail.empty?
557
+ l = "#[fg=#{dc}]" + " " + line1.join(" | ") + "#[end]"
558
+ lines << l
559
+ l = "#[fg=#{dc}]" + " " + line2.join(" | ") + "#[end]"
560
+ lines << l
561
+ #end
562
+ end
563
+ @hash[:diff] ||= lines.size - @hash[:first]
564
+ end
565
+ w.text(lines, :content_type => :tmux)
566
+ w.title "[ #{file} ]"
567
+
568
+ i = @hash[:first] || 1
569
+ w.goto_line i
570
+ @current_file = file
571
+ #@current_forum = file_to_forum file
572
+ title "#{@current_forum} (#{count} articles) "
573
+ title_right obj[:create_time]
574
+ end
575
+ def file_to_forum filename
576
+ forum = File.basename(filename).sub(File.extname(filename),"").sub("__","/")
577
+ end
578
+ def forum_to_file forum
579
+ file = "#{forum}.yml".sub("/","__")
580
+ file = "#{@cache_path}/#{file}"
581
+ end
582
+ alias :show :display_yml
583
+ def get_data forum
584
+ #file = forum + ".yml"
585
+ file = forum_to_file forum
586
+ if File.exists? file and fresh?(file)
587
+ else
588
+ progress_dialog :color_pair => $reversecolor do |sw|
589
+ sw.print "Fetching #{forum} ..."
590
+ #system("hackercli.rb -y #{file} #{forum}")
591
+ o,e,s = Open3.capture3("hackercli.rb -y #{file} #{forum}")
592
+ unless s.success?
593
+ $log.debug " error from capture3 #{e}"
594
+ alert e
595
+ return
596
+ end
597
+ end
598
+ end
599
+ if File.exists? file
600
+ @current_forum = forum
601
+ display_yml file
602
+ else
603
+ alert "#{file} not created. Check externally. run hackercli.rb -y #{file} #{forum} externally"
604
+ end
605
+ end
606
+ # return true if younger than one hour
607
+ def fresh? file
608
+ return true if @toggle_offline
609
+
610
+ f = File.stat(file)
611
+ now = Time.now
612
+ return (( now - f.mtime) < 7200)
613
+ end
614
+ def show_links art
615
+ return unless art
411
616
  links = {}
412
617
  keys = %w{a b c d e f}
413
618
  i = 0
@@ -417,61 +622,154 @@ App.new do
417
622
  i += 1
418
623
  end
419
624
  end
420
- ch, binding = menu "Links Menu", links
625
+ ch, binding = menu "Select a link", links, :subtitle => " Enter Upper case letter to open in gui"
421
626
  #alert "is #{index}: #{art[:title]} #{ch}:#{binding} "
627
+ app = @browser_text || "elinks"
628
+ unless binding
629
+ return unless ch
630
+ # it must be an upper case for GUI
631
+ return unless ch == ch.upcase
632
+ ch = ch.downcase
633
+ return unless keys.include? ch
634
+ binding = links[ch]
635
+ app = @browser_gui || "open"
636
+ end
422
637
  if binding
423
- open_url binding
638
+ open_url binding, app
424
639
  end
640
+ end
641
+ # since this does not happen inside form's loop, therefore form is unable to repaint, repaint
642
+ # happens only after a keystroke
643
+ # This allows us to pass in a hash with string names for methods. This hash can be easily updated,
644
+ # or even read in from a config file/yml file. It is assumed here that all the string names
645
+ # correspond to names of methods withing this class, so no class references are required.
646
+ # TODO split the command if there are spaces.
647
+ def handle_keys hash
648
+ @app.keypress do |str|
649
+ binding = hash[str]
650
+ if binding
651
+ binding = binding.to_sym
652
+ if respond_to?(binding, true)
653
+ send(binding)
654
+ else
655
+ #alert "unresponded to #{str}"
656
+ end
657
+ end
658
+ end
659
+ end
660
+
661
+ # Should work on this as a means of binding each element of a hash into forms keymap.
662
+ # FIXME works except that multiplier not working ??
663
+ def form_bind hash
664
+ hash.each_pair do |k, v|
665
+ nk = key_to_i(k)
666
+ desc = "??"
667
+ desc = v if v.is_a? String or v.is_a? Symbol
668
+ @form.bind_key(nk, desc) { self.send(v) }
669
+ end
670
+ end
671
+ # convert a key in the format to an int so it can be mapped using bind_key
672
+ # "[a-zA-Z"] etc a single cahr
673
+ # C-a to C-z
674
+ # M-a to M-z
675
+ # F1 .. F10
676
+ # This does not take complex cases yet. It is a simplistic conversion.
677
+ def key_to_i k
678
+ if k.size == 1
679
+ return k.getbyte(0)
680
+ end
681
+ if k =~ /^<M-/
682
+ ch = k[3]
683
+ return 128 + ch.ord
684
+ elsif k == "<CR>"
685
+ return 13
686
+ elsif k =~ /^<[Cc]/
687
+ ch = k[3]
688
+ x = ch.ord - "a".ord + 1
689
+ elsif k[0,2] == "<F"
690
+ ch = k[2..-2]
691
+ return 264 + ch.to_i
692
+ else
693
+ alert "not able to bind #{k}"
694
+ end
695
+
696
+ end
697
+ end # class
698
+ end # module HackerCli
699
+ include HackerCli
700
+
701
+ # http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
702
+ require 'optparse'
703
+ options = {}
704
+ app = File.basename $0
705
+ OptionParser.new do |opts|
706
+ opts.banner = %Q{
707
+ #{app} version #{VERSION} (YML version)
708
+ Usage: #{app} [options]
709
+ }
710
+
711
+ #opts.on("-m MODE", String,"--mode", "Use 'text' or 'gui' browser") do |v|
712
+ #options[:browser_mode] = v
713
+ #end
714
+ opts.on("-t browser", String,"--text", "browser for text mode, default elinks") do |v|
715
+ options[:browser_text] = v
716
+ end
717
+ opts.on("-g browser", String,"--gui", "browser for gui mode, default open") do |v|
718
+ options[:browser_gui] = v
425
719
  end
426
- ht = 24
427
- borderattrib = :reverse
720
+ opts.on("-c cache dir", String,"--cache-dir", "location to store yml files, default .") do |v|
721
+ options[:cache_path] = File.expand_path(v)
722
+ end
723
+ opts.on("-u config_file", String,"--config-file", "path to load config info from") do |v|
724
+ options[:config_file] = v
725
+ end
726
+ opts.on("--list x,y,z", Array, "Example 'list' of forums: hacker,ruby,programming...") do |list|
727
+ options[:list] = list
728
+ end
729
+ # file age in hours
730
+ # offline mode
731
+ # config file path
732
+ end.parse!
733
+ App.new do
734
+ def logger; return @log; end
735
+ @log = create_logger "hacker.log"
736
+ @h = Hackman.new self, options
737
+ @color_scheme = @h.color_scheme
428
738
  @header = app_header "hackman #{VERSION}", :text_center => "RSS Reader", :name => "header",
429
- :text_right =>"Press =", :color => :white, :bgcolor => $color_scheme[0]
739
+ :text_right =>"Menu `", :color => :white, :bgcolor => @color_scheme[:header_bg]
430
740
  message "Press F10 (or qq) to exit, F1 Help, ` for Menu "
431
741
 
432
742
 
743
+
433
744
 
434
745
  # commands that can be mapped to or executed using M-x
435
746
  # however, commands of components aren't yet accessible.
436
747
  def get_commands
437
748
  %w{ choose_forum next_forum prev_forum }
438
749
  end
750
+ # help text for F1, but this needs to be kept consistent with @bindings,
751
+ # if that is changed, then how does this show the change, considering that
752
+ # the config file will be read in Hackman, not here.
439
753
  def help_text
440
754
  <<-eos
441
- rCommandLine HELP
442
-
443
- These are some features for either getting filenames from user
444
- at the bottom of the window like vim and others do, or filtering
445
- from a list (like ControlP plugin). Or seeing a file at bottom
446
- of screen for a quick preview.
755
+ Hackman Help
447
756
 
448
- : - Command mode
757
+ F2 - forum selection (interface like Ctrl-P, very minimal)
449
758
  F1 - Help
450
759
  F10 - Quit application
451
760
  qq - Quit application
452
- = - file selection (interface like Ctrl-P, very minimal)
453
-
454
- Some commands for using bottom of screen as vim and emacs do.
455
- These may be selected by pressing ':'
456
-
457
- testchoosedir - filter directory list as you type
458
- '>' to step into a dir, '<' to go up.
459
- testchoosefile - filter file list as you type
460
- ENTER to select, C-c or Esc-Esc to quit
461
- testdir - vim style, tabbing completes matching files
462
- testnumberedmenu - use menu indexes to select options
463
- choose_forum - display a list at bottom of screen
464
- Press <ENTER> to select, arrow keys to traverse,
465
- and characters to filter list.
466
- testdisplaytext - display text at bottom (current file contents)
467
- Press <ENTER> when done.
468
-
469
- The file/dir selection options are very minimally functional. Improvements
470
- and thorough testing are required. I've only tested them out gingerly.
471
-
472
- testchoosedir and file were earlier like Emacs/memacs with TAB completion
473
- but have now moved to the much faster and friendlier ControlP plugin like
474
- 'filter as you type' format.
761
+
762
+ ` (backtick) - Main Menu (add, remove, change forum)
763
+ = (Equal) - Toggle Menu (titles only)
764
+
765
+ o - open url menu for current article (under cursor)
766
+ <n>o - open url menu for <n>th article
767
+ <n>z - goto <n>th article
768
+
769
+ "<" - previous forum in list
770
+ ">" - next forum in list
771
+
772
+ "/" - search within the page (case-sensitive). Append "/i" to ignore case.
475
773
 
476
774
  -----------------------------------------------------------------------
477
775
  :n or Alt-n for general help.
@@ -481,51 +779,52 @@ App.new do
481
779
  #install_help_text help_text
482
780
 
483
781
  def app_menu
484
- @curdir ||= Dir.pwd
485
- Dir.chdir(@curdir) if Dir.pwd != @curdir
782
+ # TODO update and fix this
486
783
  require 'canis/core/util/promptmenu'
487
784
  menu = PromptMenu.new self do
488
785
  item :f, :choose_forum
489
- item :t, :testdisplay_text
786
+ item :n, :next_forum
787
+ item :p, :prev_forum
788
+ item :a, :add_forum
789
+ item :d, :remove_forum
490
790
  end
491
791
  menu.display_new :title => "Menu"
492
792
  end
493
793
  # BINDING SECTION
494
- @form.bind_key(?:, "App Menu") { app_menu; }
495
- @form.bind_key(?`, "Main Menu") { main_menu; }
496
- @form.bind_key(FFI::NCurses::KEY_F2, "Main Menu") { choose_forum; }
497
- @form.bind_key(FFI::NCurses::KEY_F3, "Cycle bgcolor") { color_scheme_select "c"; }
498
- @form.bind_key(FFI::NCurses::KEY_F4, "Cycle bgcolor") { color_scheme_select "C"; }
499
- @form.bind_key($kh_int["S-F3"], "Cycle bgcolor") { color_scheme_select "C"; }
794
+ if false
795
+ #@form.bind_key(?:, "App Menu") { app_menu; }
796
+ @form.bind_key(?`, "Main Menu") { @h.main_menu; }
797
+ @form.bind_key(FFI::NCurses::KEY_F2, "Main Menu") { @h.choose_forum; }
798
+ @form.bind_key(FFI::NCurses::KEY_F3, "Cycle bgcolor") { @h.color_scheme_select "c"; }
799
+ @form.bind_key(FFI::NCurses::KEY_F4, "Cycle bgcolor") { @h.color_scheme_select "C"; }
800
+ @form.bind_key($kh_int["S-F3"], "Cycle bgcolor") { @h.color_scheme_select "C"; }
500
801
  @form.bind_key(?=, "Toggle Menu") {
501
- toggle_menu;
802
+ @h.toggle_menu;
502
803
  }
503
- @form.bind_key(?<, "Previous Forum") { prev_forum; }
504
- @form.bind_key(?>, "Next Forum") { next_forum; }
804
+ @form.bind_key(?<, "Previous Forum") { @h.prev_forum; }
805
+ @form.bind_key(?>, "Next Forum") { @h.next_forum; }
806
+ end
505
807
 
808
+ @form.help_manager.help_text = help_text
809
+
810
+ begin
506
811
  stack :margin_top => 1, :margin_left => 0, :width => :expand , :height => FFI::NCurses.LINES-2 do
507
812
  tv = textpad :height_pc => 100, :width_pc => 100, :name => "tv", :suppress_borders => true,
508
- :bgcolor => $color_scheme[2], :color => 255, :attr => NORMAL
813
+ :bgcolor => @color_scheme[:body_bg], :color => 255, :attr => NORMAL
509
814
  #tv.renderer ruby_renderer
510
- tv.bind(:PRESS) {|ev|
511
- index = ev.current_index
512
- art = get_item_for_line index
513
- show_links art
514
- }
515
- tv.bind_key(?z) { goto_article }
516
- tv.bind_key(?o) {
517
- # if multiplier is 0, use current line
518
- art = @hash[:articles][$multiplier - 1]
519
- if $multiplier == 0
520
- index = tv.current_index
521
- art = get_item_for_line index
522
- end
523
- show_links art
524
- }
815
+ #tv.bind(:PRESS) {|ev| display_links }
525
816
  tv.text_patterns[:articles] = Regexp.new(/^ *\d+ /)
526
817
  tv.bind_key(KEY_TAB, "goto article") { tv.next_regex(:articles) }
527
818
  end # stack
528
819
 
529
- sl = status_line :row => Ncurses.LINES-1, :bgcolor => :yellow, :color => $color_scheme[3]
530
- choose_forum
820
+ sl = status_line :row => Ncurses.LINES-1, :bgcolor => :yellow, :color => @color_scheme[:status_bg]
821
+ @h.choose_forum
822
+ rescue => ex
823
+ textdialog ["Error in hackman: #{ex} ", *ex.backtrace], :title => "Exception"
824
+ $log.debug( ex) if ex
825
+ $log.debug(ex.backtrace.join("\n")) if ex
826
+ ensure
827
+ p ex if ex
828
+ p(ex.backtrace.join("\n")) if ex
829
+ end
531
830
  end # app
@@ -1,3 +1,3 @@
1
1
  module Hackercli
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hackercli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kepler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-11 00:00:00.000000000 Z
11
+ date: 2014-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler