Module: Ribhu

Extended by:
Ribhu
Included in:
Ribhu
Defined in:
lib/ribhu.rb

Overview

require “ribhu/version”

Instance Method Summary collapse

Instance Method Details

#ask(prompt, dt = nil) ⇒ Object



426
427
428
# File 'lib/ribhu.rb', line 426

def ask prompt, dt=nil
  return get_line prompt
end

#calc_sta(pagesize, cur) ⇒ Object

calculate start of display based on current position This is the value ‘sta’ should have (starting index)

Parameters:

  • int

    pagesize : number of items on one page

  • int

    cur : current cursor position

Returns:

  • int : position where ‘sta’ should be



581
582
583
584
585
# File 'lib/ribhu.rb', line 581

def calc_sta pagesize, cur
  pages = (cur * 1.001 / pagesize).ceil
  pages -= 1 if pages > 0
  return pages * pagesize
end

#columnate(ary, sz) ⇒ Object

print in columns ary - array of data sz - lines in one column This is the original which did not format or color, but since we cannot truncate unless we have unformatted data i need to mix the functionality into columnate_with_indexing Called by print_help, this is generic and can be used as a common func



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/ribhu.rb', line 269

def columnate ary, sz
  buff=Array.new
  return buff if ary.nil? || ary.size == 0

  # ix refers to the index in the complete file list, wherease we only show 60 at a time
  ix=0
  while true
    ## ctr refers to the index in the column
    ctr=0
    while ctr < sz

      f = ary[ix]
      # deleted truncate and pad part since we expect cols to be sized same

      if buff[ctr]
        buff[ctr] += f
      else
        buff[ctr] = f
      end

      ctr+=1
      ix+=1
      break if ix >= ary.size
    end
    break if ix >= ary.size
  end
  return buff
end

#get_charObject

I thin we need to make this like the command line one TODO



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/ribhu.rb', line 343

def get_char
  w = @window || $window
  c = w.getchar
  case c
  when 13,10
    return "ENTER"
  when 32
    return "SPACE"
  when 127
    return "BACKSPACE"
  when 27
    return "ESCAPE"
  end
  keycode_tos c
  #  if c > 32 && c < 127
  #return c.chr
  #end
  ## use keycode_tos from Utils.
end

#get_index(key, vsz = 999) ⇒ Object

returns the integer offset in view (file array based on a-y za-zz and Za - Zz Called when user types a key

should we even ask for a second key if there are not enough rows
What if we want to also trap z with numbers for other purposes


326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/ribhu.rb', line 326

def get_index key, vsz=999
  i = $IDX.index(key)
  return i+$stact if i
  #sz = $IDX.size
  zch = nil
  if vsz > 25
    if key == "z" || key == "Z"
      #print key
      zch = get_char
      #print zch
      i = $IDX.index("#{key}#{zch}")
      return i+$stact if i
    end
  end
  return nil
end

#get_line(text, config = {}) ⇒ Object

identical to get_string but does not show as a popup with buttons, just ENTER This is required if there are multiple inputs required and having several get_strings one after the other seems really odd due to multiple popups Unlike, get_string this does not return a nil if C-c pressed. Either returns a string if ENTER pressed or a blank if C-c or Double Escape. So only blank to be checked TODO up arrow can access history



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'lib/ribhu.rb', line 390

def get_line text, config={}
  begin
    w = one_line_window
    form = RubyCurses::Form.new w
    config[:label] = text
    config[:row] = 0
    config[:col] = 1

    #f = Field.new form, :label => text, :row => 0, :col => 1
    f = Field.new form, config
    form.repaint
    w.wrefresh
    while((ch = w.getchar()) != FFI::NCurses::KEY_F10 )
      break if ch == 13
      if ch == 3 || ch == 27 || ch == 2727
        return ""
      end
      begin
        form.handle_key(ch)
        w.wrefresh
      rescue => err
        $log.debug( err) if err
        $log.debug(err.backtrace.join("\n")) if err
        textdialog ["Error in Messagebox: #{err} ", *err.backtrace], :title => "Exception"
        w.refresh # otherwise the window keeps showing (new FFI-ncurses issue)
        $error_message.value = ""
      ensure
      end
    end # while loop

  ensure
    w.destroy
    w = nil 
  end
  return f.text
end

#get_shortcut(ix) ⇒ Object

return shortcut for an index (offset in file array) use 2 more arrays to make this faster

if z or Z take another key if there are those many in view
Also, display ROWS * COLS so now we are not limited to 60.


315
316
317
318
319
320
321
# File 'lib/ribhu.rb', line 315

def get_shortcut ix
  return "<" if ix < $stact
  ix -= $stact
  i = $IDX[ix]
  return i if i
  return "->"
end

#get_single(text, config = {}) ⇒ Object

prints a prompt at bottom of screen, takes a character and returns textual representation of character (as per get_char) and not the int that window.getchar returns. It uses a window, so underlying text is not touched.



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/ribhu.rb', line 367

def get_single text, config={}
  w = one_line_window
  x = y = 0
  color = config[:color_pair] || $datacolor
  color=Ncurses.COLOR_PAIR(color);
  w.attron(color);
  w.mvprintw(x, y, "%s" % text);
  w.attroff(color);
  w.wrefresh
  Ncurses::Panel.update_panels
  chr = get_char
  w.destroy
  w = nil 
  return chr
end

#index_this_list(list) ⇒ Object

indexes and returns indexed and colored version of list using alpha as indexes See $IDX and get_shortcut for index details

Parameters:

  • Array

    a list of values to index which will then be displayed using a padpopup



218
219
220
221
222
223
224
225
226
227
# File 'lib/ribhu.rb', line 218

def index_this_list list
  alist = []
  list.each_with_index { |v, ix| 
    k = get_shortcut ix
    alist << " #[fg=yellow, bold] #{k.ljust(2)} #[end] #[fg=green]#{v}#[end]" 
    # above gets truncated by columnate and results in errors in colorparsers etc
    #alist << " #{k} #{v}" 
  }
  return alist
end

#indexed_list(title, list, config = {}, &block) ⇒ Object

a general function that creates a popup list after indexing the current list, takes a key and returns the value from the list that was selected, or nil if the value was invalid. Called by show_list (cygnus gem) which is in turn called by several methods.

Raises:

  • (ArgumentError)


239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/ribhu.rb', line 239

def indexed_list title, list, config={}, &block
  raise ArgumentError, "Nil list received by indexed_list" unless list
  $stact = 0
  alist = index_this_list list
  longest = list.max_by(&:length)
  #  s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
  config[:title] = title
  # if width is greater than size of screen then padfresh will return -1 and nothing will print
  config[:width] = [ longest.size() + 10, FFI::NCurses.COLS - 1 ].min
  config[:row] = config[:col] = 0
  ch = padpopup alist, config, &block
  return unless ch
  if ch.size > 1
    # could be a string due to pressing enter
    # but what if we format into multiple columns
    ch = ch.strip[0]
  end
  # we are checking this AFTER the popup has returned, what window will be used ?
  ch = get_index ch
  return nil unless ch

  return list[ch]
end

Menu creator which displays a menu and executes methods based on keys. In some cases, we call this and then do a case statement on either key or binding.

Call this with care if you do not intend values to be executed. Maybe that was a bad
idea to club execution with display.

Parameters:

  • String

    title

  • hash

    of keys and methods to call

Returns:

  • key pressed, and binding (if found, and responded)

Raises:

  • (ArgumentError)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ribhu.rb', line 89

def menu title, hash, config={}, &block
  raise ArgumentError, "Nil hash received by menu" unless hash
  list = []
  hash.each_pair { |k, v| list << "   #[fg=yellow, bold] #{k} #[/end]    #[fg=green] #{v} #[/end]" }
  #  s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
  config[:title] = title
  ch = padpopup list, config, &block
  return unless ch
  if ch.size > 1
    # could be a string due to pressing enter
    # but what if we format into multiple columns
    ch = ch.strip[0]
  end

  binding = hash[ch]
  binding = hash[ch.to_sym] unless binding
  if binding
    if respond_to?(binding, true)
      send(binding)
    end
  end
  return ch, binding
end

#padpopup(list, config = {}, &block) ⇒ Object

pops up a list, taking a single key and returning if it is in range of 33 and 126 Called by menu, print_help, show_marks etc You may pass valid chars or ints so it only returns on pressing those.

Parameters:

  • Array

    of lines to print which may be formatted using :tmux format

Returns:

  • character pressed (ch.chr)

  • nil if escape or C-q pressed



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/ribhu.rb', line 121

def padpopup list, config={}, &block
  max_visible_items = config[:max_visible_items]
  row = config[:row] || 5
  col = config[:col] || 5
  # format options are :ansi :tmux :none
  fmt = config[:format] || :tmux
  config.delete :format
  relative_to = config[:relative_to]
  if relative_to
    layout = relative_to.form.window.layout
    row += layout[:top]
    col += layout[:left]
  end
  config.delete :relative_to
  # still has the formatting in the string so length is wrong.
  #longest = list.max_by(&:length)
  width = config[:width] || 60
  if config[:title]
    width = config[:title].size + 2 if width < config[:title].size
  end
  height = config[:height]
  height ||= [max_visible_items || 25, list.length+2].min 
  #layout(1+height, width+4, row, col) 
  layout = { :height => 0+height, :width => 0+width, :top => row, :left => col } 
  window = VER::Window.new(layout)
  form = RubyCurses::Form.new window

  ## added 2013-03-13 - 18:07 so caller can be more specific on what is to be returned
  valid_keys_int = config.delete :valid_keys_int
  valid_keys_char = config.delete :valid_keys_char

  listconfig = config[:listconfig] || {}
  #listconfig[:list] = list
  listconfig[:width] = width
  listconfig[:height] = height
  #listconfig[:selection_mode] ||= :single
  listconfig.merge!(config)
  listconfig.delete(:row); 
  listconfig.delete(:col); 
  # trying to pass populists block to listbox
  lb = RubyCurses::TextPad.new form, listconfig, &block
  if fmt == :none
    lb.text(list)
  else
    lb.formatted_text(list, fmt)
  end
  #
  #window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
  form.repaint
  Ncurses::Panel.update_panels
  if valid_keys_int.nil? && valid_keys_char.nil?
    # changed 32 to 33 so space can scroll list
    valid_keys_int = (33..126)
  end

  begin
    while((ch = window.getchar()) != 999 )

      # if a char range or array has been sent, check if the key is in it and send back
      # else just stay here
      if valid_keys_char
        if ch > 32 && ch < 127
          chr = ch.chr
          return chr if valid_keys_char.include? chr
        end
      end

      # if the user specified an array or range of ints check against that
      # therwise use the range of 33 .. 126
      return ch.chr if valid_keys_int.include? ch

      case ch
      when ?\C-q.getbyte(0)
        break
      else
        if ch == 13 || ch == 10
          s = lb.current_value.to_s # .strip #if lb.selection_mode != :multiple
          return s
        end
        # close if escape or double escape
        if ch == 27 || ch == 2727
          return nil
        end
        lb.handle_key ch
        form.repaint
      end
    end
  ensure
    window.destroy  
  end
  return nil
end

#padpopuplist(list, config = {}, &block) ⇒ Object

COPIED FROM CYGNUS will go into rbcurse after i test this out

pad version of original popuplist Not used in cygnus, so will require testing if used from elsewhere Is meant to replace the original popuplist soon since the original list and other classes have too much work giong on in repaint. Single selection, selection is with ENTER key, SPACE scrolls

Parameters:

  • Array

    values to be displayed

  • Hash

    configuration settings such as row, col, width, height etc

Returns:

  • int - index in list if selected, nil if C-q pressed

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ribhu.rb', line 17

def padpopuplist list, config={}, &block
  raise ArgumentError, "Nil list received by popuplist" unless list

  max_visible_items = config[:max_visible_items]
  row = config[:row] || 5
  col = config[:col] || 5
  relative_to = config[:relative_to]
  if relative_to
    layout = relative_to.form.window.layout
    row += layout[:top]
    col += layout[:left]
  end
  config.delete :relative_to
  longest = list.max_by(&:length)
  width = config[:width] || longest.size()+2 # borders take 2
  if config[:title]
    width = config[:title].size + 2 if width < config[:title].size
  end
  height = config[:height]
  height ||= [max_visible_items || 10+2, list.length+2].min 
  #layout(1+height, width+4, row, col) 
  layout = { :height => 0+height, :width => 0+width, :top => row, :left => col } 
  window = VER::Window.new(layout)
  form = RubyCurses::Form.new window

  listconfig = config[:listconfig] || {}
  listconfig[:list] = list
  listconfig[:width] = width
  listconfig[:height] = height
  #listconfig[:selection_mode] ||= :single
  listconfig.merge!(config)
  listconfig.delete(:row); 
  listconfig.delete(:col); 
  # trying to pass populists block to listbox
  #lb = RubyCurses::List.new form, listconfig, &block
  lb = RubyCurses::TextPad.new form, listconfig, &block
  #lb = Cygnus::TextPad.new form, :height => height, :width => width, :row => 0, :col => 0 , :title => "A title", :name => "popup"
  lb.text(list)
  #
  #window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
  form.repaint
  Ncurses::Panel.update_panels
  begin
    while((ch = window.getchar()) != 999 )
      case ch
      when ?\C-q.getbyte(0)
        break
      else
        lb.handle_key ch
        form.repaint
        if ch == 13 || ch == 10
          return lb.current_index #if lb.selection_mode != :multiple
        end
        #yield ch if block_given?
      end
    end
  ensure
    window.destroy  
  end
  return nil
end

#padup_list(list) ⇒ Object

justify or pad list with spaces so we can columnate, uses longest item to determine size

Parameters:

  • list

    to pad

Returns:

  • list padded with spaces



433
434
435
436
437
438
439
440
# File 'lib/ribhu.rb', line 433

def padup_list list
  longest = list.max_by(&:length)
  llen = longest.size
  alist = list.collect { |x|
    x.ljust(llen)
  }
  alist
end

#pause(text = " Press a key ...") ⇒ Object



307
308
309
310
# File 'lib/ribhu.rb', line 307

def pause text=" Press a key ..."
  get_single text
  #get_char
end

#pbold(text) ⇒ Object



297
298
299
300
# File 'lib/ribhu.rb', line 297

def pbold text
  #puts "#{BOLD}#{text}#{BOLD_OFF}"
  get_single text, :color_pair => $reversecolor
end

#perror(text) ⇒ Object



301
302
303
304
305
306
# File 'lib/ribhu.rb', line 301

def perror text
  ##puts "#{RED}#{text}#{CLEAR}"
  #get_char
  #alert text
  get_single text + "  Press a key...", :color_pair => $errorcolor
end

#ri_full_indexed_list(list, config = {}, &block) ⇒ Object

pops up a list, taking a single key and returning if it is in range of 33 and 126 This is a specialized method and overrides textpads keys and behavior



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/ribhu.rb', line 446

def ri_full_indexed_list list, config={}, &block
  config[:row] ||= 0
  config[:col] ||= 0
  config[:width] ||= FFI::NCurses.COLS - config[:col]
  width = config[:width]
  if config[:title]
    width = config[:title].size + 2 if width < config[:title].size
  end
  height = config[:height]
  #height ||= [max_visible_items || 25, list.length+2].min 
  height ||= FFI::NCurses.LINES - config[:row]
  config[:height] = height
  config[:name] = "fil"
  row = config[:row]
  col = config[:col]
  #layout(1+height, width+4, row, col) 
  layout = { :height => 0+height, :width => 0+width, :top => row, :left => col } 
  window = VER::Window.new(layout)
  form = RubyCurses::Form.new window


  #config[:suppress_border] = true
  lb = RubyCurses::TextPad.new form, config, &block
  grows = lb.rows
  gviscols ||= 3
  pagesize = grows * gviscols
  files = list
  patt = nil
  view = nil
  sta = cursor = 0
  $stact = 0 # to prevent crash
  ignorecase = true

  while true
    break if $quitting
    if patt
      if ignorecase
        view = files.grep(/#{patt}/i)
      else
        view = files.grep(/#{patt}/)
      end
    else 
      view = files
    end
    fl=view.size
    sta = 0 if sta < 0
    cursor = fl -1 if cursor >= fl
    cursor = 0 if cursor < 0
    sta = calc_sta pagesize, cursor
    $log.debug "XXX:   sta is #{sta}, size is #{fl}"
    viewport = view[sta, pagesize]
    fin = sta + viewport.size
    #alist = columnate_with_indexing viewport, grows
    viewport = padup_list viewport
    viewport = index_this_list viewport
    alist = columnate viewport, grows
    lb.formatted_text(alist, :tmux)
    # we need to show the next 1 to n of n for long lists
    #@header.text_right "#{$sta+1} to #{fin} of #{fl}"
    #
    form.repaint
    Ncurses::Panel.update_panels

    begin
      
      ch = window.getchar()

      # if a char range or array has been sent, check if the key is in it and send back
      # else just stay here
      #if ( ( ch >= ?a.ord && ch <= ?z.ord ) || ( ch >= ?A.ord && ch <= ?Z.ord ) )
      if ( ( ch >= ?a.ord && ch <= ?z.ord ) || ( ch == ?Z.ord ) )
       
        chr = ch.chr
        
        chr = get_index chr, viewport.size
        # viewport has indexed data
        #viewport = view[sta, pagesize]
        return view[sta+chr] if chr
        next
      end


      case ch
      when 32, "SPACE", ?\M-n.getbyte(0)
        #next_page
        sta += pagesize
        cursor = sta if cursor < sta
        next
      when ?\M-p.getbyte(0)
        # prev page
        sta -= pagesize
        cursor = sta
        next
      when ?/.getbyte(0)
        # filter data on regex
        patt = get_line "Enter pattern: "
        next
      when ?\C-q.getbyte(0)
        return nil
      else
        # close if escape or double escape or C-c
        if ch == 27 || ch == 2727 || ch == 3
          # this just closes the app ! since my finger remains on Ctrl which is Escape
          return nil
        end
        # lets check our own bindings so textpad doesn't take over
        # Either that or check form's first
        # but this way we can just reuse from cetus
        #retval = c_process_key ch
        #next if retval

        retval = form.handle_key ch #if retval == :UNHANDLED
        next if retval != :UNHANDLED
        $log.debug "XXXX form returned #{retval} for #{ch}"
        #alert "got key before lb.handle #{ch.chr}"
        retval = lb.handle_key ch  if retval.nil? || retval == :UNHANDLED
        #          if retval == :UNHANDLED
        #alert "got key in unhdnalde lb.handle #{ch}, #{retval}"
        $log.debug "XXXX textpad returned #{retval} for #{ch}"
      end

      form.repaint
      #end # while getchar
    end
  end # while true
  return nil
ensure
  window.destroy 
end