hackercli 0.0.1 → 0.0.2

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: b99813316a49a7f734835aaf0d913f0e7f318fe5
4
- data.tar.gz: 7ef92b17ffc21396553663a3ec8471f0220ef1a6
3
+ metadata.gz: 75c4a562ea1421cb25e6e931f248fe548dca1455
4
+ data.tar.gz: 5eae9a7fae225f5466ce8c3e821cc3a438d72fad
5
5
  SHA512:
6
- metadata.gz: 9317754f66a17e8e6158aa0f61adaab78ed833959fd042f362f8964eb20ffb3c86eb4b171685a12657d7bd982c04b977ee099b3f48f779f1c7bbf54566ac70db
7
- data.tar.gz: cf74fa1d7c328e73bd433f1d4cae0857dab48270368899ebda3f9adf9b389861ac7d35af257472b555958cac2899b2e9cbb8afd38ddf5a500c19dc1d8d399096
6
+ metadata.gz: ecaef63610e4e8337bd71b3073c71f979c50b00e2629c3528125844ca2c3bf4b0fc5dd7744b63855ec4315e8ac937f831cb1b48764dcd5e96289eca07a080648
7
+ data.tar.gz: 0016e69972886d8ec5ed937019b48e326b2f56cfa3105bb31014ceab1c4e9b7d3538b5ef39e7402e90f5d843daabaab259b59d2329520f406e3589ab27afe837
data/README.md CHANGED
@@ -6,51 +6,94 @@ provided. May be used as a filter for other commands.
6
6
  This is a single file and so may be placed anywhere in the path. Also, one may include it in a project
7
7
  and get the array of hashes for each article and use as per requirements.
8
8
 
9
- This is NOT dependent on any other gem as it uses and parses the simple RSS feed using +String.scan+ only.
9
+ This is NOT dependent on any other gem as it uses and parses the simple RSS feed using `String.scan` only.
10
10
 
11
11
  The feed used for Hacker News is:
12
12
 
13
- https://news.ycombinator.com/bigrss
13
+ https://news.ycombinator.com/bigrss
14
14
 
15
15
  The feed used for Reddit News is (replace ruby with any other subreddit):
16
16
 
17
17
  http://www.reddit.com/r/ruby/.rss
18
18
 
19
19
  Please click these links and check if they are working if there is any problem.
20
+ To see current options:
20
21
 
21
- hackercli.rb --help
22
+ hackercli.rb --help
22
23
 
23
24
 
24
25
  ## Installation
25
26
 
26
- Or install it yourself as:
27
-
28
27
  $ gem install hackercli
29
28
 
30
29
  ## Usage
31
30
 
32
31
  hackercli.rb --help
33
32
 
34
- To view hacker news titles and info.
33
+ To view hacker news titles and urls
35
34
 
36
35
  hackercli.rb
36
+
37
+ hackercli.rb slashdot
38
+
39
+ Pipe to other commands (default separatar is a TAB)
40
+
41
+ hackercli.rb | cut -f1,2 | nl | sort -n -r
37
42
 
38
43
 
39
44
  To view only titles:
40
45
 
41
46
  hackercli.rb -t
42
47
 
48
+
49
+ To view description column also (this is normally not printed since it can be long):
50
+
51
+ hackercli.rb -v
52
+
43
53
  To view reddit ruby:
44
54
 
45
- hackercli.rb -s ruby
55
+ hackercli.rb ruby
56
+
57
+ hackercli.rb <subreddit>
46
58
 
47
59
  Present the URL of some other RSS feed:
48
60
 
49
- hackercli.rb -u https://someurl.com/.rss
61
+ hackercli.rb -u http://feeds.arstechnica.com/arstechnica/index
62
+
63
+ hackercli.rb -u http://feeds.boingboing.net/boingboing/iBag
64
+
65
+ Save output to a YML file:
66
+
67
+ hackercli.rb -y ruby.yml ruby
68
+
69
+ Please try the `--help` option to see current feeds supported, and latest options.
50
70
 
51
71
  NOTE: this has been tested only with Hackernews bigrss and reddit news' RSS, so I cannot gaurantee
52
72
  how it will behave with others. Some tags such as item, title and link are expected to be present.
53
73
 
74
+ ## Changes
75
+
76
+ ### 0.0.2
77
+
78
+ - Earlier the `-s` option was used to specify subforum. Now, it is not an option. subforum is passed
79
+ as an argument.
80
+
81
+ - Save to YML. I would prefer to use this in a client program rather than use tabbed output.
82
+ The YML file contains descriptive field which some callers may require.
83
+ The tabbed output does not contain description.
84
+
85
+ - Several other RSS feeds have been checked out such as **slashdot** and **arstechnica**.
86
+ You may pass "*ars:open-source*" or "*ars:software*" as an argument.
87
+ Check `--help` for latest options and features.
88
+
89
+ ## Upcoming
90
+
91
+ I've added a curses frontend to the generated yml files in bin named `hackman`, which depends on the
92
+ curses library `canis`. I am making it key-binding compliant with `corvus`, so one may switch from one
93
+ to the other without problems.
94
+
95
+ Should store the files in given location, read up forum list and other things from an info file.
96
+ (Perhaps share with corvusinfo).
54
97
 
55
98
  ## Testing and debugging
56
99
 
@@ -62,11 +105,17 @@ the program.
62
105
 
63
106
  ## See Also:
64
107
 
108
+ ### rubygems
109
+
110
+ https://rubygems.org/gems/hackercli
111
+
65
112
  ### hacker-curse
66
113
 
67
- This uses nokogiri to parse the actual Hackernews (or reddit) page, and can print on the CLI as well as
114
+ hacker-curse uses nokogiri to parse the actual Hackernews (or reddit) page, and can print on the CLI as well as
68
115
  be used as a library for another application. hacker-curse also provides a curses interface for viewing titles
69
- and comments, and launching the article or comments page in the GUI browser.
116
+ and comments, and launching the article or comments page in the GUI browser. Currently, the frontend is being
117
+ developed. The library is ready and is on github. It contains a non-curses client named `corvus` which you should
118
+ try.
70
119
 
71
120
  ## Contributing
72
121
 
@@ -75,3 +124,6 @@ and comments, and launching the article or comments page in the GUI browser.
75
124
  3. Commit your changes (`git commit -am 'Add some feature'`)
76
125
  4. Push to the branch (`git push origin my-new-feature`)
77
126
  5. Create a new Pull Request
127
+
128
+ Please let me know if you find this useful, or write a front-end for this. I'd like to know how to make this more
129
+ useful, and include a link to your repo.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # ----------------------------------------------------------------------------- #
3
- # File: bigrss.rb
3
+ # File: hackercli.rb
4
4
  # Description: reads Hacker News bigrss feed and prints out
5
5
  # Also works with reddit's rss feed
6
6
  #
@@ -8,15 +8,18 @@
8
8
  # titles and connecting to the page. HN's rss does not provide any info
9
9
  # such as points/age etc. Reddit provides a little more but has to be parsed.
10
10
  #
11
- # Currently saves downloaded file as "last.rss" so you may rerun queries on it
11
+ # Currently saves downloaded file as "<forum>.rss" so you may rerun queries on it
12
12
  # using the "-u" flag.
13
13
  #
14
+ # Caveats: fails if newlines in rss feed as in case of arstechnical
15
+ # We need to join the lines first so that scan can work
16
+ #
14
17
  # Author: j kepler http://github.com/mare-imbrium/canis/
15
18
  # Date: 2014-07-20 - 11:37
16
19
  # License: MIT
17
20
  # Last update: 2014-07-21 17:50
18
21
  # ----------------------------------------------------------------------------- #
19
- # bigrss.rb Copyright (C) 2012-2014 j kepler
22
+ # hackercli.rb Copyright (C) 2012-2014 j kepler
20
23
 
21
24
  require 'open-uri'
22
25
  require 'cgi'
@@ -31,16 +34,28 @@ class Bigrss
31
34
  #instance_eval &block if block_given?
32
35
  end
33
36
 
37
+ # # returns a hash containing :articles array, and one or two outer fields such as page_url and time
38
+ # returns an array containing a hash for each article
39
+ # The hash contains :title, :url, :comments_url and in some case :pubdata and comments_count
34
40
  def run
41
+ page = {}
42
+
35
43
  resp = []
36
44
  filename = @options[:url]
45
+ page[:page_url] = filename
46
+ now = Time.now
47
+ page[:create_time_seconds] = now.to_i
48
+ page[:create_time] = now.to_s
49
+ page[:articles] = resp
37
50
  f = open(filename)
38
- content = f.read
51
+ outfile = @options[:subreddit] || "last"
52
+ # ars technical sends in new lines
53
+ content = f.read.delete("\n")
39
54
  content.gsub!('&#x2F;',"/")
40
55
  content.gsub!('&#x27;',"'")
41
56
  content.gsub!('&#x34;','"')
42
57
  content = CGI.unescapeHTML(content)
43
- File.open("last.rss","w") {|ff| ff.write(content) }
58
+ File.open("#{outfile}.rss","w") {|ff| ff.write(content) }
44
59
  items = content.scan(/<item>(.*?)<\/item>/)
45
60
  items.each_with_index do |e,i|
46
61
  e = e.first
@@ -48,6 +63,8 @@ class Bigrss
48
63
  title = e.scan(/<title>(.*?)<\/title/).first.first
49
64
  h[:title] = title
50
65
  url = e.scan(/<link>(.*?)<\/link/).first.first
66
+ # in the case of hacker news this is the article url
67
+ # In the case of reddit, this is the comment url along with comment url
51
68
  h[:url] = url
52
69
  comment_url = ""
53
70
  # HN has comments links in a tag
@@ -73,7 +90,7 @@ class Bigrss
73
90
  end
74
91
  #puts " #{title}#{sep}#{url}#{sep}#{comment_url}"
75
92
  end
76
- return resp unless block_given?
93
+ return page unless block_given?
77
94
  end
78
95
  def extract_part e, tag, hash
79
96
  if e.index("<#{tag}>")
@@ -103,6 +120,12 @@ end
103
120
 
104
121
 
105
122
 
123
+ def to_yml outfile, arr
124
+ require 'yaml'
125
+ File.open(outfile, 'w' ) do |f|
126
+ f << YAML::dump(arr)
127
+ end
128
+ end
106
129
 
107
130
 
108
131
 
@@ -111,11 +134,40 @@ end
111
134
  if true
112
135
  begin
113
136
  url = nil
137
+ ymlfile = nil
114
138
  # http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
115
139
  require 'optparse'
116
140
  options = {}
141
+ appname = File.basename $0
117
142
  OptionParser.new do |opts|
118
- opts.banner = "Usage: #{$0} [options]"
143
+ opts.banner =
144
+ %Q{
145
+ Usage: #{$0} [options]
146
+ Examples:
147
+ Display Hacker News titles and urls:
148
+ #{appname}
149
+ #{appname} hacker
150
+ Display subreddits from reddit.com:
151
+ #{appname} programming
152
+ #{appname} ruby
153
+ Display info from other sites:
154
+ #{appname} ars # index from arstechnica
155
+ #{appname} ars:software # software from arstechnica
156
+ #{appname} ars:open-source # open-source from arstechnica
157
+ #{appname} slashdot
158
+ Display info from a saved rss file:
159
+ #{appname} -u ruby.rss
160
+ Save info from reddit ruby to a YML file:
161
+ #{appname} -y ruby.yml ruby
162
+ Display info from another url:
163
+ #{appname} -u http://feeds.boingboing.net/boingboing/iBag
164
+ #{appname} -u http://www.lifehacker.co.in/rss_tag_section_feeds.cms?query=productivity
165
+ #{appname} -u http://rss.slashdot.org/Slashdot/slashdot
166
+ #{appname} -u http://feeds.arstechnica.com/arstechnica/open-source
167
+ #{appname} -u http://feeds.arstechnica.com/arstechnica/software
168
+
169
+
170
+ }
119
171
 
120
172
  opts.on("-v", "--[no-]verbose", "Print description also") do |v|
121
173
  options[:verbose] = v
@@ -129,10 +181,13 @@ if true
129
181
  opts.on("-d SEP", String,"--delimiter", "Delimit columns with SEP") do |v|
130
182
  options[:delimiter] = v
131
183
  end
132
- opts.on("-s SUBREDDIT", String,"--subreddit", "Get articles from subreddit named SUBREDDIT") do |v|
133
- options[:subreddit] = v
134
- url = "http://www.reddit.com/r/#{v}/.rss"
184
+ opts.on("-y yml path", String,"--yml-path", "save as YML file") do |v|
185
+ ymlfile = v
135
186
  end
187
+ #opts.on("-s SUBREDDIT", String,"--subreddit", "Get articles from subreddit named SUBREDDIT") do |v|
188
+ #options[:subreddit] = v
189
+ #url = "http://www.reddit.com/r/#{v}/.rss"
190
+ #end
136
191
  opts.on("-u URL", String,"--url", "Get articles from URL/file") do |v|
137
192
  url = v
138
193
  end
@@ -141,11 +196,43 @@ if true
141
196
  #p options
142
197
  #p ARGV
143
198
 
144
- #filename=ARGV[0];
145
- url ||= "https://news.ycombinator.com/bigrss"
199
+ v = ARGV[0];
200
+ if v
201
+ case v
202
+ when "news", "hacker", "hn"
203
+ url = "https://news.ycombinator.com/bigrss"
204
+ options[:subreddit] = "hacker"
205
+ when "slashdot"
206
+ url = "http://rss.slashdot.org/Slashdot/slashdot"
207
+ options[:subreddit] = "slashdot"
208
+ when "ars"
209
+ url = "http://feeds.arstechnica.com/arstechnica/index"
210
+ options[:subreddit] = "arstechnica"
211
+ else
212
+ if v.index("ars:") == 0
213
+ subf = v.split(":")
214
+ url = "http://feeds.arstechnica.com/arstechnica/#{subf.last}"
215
+ options[:subreddit] = subf.join("_")
216
+ else
217
+ url = "http://www.reddit.com/r/#{v}/.rss"
218
+ options[:subreddit] = v
219
+ end
220
+ end
221
+ end
222
+ unless url
223
+ url ||= "https://news.ycombinator.com/bigrss"
224
+ options[:subreddit] = "hacker"
225
+ end
226
+ #$stderr.puts "url is: #{url} "
227
+
146
228
  options[:url] = url
147
229
  klass = Bigrss.new options
148
- arr = klass.run
230
+ page = klass.run
231
+ if ymlfile
232
+ to_yml ymlfile, page
233
+ exit
234
+ end
235
+ arr = page[:articles]
149
236
  titles_only = options[:titles]
150
237
  sep = options[:delimiter] || "\t"
151
238
  limit = options[:number] || arr.count
@@ -0,0 +1,531 @@
1
+ #!/usr/bin/env ruby
2
+ # ----------------------------------------------------------------------------- #
3
+ # File: hackman.rb
4
+ # Description: curses frontend for rss feeds generated by hackercli
5
+ # Author: j kepler http://github.com/mare-imbrium/canis/
6
+ # Date: 2014-08-09 - 10:12
7
+ # License: MIT
8
+ # Last update: 2014-08-11 21:30
9
+ # ----------------------------------------------------------------------------- #
10
+ # hackman.rb Copyright (C) 2012-2014 j kepler
11
+ # encoding: utf-8
12
+ require 'canis/core/util/app'
13
+ require 'canis/core/util/rcommandwindow'
14
+ require 'fileutils'
15
+ require 'pathname'
16
+ require 'canis/core/include/defaultfilerenderer'
17
+ require 'canis/core/include/appmethods'
18
+
19
+ # TODO :
20
+ # - add to forum list, remove, save
21
+ # - 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
+ #
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
27
+ #
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)
83
+ #
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)
104
+ end
105
+ 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)
162
+ end
163
+ #
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
182
+ end
183
+
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
187
+
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
195
+ end
196
+ # close if escape or double escape
197
+ if ch == 27 || ch == 2727
198
+ return nil
199
+ end
200
+ lb.handle_key ch
201
+ form.repaint
202
+ end
203
+ end
204
+ ensure
205
+ window.destroy
206
+ 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} ]"
326
+ 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]
370
+ end
371
+ if a.key? :pubdate
372
+ detail << a[:pubdate]
373
+ end
374
+ unless detail.empty?
375
+ l = "#[fg=green]" + " " + detail.join(" | ") + "#[end]"
376
+ lines << l
377
+ end
378
+ end
379
+ @hash[:diff] ||= lines.size - @hash[:first]
380
+ end
381
+ w.text(lines, :content_type => :tmux)
382
+ w.title "[ #{file} ]"
383
+
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}")
400
+ end
401
+ 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
411
+ links = {}
412
+ keys = %w{a b c d e f}
413
+ i = 0
414
+ art.each_pair do |k, p|
415
+ if p.index("http") == 0
416
+ links[keys[i]] = p
417
+ i += 1
418
+ end
419
+ end
420
+ ch, binding = menu "Links Menu", links
421
+ #alert "is #{index}: #{art[:title]} #{ch}:#{binding} "
422
+ if binding
423
+ open_url binding
424
+ end
425
+ end
426
+ ht = 24
427
+ borderattrib = :reverse
428
+ @header = app_header "hackman #{VERSION}", :text_center => "RSS Reader", :name => "header",
429
+ :text_right =>"Press =", :color => :white, :bgcolor => $color_scheme[0]
430
+ message "Press F10 (or qq) to exit, F1 Help, ` for Menu "
431
+
432
+
433
+
434
+ # commands that can be mapped to or executed using M-x
435
+ # however, commands of components aren't yet accessible.
436
+ def get_commands
437
+ %w{ choose_forum next_forum prev_forum }
438
+ end
439
+ def help_text
440
+ <<-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.
447
+
448
+ : - Command mode
449
+ F1 - Help
450
+ F10 - Quit application
451
+ 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.
475
+
476
+ -----------------------------------------------------------------------
477
+ :n or Alt-n for general help.
478
+ eos
479
+ end
480
+
481
+ #install_help_text help_text
482
+
483
+ def app_menu
484
+ @curdir ||= Dir.pwd
485
+ Dir.chdir(@curdir) if Dir.pwd != @curdir
486
+ require 'canis/core/util/promptmenu'
487
+ menu = PromptMenu.new self do
488
+ item :f, :choose_forum
489
+ item :t, :testdisplay_text
490
+ end
491
+ menu.display_new :title => "Menu"
492
+ end
493
+ # 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"; }
500
+ @form.bind_key(?=, "Toggle Menu") {
501
+ toggle_menu;
502
+ }
503
+ @form.bind_key(?<, "Previous Forum") { prev_forum; }
504
+ @form.bind_key(?>, "Next Forum") { next_forum; }
505
+
506
+ stack :margin_top => 1, :margin_left => 0, :width => :expand , :height => FFI::NCurses.LINES-2 do
507
+ tv = textpad :height_pc => 100, :width_pc => 100, :name => "tv", :suppress_borders => true,
508
+ :bgcolor => $color_scheme[2], :color => 255, :attr => NORMAL
509
+ #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
+ }
525
+ tv.text_patterns[:articles] = Regexp.new(/^ *\d+ /)
526
+ tv.bind_key(KEY_TAB, "goto article") { tv.next_regex(:articles) }
527
+ end # stack
528
+
529
+ sl = status_line :row => Ncurses.LINES-1, :bgcolor => :yellow, :color => $color_scheme[3]
530
+ choose_forum
531
+ end # app
@@ -1,3 +1,3 @@
1
1
  module Hackercli
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
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.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - kepler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-21 00:00:00.000000000 Z
11
+ date: 2014-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,6 +44,7 @@ email:
44
44
  - githubkepler.50s@gishpuppy.com
45
45
  executables:
46
46
  - hackercli.rb
47
+ - hackman.rb
47
48
  extensions: []
48
49
  extra_rdoc_files: []
49
50
  files:
@@ -53,6 +54,7 @@ files:
53
54
  - README.md
54
55
  - Rakefile
55
56
  - bin/hackercli.rb
57
+ - bin/hackman.rb
56
58
  - hackercli.gemspec
57
59
  - lib/hackercli.rb
58
60
  - lib/hackercli/version.rb