rubytext 0.1.23 → 0.1.25

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
  SHA256:
3
- metadata.gz: 64b02560a60dde6b8be61c328c5ef17783f04f4d1f0d0fcdc3d01be2d1e77407
4
- data.tar.gz: 2901d7e3edd0b8df5eae3c0fe010d5b609feb125e00f79bf659e34b8cd8ce377
3
+ metadata.gz: 404061798371be530a55ad03d0c679b8d187aeee89dd40450e38d73591cacda5
4
+ data.tar.gz: 3a9587a311670022ff32037159c71e1c260f23f4bffca9365c77ecc90e3aa960
5
5
  SHA512:
6
- metadata.gz: a240d93d49063fb3428353080f30d7eecec11b2140c11cfd4552495fd663ebc987c6155f98cf72008795328779c1c09eb372c25c495ecfa3bc149c2bb502c89b
7
- data.tar.gz: 3aee37214e7afb38b29b5cfabb5d5f67b8217e777b42ca95db55bc85299ccf4bd8b51aecfab1bada8fa99aa2489420b4ff92f1a6c52fae5b16673093980e7944
6
+ metadata.gz: a086383fbc7a3b82b816f5f03b585ae86cecb15ebf123975d4d0f47c804e44bbec80f733a213526b93cb554a50d059e29f8a521b1dfd748b4755df038b465c9f
7
+ data.tar.gz: 0a1582a8bbdd7047a909611e6afa2b9cc38c6036053e82f45c20c3c388d7749488ee479e28e9efd436102a3a09156130eceace11159fc3fd9116eed8aa42ba3d
@@ -0,0 +1,56 @@
1
+ if ARGV.size != 2
2
+ STDERR.puts "Usage: ruby ide.rb libname.rb progname.rb"
3
+ exit
4
+ end
5
+
6
+ require 'rubytext'
7
+
8
+ RubyText.start
9
+
10
+ @lib, @code = ARGV
11
+
12
+ def shell(str)
13
+ STDSCR.clear
14
+ RubyText.show_cursor
15
+ system("stty sane") # FIXME - dumb hack
16
+ STDSCR.puts "\n\n When you exit, you will\n return to the IDE.\n "
17
+ system(str)
18
+ Curses.noecho # FIXME Shouldn't have to do this stuff
19
+ Curses.stdscr.keypad(true)
20
+ Curses.cbreak # by default
21
+ end
22
+
23
+ items = ["Edit lib", # 0
24
+ "Edit code", # 1
25
+ "Run code", # 2
26
+ "pry", # 3
27
+ "Shell", # 4
28
+ "irb", # 5
29
+ "RubyDocs", # 6
30
+ "Quit"] # 7
31
+
32
+ def show
33
+ STDSCR.clear
34
+ puts
35
+ puts " World's Simplest Ruby IDE\n "
36
+ puts " Lib = #{@lib}"
37
+ puts " Code = #{@code}"
38
+ puts
39
+ end
40
+
41
+ loop do
42
+ show
43
+ n, str = STDSCR.menu(r: 10, c: 5, items: items)
44
+ puts n.inspect
45
+ case n
46
+ when 0; system("vi #{@lib}")
47
+ when 1; system("vi #{@code}")
48
+ when 2; system("tput clear; ruby #{@code}; sleep 5")
49
+ when 3; shell("pry")
50
+ when 4; shell("bash")
51
+ when 5; shell("irb")
52
+ when 6; system("open -a Safari http://ruby-doc.org")
53
+ when 7; exit
54
+ end
55
+ end
56
+
data/lib/menu.rb CHANGED
@@ -1,3 +1,313 @@
1
+ #### FIXME LATER
2
+
3
+ # The top-level module
4
+
5
+ module RubyText
6
+
7
+ # Wrapper for a curses window
8
+
9
+ class Window
10
+
11
+ class Menu2D
12
+
13
+ class Vertical
14
+ attr_reader :widest, :height, :header, :hash
15
+ def initialize(vlist)
16
+ @header = vlist[0]
17
+ @hash = vlist[1]
18
+ @widest = @header.length
19
+ @hash.each_pair {|k,v| puts "k = #{k.inspect}"; getch; @widest = [@widest, k.length].max }
20
+ @height = @hash.size
21
+ end
22
+ end
23
+
24
+ def initialize(win:, r: :center, c: :center, items:, colrow: [0, 0],
25
+ border: true, title: nil, fg: Green, bg: Black)
26
+ @win = win
27
+ @list = []
28
+ @header = @list.map {|x| x.header }
29
+ items.each {|vlist| @list << Vertical.new(vlist) }
30
+ @highest = @list.map {|x| x.height }.max
31
+ @full_width = @list.inject(0) {|sum, vlist| sum += vlist.widest + 2 }
32
+ @nlists = items.size
33
+ @grid = Array.new(@nlists) # column major order
34
+ @grid.map! {|x| [" "] * @highest }
35
+ @list.each.with_index do |vlist, i|
36
+ vlist.hash.each_pair.with_index do |kv, j|
37
+ k, v = kv
38
+ @grid[i][j] = [k, v]
39
+ end
40
+ end
41
+ RubyText.hide_cursor
42
+ @high = @highest
43
+ @wide = @full_width
44
+ @high += 2 if border
45
+ @wide += 2 if border
46
+
47
+ tlen = title.length + 8 rescue 0
48
+ # wide = [wide, tlen].max
49
+ row, col = @win.coords(r, c)
50
+ row = row - @high/2 if r == :center
51
+ col = col - @wide/2 if c == :center
52
+ r, c = row, col
53
+ @win.saveback(@high+1, @wide, r, c)
54
+ mr, mc = r+@win.r0, c+@win.c0
55
+ title = nil unless border
56
+
57
+ @mwin = RubyText.window(@high+1, @wide, r: mr, c: mc, border: true,
58
+ fg: fg, bg: bg, title: title)
59
+ @header.each {|head| printf "%-#{maxw}s", head }
60
+ puts # after header
61
+ Curses.stdscr.keypad(true)
62
+ maxcol = items.size - 1
63
+ sizes = items.map {|x| x.size }
64
+ max = sizes.max
65
+ # mwin.go(r, c)
66
+ r += 1 # account for header
67
+ @selc, @selr = colrow
68
+ end
69
+
70
+ def show(r, c, colrow: [0, 0])
71
+ @selc, @selr = colrow
72
+ @grid.each.with_index do |column, cix|
73
+ column.each.with_index do |pairs, rix| # {Jan: ..., Feb: ..., Mar: ..., ...}
74
+ # STDSCR.puts "go: #{r}+#{rix}, #{c}+#{cix}*#{maxw}"
75
+ @mwin.go(rix, cix) # FIXME wrong?
76
+ style = ([@selc, @selr] == [cix, rix]) ? :reverse : :normal
77
+ key, val = pairs
78
+ label = key.to_s
79
+ @mwin.print label # fx(label, style)
80
+ end
81
+ end
82
+ end
83
+
84
+ def handle(r, c)
85
+ loop do
86
+ show(r, c)
87
+ ch = getch
88
+ case ch
89
+ when RubyText::Window::Up
90
+ @selr -= 1 if @selr > 0
91
+ when RubyText::Window::Down
92
+ # puts "PAUSE r,c = #@selr #@selc highest=#@highest"; getch
93
+ @selr += 1 if @selr < @highest - 1
94
+ when RubyText::Window::Left
95
+ @selc -= 1 if @selc > 0
96
+ when RubyText::Window::Right
97
+ @selc += 1 if @selc < @full_width
98
+ when RubyText::Window::Esc
99
+ @win.restback(@high+1, @wide, r-1, c)
100
+ RubyText.show_cursor
101
+ return [nil, nil, nil]
102
+ when RubyText::Window::Enter
103
+ @win.restback(@high+1, @wide, r-1, c)
104
+ RubyText.show_cursor
105
+ choice = @grid[@selc][@selr][1]
106
+ case choice
107
+ when String;
108
+ puts "Returning #{[@selc, @selr, choice].inspect}"; getch
109
+ return [@selc, @selr, choice]
110
+ when NilClass; return [nil, nil, nil]
111
+ end
112
+ result = choice.call # should be a Proc
113
+ return [nil, nil, nil] if result.nil? || result.empty?
114
+ return result
115
+ else Curses.beep
116
+ end
117
+ end
118
+ RubyText.show_cursor
119
+ end
120
+ end
121
+
122
+
123
+ def rectmenu(r: :center, c: :center, items:, colrow: [0, 0],
124
+ border: true,
125
+ title: nil, fg: Green, bg: Black)
126
+ RubyText.hide_cursor
127
+ maxh, maxw = _rectmenu_maxes(items)
128
+ header, stuff = _rect_hash2array(items, maxh, maxw)
129
+ wide = items.size * maxw
130
+ high = maxh
131
+ high += 2 if border
132
+ wide += 2 if border
133
+
134
+ tlen = title.length + 8 rescue 0
135
+ # wide = [wide, tlen].max
136
+ row, col = @win.coords(r, c)
137
+ row = row - high/2 if r == :center
138
+ col = col - wide/2 if c == :center
139
+ r, c = row, col
140
+ @win.saveback(high+1, wide, r, c)
141
+ mr, mc = r+@win.r0, c+@win.c0
142
+ title = nil unless border
143
+
144
+ mwin = RubyText.window(high+1, wide, r: mr, c: mc, border: true,
145
+ fg: fg, bg: bg, title: title)
146
+ header.each {|head| printf "%-#{maxw}s", head }
147
+ puts # after header
148
+ Curses.stdscr.keypad(true)
149
+ maxcol = items.size - 1
150
+ sizes = items.map {|x| x.size }
151
+ max = sizes.max
152
+ # mwin.go(r, c)
153
+ r += 1 # account for header
154
+ selc, selr = colrow
155
+
156
+ loop do
157
+ RubyText.hide_cursor # FIXME should be unnecessary
158
+ stuff.each.with_index do |column, cix|
159
+ column.each.with_index do |pairs, rix| # {Jan: ..., Feb: ..., Mar: ..., ...}
160
+ STDSCR.puts "go: #{r}+#{rix}, #{c}+#{cix}*#{maxw}"
161
+ mwin.go(rix+1, cix*maxw)
162
+ style = ([selc, selr] == [cix, rix]) ? :reverse : :normal
163
+ key, val = pairs
164
+ label = key.to_s
165
+ # mwin.print fx(label, style)
166
+ mwin.print label # fx(label, style)
167
+ end
168
+ end
169
+ ch = getch
170
+ case ch
171
+ when Up
172
+ selr -= 1 if selr > 0
173
+ when Down
174
+ selr += 1 if selr < maxh - 1
175
+ when Left
176
+ selc -= 1 if selc > 0
177
+ when Right
178
+ selc += 1 if selc < maxcol
179
+ when Esc
180
+ self.restback(high+1, wide, r-1, c)
181
+ RubyText.show_cursor
182
+ return [nil, nil, nil]
183
+ when Enter
184
+ self.restback(high+1, wide, r-1, c)
185
+ RubyText.show_cursor
186
+ choice = stuff[selc][selr][1]
187
+ case choice
188
+ when String; return [selc, selr, choice]
189
+ when NilClass; return [nil, nil, nil]
190
+ end
191
+ result = choice.call # should be a Proc
192
+ return [nil, nil, nil] if result.nil? || result.empty?
193
+ return result
194
+ else Curses.beep
195
+ end
196
+ RubyText.show_cursor
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ module RubyText
203
+
204
+ # Two-paned widget with menu on left, informtional area on right
205
+
206
+ def self.selector(win: STDSCR, r: 0, c: 0, rows: 10, cols: 20,
207
+ items:, fg: White, bg: Blue,
208
+ win2:, callback:, enter: nil, quit: "q")
209
+ high = rows
210
+ wide = cols
211
+ mwin = RubyText.window(high, wide, r: r, c: c, fg: fg, bg: bg)
212
+ handler = callback
213
+ Curses.stdscr.keypad(true)
214
+ RubyText.hide_cursor
215
+ sel = 0
216
+ max = items.size - 1
217
+ handler.call(sel, items[sel], win2)
218
+ loop do
219
+ mwin.home
220
+ items.each.with_index do |item, row|
221
+ mwin.crlf
222
+ style = (sel == row) ? :reverse : :normal
223
+ mwin.print fx(" #{item}", style)
224
+ end
225
+ ch = getch
226
+ case ch
227
+ when Up
228
+ if sel > 0
229
+ sel -= 1
230
+ handler.call(sel, items[sel], win2)
231
+ end
232
+ when Down
233
+ if sel < max
234
+ sel += 1
235
+ handler.call(sel, items[sel], win2)
236
+ end
237
+ when Enter
238
+ if enter
239
+ del = enter.call(sel, items[sel], win2)
240
+ if del
241
+ items -= [items[sel]]
242
+ raise
243
+ end
244
+ end
245
+ when Tab
246
+ Curses.flash
247
+ when quit # parameter
248
+ exit
249
+ else Curses.beep # all else is trash
250
+ end
251
+ end
252
+ rescue
253
+ retry
254
+ end
255
+
256
+ # "Menu" for checklists
257
+
258
+ def checklist(r: :center, c: :center,
259
+ items:, curr: 0, selected: [],
260
+ title: nil, sel_fg: Yellow, fg: White, bg: Blue)
261
+ RubyText.hide_cursor
262
+ high = items.size + 2
263
+ wide = items.map(&:length).max + 8
264
+ tlen = title.length + 8 rescue 0
265
+ wide = [wide, tlen].max
266
+ row, col = self.coords(r, c)
267
+ row = row - high/2 if r == :center
268
+ col = col - wide/2 if c == :center
269
+ r, c = row, col
270
+ self.saveback(high, wide, r, c)
271
+ mr, mc = r+self.r0, c+self.c0
272
+ mwin = RubyText.window(high, wide, r: mr, c: mc,
273
+ fg: fg, bg: bg, title: title)
274
+ Curses.stdscr.keypad(true)
275
+ sel = curr
276
+ max = items.size - 1
277
+ loop do
278
+ RubyText.hide_cursor # FIXME should be unnecessary
279
+ items.each.with_index do |item, row|
280
+ mwin.go row, 0
281
+ style = (sel == row) ? :reverse : :normal
282
+ color = selected.find {|x| x[0] == row } ? sel_fg : fg
283
+ label = "[ ]" + item
284
+ mwin.print fx(label, color, style)
285
+ end
286
+ ch = getch
287
+ case ch
288
+ when Up
289
+ sel -= 1 if sel > 0
290
+ when Down
291
+ sel += 1 if sel < max
292
+ when Esc
293
+ self.restback(high, wide, r, c)
294
+ RubyText.show_cursor
295
+ return []
296
+ when Enter
297
+ self.restback(high, wide, r, c)
298
+ RubyText.show_cursor
299
+ return selected.map {|i| items[i] }
300
+ when " "
301
+ selected << [sel, items[sel]]
302
+ sel += 1 if sel < max
303
+ else Curses.beep
304
+ end
305
+ RubyText.show_cursor
306
+ end
307
+ end
308
+
309
+ end
310
+
1
311
  # The top-level module
2
312
 
3
313
  module RubyText
@@ -9,16 +319,13 @@ module RubyText
9
319
  # One-line menu at top of window
10
320
 
11
321
  def topmenu(items:, curr: 0, fg: Green, bg: Black)
12
- r, c = 0, 0
13
- high = 1
14
-
322
+ r, c, high = 0, 0, 1
15
323
  RubyText.hide_cursor
324
+ hash_flag = false
325
+ results = items
16
326
  if items.is_a?(Hash)
17
- results = items.values
18
- items = items.keys
327
+ results, items = items.values, items.keys
19
328
  hash_flag = true
20
- else
21
- results = items
22
329
  end
23
330
 
24
331
  width = 0 # total width
@@ -52,16 +359,19 @@ module RubyText
52
359
  when Esc, " " # spacebar also quits
53
360
  self.restback(high, width, r, c)
54
361
  RubyText.show_cursor
362
+ STDSCR.go r, c
55
363
  return [nil, nil]
56
364
  when Down, Enter
57
365
  self.restback(high, width, r, c)
58
366
  RubyText.show_cursor
367
+ STDSCR.go r, c
59
368
  choice = results[sel]
60
369
  return [sel, choice] if choice.is_a? String
61
370
  result = choice.call
62
- next if result.nil?
63
- next if result.empty?
64
- return result
371
+ return [nil, nil, nil] if result.nil? || result.empty?
372
+ # next if result.nil?
373
+ # next if result.empty?
374
+ # return result
65
375
  else Curses.beep
66
376
  end
67
377
  RubyText.show_cursor
@@ -72,7 +382,7 @@ module RubyText
72
382
 
73
383
  def menu(r: :center, c: :center, items:, curr: 0,
74
384
  border: true, sticky: false,
75
- title: nil, fg: Green, bg: Black)
385
+ title: nil, fg: Green, bg: Black, wrap: false)
76
386
  RubyText.hide_cursor
77
387
  if items.is_a?(Hash)
78
388
  results = items.values
@@ -112,9 +422,17 @@ module RubyText
112
422
  ch = getch
113
423
  case ch
114
424
  when Up
115
- sel -= 1 if sel > 0
116
- when Down
117
- sel += 1 if sel < max
425
+ if sel > 0
426
+ sel -= 1
427
+ else
428
+ sel = max if wrap # asteroids mode :)
429
+ end
430
+ when Down, " " # let space mean down?
431
+ if sel < max
432
+ sel += 1
433
+ else
434
+ sel = 0 if wrap # asteroids mode :)
435
+ end
118
436
  when Esc
119
437
  self.restback(high, wide, r, c)
120
438
  RubyText.show_cursor
@@ -377,3 +695,4 @@ module RubyText
377
695
 
378
696
  end
379
697
 
698
+
@@ -1,6 +1,6 @@
1
1
 
2
2
  module RubyText
3
- VERSION = "0.1.23"
3
+ VERSION = "0.1.25"
4
4
 
5
5
  Path = File.expand_path(File.join(File.dirname(__FILE__)))
6
6
  end
data/lib/settings.rb CHANGED
@@ -9,7 +9,7 @@ module RubyText
9
9
  @current = @defaults.dup
10
10
  @stack = []
11
11
  @stack.push @current # Note: Never let stack be empty
12
- set_curses(@current) # Set them for real
12
+ set_curses(**@current) # Set them for real
13
13
  # FIXME To be continued...
14
14
  end
15
15
 
@@ -39,7 +39,7 @@ module RubyText
39
39
  cursor ||= @current[:cursor]
40
40
  @stack.push @current
41
41
  @current = {raw: raw, echo: echo, cbreak: cbreak, keypad: keypad, cursor: cursor}
42
- set_curses(@current)
42
+ set_curses(**@current)
43
43
  end
44
44
 
45
45
  def reset_boolean
@@ -57,7 +57,7 @@ module RubyText
57
57
  sym0 = val ? sym : str[1..-1].to_sym
58
58
  list[sym0] = val
59
59
  end
60
- set_boolean(list)
60
+ set_boolean(**list)
61
61
  # allow a block here?
62
62
  end
63
63
 
@@ -130,7 +130,7 @@ module RubyText
130
130
  if name[0] == '_'
131
131
  Curses.send(name[1..-1], *args)
132
132
  else
133
- raise "#{name} #{args.inspect}" # NoMethodError
133
+ raise "Missing: #{name} #{args.inspect}" # NoMethodError
134
134
  end
135
135
  end
136
136
 
data/lib/widgets.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+
1
3
  module RubyText
2
4
  def self.ticker(row: STDSCR.rows-1, col: 0, width: STDSCR.cols,
3
5
  fg: White, bg: Blue, text:, delay: 0.1)
@@ -35,14 +37,20 @@ module RubyText
35
37
  ret
36
38
  end
37
39
 
38
- def self.splash(msg)
40
+ def self.splash(msg = nil)
41
+ io = StringIO.new("")
42
+ if msg.nil?
43
+ yield io
44
+ msg = io.string
45
+ end
46
+
39
47
  lines = msg.split("\n")
40
48
  high = lines.size + 4
41
49
  wide = lines.map {|x| x.length }.max + 4
42
50
  r0 = (STDSCR.rows - high)/2
43
51
  c0 = (STDSCR.cols - wide)/2
44
52
  STDSCR.saveback(high, wide, r0, c0)
45
- win = RubyText.window(high, wide, r: r0, c: c0,
53
+ win = RubyText.window(high, wide, r: r0, c: c0, scroll: true,
46
54
  fg: White, bg: Red, title: "[Press any key]")
47
55
  win.print "\n "
48
56
  win.puts msg
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubytext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.23
4
+ version: 0.1.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hal Fulton
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-15 00:00:00.000000000 Z
11
+ date: 2022-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -72,6 +72,7 @@ files:
72
72
  - examples/sym_navigate.rb
73
73
  - examples/ticker_threads.rb
74
74
  - examples/topbottom.rb
75
+ - examples/topmenu.rb
75
76
  - examples/udlr_bang.rb
76
77
  - examples/updown_etc.rb
77
78
  - examples/win_centering.rb
@@ -145,7 +146,7 @@ homepage: https://github.com/Hal9000/rubytext
145
146
  licenses:
146
147
  - Ruby
147
148
  metadata: {}
148
- post_install_message:
149
+ post_install_message:
149
150
  rdoc_options: []
150
151
  require_paths:
151
152
  - lib
@@ -160,8 +161,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
161
  - !ruby/object:Gem::Version
161
162
  version: '0'
162
163
  requirements: []
163
- rubygems_version: 3.0.4
164
- signing_key:
164
+ rubygems_version: 3.1.2
165
+ signing_key:
165
166
  specification_version: 4
166
167
  summary: A thick wrapper for Curses
167
168
  test_files: []