hackercli 0.0.2 → 0.0.3

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 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