Module: Canis::Utils

Included in:
CommandWindow, Form, ListCellRenderer, MessageBox, TreeCellRenderer, Widget
Defined in:
lib/canis/core/widgets/rwidget.rb,
lib/canis/core/include/appmethods.rb

Overview

— {{{

Since:

  • 1.2.0

Defined Under Namespace

Classes: MapNode

Instance Method Summary collapse

Instance Method Details

#_process_key(keycode, object, window) ⇒ Object

This the new one which does not use orderedhash, it uses an array for multiple assignments and falls back to a single assignment if multiple fails. e.g. process_key ch, self returns UNHANDLED if no block for it after form handles basic keys, it gives unhandled key to current field, if current field returns unhandled, then it checks this map. added 2009-01-06 19:13 since widgets need to handle keys properly added 2009-01-18 12:58 returns ret val of blk.call so that if block does not handle, the key can still be handled e.g. table last row, last col does not handle, so it will auto go to next field

2010-02-24 13:45 handles 2 key combinations, copied from Form, must be identical in logic
except maybe for window pointer.

Since:

  • 1.2.0



773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
# File 'lib/canis/core/widgets/rwidget.rb', line 773

def _process_key keycode, object, window
  return :UNHANDLED if @_key_map.nil?
  chr = nil
  ch = keycode
  if ch > 0 and ch < 256
    chr = ch.chr
  end
  blk = @_key_map[keycode]
  # i am scrappaing this since i am once again complicating too much
=begin
  # if blk then we found an exact match which supercedes any ranges, arrays and regexes
  unless blk
    @_key_map.each_pair do |k,p|
      $log.debug "KKK:  processing key #{ch}  #{chr} "
      if (k == ch || k == chr)
        $log.debug "KKK:  checking match == #{k}: #{ch}  #{chr} "
        # compare both int key and chr
        $log.debug "KKK:  found match 1 #{ch}  #{chr} "
        #p.call(self, ch)
        #return 0
        blk = p
        break
      elsif k.respond_to? :include?
        $log.debug "KKK:  checking match include #{k}: #{ch}  #{chr} "
        # this bombs if its a String and we check for include of a ch.
        if !k.is_a?( String ) && (k.include?( ch ) || k.include?(chr))
          $log.debug "KKK:  found match include #{ch}  #{chr} "
          #p.call(self, ch)
          #return 0
          blk = p
          break
        end
      elsif k.is_a? Regexp
        if k.match(chr)
          $log.debug "KKK:  found match regex #{ch}  #{chr} "
          #p.call(self, ch)
          #return 0
          blk = p
          break
        end
      end
    end
  end
=end
  # blk either has a proc or is nil
  # we still need to check for a complex map.  if none, then execute simple map.
  ret = check_composite_mapping(ch, window)
  $log.debug "  composite returned (#{ret}) for #{ch} "
  if !ret
    return execute_mapping(blk, ch, object) if blk
  end
  return execute_mapping(ret, ch, object) if ret
  return :UNHANDLED
end

#bind_composite_mapping(key, *args, action) ⇒ Object

Since:

  • 1.2.0



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'lib/canis/core/widgets/rwidget.rb', line 529

def bind_composite_mapping key, *args, action
  @_key_composite_map ||= Hash.new {|hash, key| hash[key] = MapNode.new }
  if key.is_a? String
    n = @_key_composite_map[key]
    n.action = action
  else
    mp = @_key_composite_map
    n = nil
    key.each do |e|
      n = mp[e]
      mp = n.map
    end
    n.action = action
  end
  val = @_key_composite_map.fetch(key[0], nil)
  $log.debug " composite contains #{key} : #{val} "
end

#bind_key(keycode, *args, &blk) ⇒ Object

A new attempt at a flat hash 2014-05-06 - 00:16 bind an action to a key, required if you create a button which has a hotkey or a field to be focussed on a key, or any other user defined action based on key e.g. bind_key ?C-x, object, block added 2009-01-06 19:13 since widgets need to handle keys properly

2010-02-24 12:43 trying to take in multiple key bindings, TODO unbind
TODO add symbol so easy to map from config file or mapping file

Ideally i want to also allow a regex and array/range to be used as a key 
However, then how do i do multiple assignments which use an array.

Currently the only difference is that there is no hash inside the value,
key can be an int, or array of ints (for multiple keycode like qq or gg).

Since:

  • 1.2.0



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
# File 'lib/canis/core/widgets/rwidget.rb', line 458

def bind_key keycode, *args, &blk
  #$log.debug " #{@name} bind_key received #{keycode} "
  @_key_map ||= {}
  #
  # added on 2011-12-4 so we can pass a description for a key and print it
  # The first argument may be a string, it will not be removed
  # so existing programs will remain as is.
  @key_label ||= {}
  if args[0].is_a?(String) || args[0].is_a?(Symbol)
    @key_label[keycode] = args[0] 
  else
    @key_label[keycode] = :unknown
  end

  if !block_given?
    blk = args.pop
    raise "If block not passed, last arg should be a method symbol" if !blk.is_a? Symbol
    #$log.debug " #{@name} bind_key received a symbol #{blk} "
  end
  case keycode
  when String
    # single assignment
    keycode = keycode.getbyte(0) 
  when Array
    # double assignment
    # this means that all these keys have to be pressed in succession for this block, like "gg" or "C-x C-c"
    raise "A one key array will not work. Pass without array" if keycode.size == 1
    ee = []
    keycode.each do |e| 
      e = e.getbyte(0) if e.is_a? String
      ee << e
    end
    bind_composite_mapping ee, args, blk
    return self
    #@_key_map[a0] ||= OrderedHash.new
    #@_key_map[a0][a1] = blk
    #$log.debug " XX assigning #{keycode} to  _key_map " if $log.debug? 
  else
    $log.debug " assigning #{keycode} to  _key_map for #{self.class}, #{@name}" if $log.debug? 
  end
  @_key_map[keycode] = blk
  @_key_args ||= {}
  @_key_args[keycode] = args
  self
end

#bind_keys(keycodes, *args, &blk) ⇒ Object

Since:

  • 1.2.0



755
756
757
# File 'lib/canis/core/widgets/rwidget.rb', line 755

def bind_keys keycodes, *args, &blk
  keycodes.each { |k| bind_key k, *args, &blk }
end

#check_composite_mapping(key, window) ⇒ Object

Since:

  • 1.2.0



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
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
# File 'lib/canis/core/widgets/rwidget.rb', line 546

def check_composite_mapping key, window
  #$log.debug  "inside check with #{key} "
  return nil if !@_key_composite_map
  return nil if !@_key_composite_map.key? key
  $log.debug "  composite has #{key} "

  # we have a match and need to loop
  mp = @_key_composite_map
  n = nil
  actions = []
  unconsumed = []
  e = key
  while true

    # we traverse each key and get action of final.
    # However, if at any level there is a failure, we need to go back to previous action
    # and push the other keys back so they can be again processed.
    if e.nil? or e == -1
      #puts "e is nil TODO "
      # TODO
      #$log.debug "  -1  push #{unconsumed} returning: #{actions.last}" 
      $log.debug "  -1  returning: #{actions.last}" 
      # is there a reason we are pushing here ?
      #unconsumed.each {|e| window.ungetch(e)}
      return actions.last 
    else
      $log.debug  " in loop with #{e} "
      unconsumed << e
      n = mp.fetch(e, nil)
      $log.debug  " got node #{n} with #{e} "
      # instead of just nil, we need to go back up, but since not recursive ...
      #return nil unless n
      unless n
        # testing shift otherwise it seems current key evaluated twice 2014-08-17
        unconsumed.shift
        $log.debug  "push unconsumed:#{unconsumed} " unless n
        unconsumed.each {|e| window.ungetch(e)} unless n
        return actions.last unless n
      end
      mp = n.map
      # there are no more keys, only an action
      if mp.nil? or mp.empty?
        $log.debug "  mp is nil or empty returning action: #{n.action}"
        #puts "mp is nil or empty"
        return n.action
      end
      # we could have consumed keys at this point
      actions << n.action if n.action
      unconsumed.clear if n.action
      #e = window.getchar
      Ncurses::wtimeout(window.get_window, 500) # will wait a second on wgetch so we can get gg and qq
      e = window.getch
      Ncurses::nowtimeout(window.get_window, true)
      # e can return -1 if timedout
      $log.debug "  getch got #{e}"
    end
  end
end

#create_logger(path) ⇒ Object

create a logger giving a path.

Since:

  • 1.2.0



910
911
912
913
914
915
916
917
918
919
920
# File 'lib/canis/core/widgets/rwidget.rb', line 910

def create_logger path
  #path = File.join(ENV["LOGDIR"] || "./" ,"canis14.log")
  file   = File.open(path, File::WRONLY|File::TRUNC|File::CREAT) 
  logg = Logger.new(path)
  raise "Could not create logger  " unless logg
  # if not set, will default to 0 which is debug. Other values are 1 - info, 2 - warn
  logg.level = ENV["CANIS_LOG_LEVEL"].to_i
  colors = Ncurses.COLORS
  logg.info "START #{colors} colors  -- #{$0} win: #{@window} : log level: #{logg.level}. To change log level, increase CANIS_LOG_LEVEL in your environment to 1 or 2 or 3."
  return logg
end

#define_key(_symbol, _keycode, *args, &blk) ⇒ Object

Define a key for a prefix command.

Example:

@form.define_key(:csmap, "s", 'specification') { specification }
@form.define_key(:csmap, "r", 'refresh', :refresh )

Parameters:

  • _symbol

    prefix command symbol (already created using define_prefix_command

  • keycode

    key within the prefix command for given block or action

  • args

    arguments to be passed to block. The first is a description. The second may be a symbol for a method to be executed (if block not given).

  • block

    action to be executed on pressing keycode

Raises:

  • (ArgumentError)

See Also:

  • +define_prefix_command+

Since:

  • 1.2.0



687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
# File 'lib/canis/core/widgets/rwidget.rb', line 687

def define_key _symbol, _keycode, *args, &blk
  #_symbol = @symbol
  h = $rb_prefix_map[_symbol]
  raise ArgumentError, "No such keymap #{_symbol} defined. Use define_prefix_command." unless h
  _keycode = _keycode[0].getbyte(0) if _keycode[0].class == String
  arg = args.shift
  if arg.is_a? String
    desc = arg
    arg = args.shift
  elsif arg.is_a? Symbol
    # its a symbol
    desc = arg.to_s
  elsif arg.nil?
    desc = "unknown"
  else
    raise ArgumentError, "Don't know how to handle #{arg.class} in PrefixManager"
  end
  # 2013-03-20 - 18:45 187compat gave error in 187 cannot convert string to int
  #@descriptions ||= []
  @descriptions ||= {}
  @descriptions[_keycode] = desc

  if !block_given?
    blk = arg
  end
  h[_keycode] = blk
end

#define_prefix_command(_name, config = {}) ⇒ Object

define a key with sub-keys to which commands are attached. e.g. to attach commands to C-x a , C-x b, C-x x etc.

Example

We create a map named :csmap and attach various commands to it on different keys. At this point, there is no main key that triggers it. Any key can be made the prefix command later. In this case, C-s was bound to the map. This is more organized that creating separate maps for C-s r, C-s s etc which then cannot be changed or customized by user.

@form.define_prefix_command :csmap, :scope => self
@form.define_key(:csmap, "r", 'refresh', :refresh )
@form.define_key(:csmap, "s", 'specification') { specification }
@form.bind_key ?\C-s, :csmap

Since:

  • 1.2.0



632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/canis/core/widgets/rwidget.rb', line 632

def define_prefix_command _name, config={} #_mapvar=nil, _prompt=nil
  $rb_prefix_map ||= {}
  _name = _name.to_sym unless _name.is_a? Symbol
  $rb_prefix_map[_name] ||= {}
  scope = config[:scope] || self
  $rb_prefix_map[_name][:scope] = scope


  # create a variable by name _name
  # create a method by same name to use
  # Don;t let this happen more than once
  instance_eval %{
def #{_name.to_s} *args
  #$log.debug "XXX:  came inside #{_name} "
   h = $rb_prefix_map["#{_name}".to_sym]
   raise "No prefix_map named #{_name}, #{$rb_prefix_map.keys} " unless h
   ch = @window.getchar
   if ch
    if ch == KEY_F1
      text =  ["Options are: "]
      h.keys.each { |e| c = keycode_tos(e); text << c + " " + @descriptions[e]  }
      textdialog text, :title => "#{_name} key bindings"
      return
    end
      res =  h[ch]
      if res.is_a? Proc
        res.call
      elsif res.is_a? Symbol
         scope = h[:scope]
         scope.send(res)
      elsif res.nil?
        Ncurses.beep
         return :UNHANDLED
      end
   else
         :UNHANDLED
   end
end
  }
  return _name
end

#execute_mapping(blk, keycode, object) ⇒ Object

Since:

  • 1.2.0



828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
# File 'lib/canis/core/widgets/rwidget.rb', line 828

def execute_mapping blk, keycode, object

  if blk.is_a? Symbol
    if respond_to? blk
      $log.debug "  RESPONDING TO BLCK #{keycode}"
      return send(blk, *@_key_args[keycode])
    else
      ## 2013-03-05 - 19:50 why the hell is there an alert here, nowhere else
      alert "This ( #{self.class} ) does not respond to #{blk.to_s} [PROCESS-KEY]"
      # added 2013-03-05 - 19:50 so called can know
      return :UNHANDLED 
    end
  else
    $log.debug "rwidget BLOCK called _process_key #{keycode} " if $log.debug? 
    return blk.call object,  *@_key_args[keycode]
  end
end

#get_attrib(str) ⇒ Object

convert a string to integer attribute FIXME: what if user wishes to OR two attribs, this will give error

Parameters:

  • e.g. (String)

    reverse bold normal underline if a Fixnum is passed, it is returned as is assuming to be an attrib

Since:

  • 1.2.0



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/canis/core/widgets/rwidget.rb', line 335

def get_attrib str
  return FFI::NCurses::A_NORMAL unless str
  # next line allows us to do a one time conversion and keep the value
  #  in the same variable
  if str.is_a? Fixnum
    if [
      FFI::NCurses::A_BOLD,
      FFI::NCurses::A_REVERSE,    
      FFI::NCurses::A_NORMAL,
      FFI::NCurses::A_UNDERLINE,
      FFI::NCurses::A_STANDOUT,    
      FFI::NCurses::A_DIM,    
      FFI::NCurses::A_BOLD | FFI::NCurses::A_REVERSE,    
      FFI::NCurses::A_BOLD | FFI::NCurses::A_UNDERLINE,    
      FFI::NCurses::A_REVERSE | FFI::NCurses::A_UNDERLINE,    
      FFI::NCurses::A_BLINK
    ].include? str
    return str
    else
      raise ArgumentError, "get_attrib got a wrong value: #{str} "
    end
  end


  att = nil
  str = str.downcase.to_sym if str.is_a? String
  case str #.to_s.downcase
  when :bold
    att = FFI::NCurses::A_BOLD
  when :reverse
    att = FFI::NCurses::A_REVERSE    
  when :normal
    att = FFI::NCurses::A_NORMAL
  when :underline
    att = FFI::NCurses::A_UNDERLINE
  when :standout
    att = FFI::NCurses::A_STANDOUT
  when :bold_reverse
    att = FFI::NCurses::A_BOLD | FFI::NCurses::A_REVERSE
  when :bold_underline
    att = FFI::NCurses::A_BOLD | FFI::NCurses::A_UNDERLINE
  when :dim
    att = FFI::NCurses::A_DIM    
  when :blink
    att = FFI::NCurses::A_BLINK    # unlikely to work
  else
    att = FFI::NCurses::A_NORMAL
  end
  return att
end

#get_color(default = $datacolor, color = color(), bgcolor = bgcolor()) ⇒ Object

if passed a string in second or third param, will create a color and return, else it will return default color Use this in order to create a color pair with the colors provided, however, if user has not provided, use supplied default.

Examples:

get_color $promptcolor, :white, :cyan

Parameters:

  • color_pair (Fixnum)

    created by ncurses

  • color (Symbol) (defaults to: color())

    name such as white black cyan magenta red green yellow

  • bgcolor (Symbol) (defaults to: bgcolor())

    name such as white black cyan magenta red green yellow

Since:

  • 1.2.0



322
323
324
325
326
327
328
# File 'lib/canis/core/widgets/rwidget.rb', line 322

def get_color default=$datacolor, color=color(), bgcolor=bgcolor()
  return default if color.nil? || bgcolor.nil?
  #raise ArgumentError, "Color not valid: #{color}: #{ColorMap.colors} " if !ColorMap.is_color? color
  #raise ArgumentError, "Bgolor not valid: #{bgcolor} : #{ColorMap.colors} " if !ColorMap.is_color? bgcolor
  acolor = ColorMap.get_color(color, bgcolor)
  return acolor
end

#key(ch) ⇒ Object

convenience func to get int value of a key added 2014-05-05 instead of ?C-a.getbyte(0) use key(?C-a) or key(?a) or key(?M-x)

Since:

  • 1.2.0



176
177
178
# File 'lib/canis/core/widgets/rwidget.rb', line 176

def key ch
  ch.getbyte(0)
end

#key_tos(ch) ⇒ String Also known as: keycode_tos

returns a string representation of a given int keycode NOTE do we really need to cache everything ? Only the computed ones should be cached ?

Parameters:

  • keycode (Fixnum)

    read by window In some case, such as Meta/Alt codes, the window reads two ints, but still we are using the param as the value returned by ?M-a.getbyte(0) and such, which is typically 128 + key

Returns:

  • (String)

    a string representation which is what is to be used when binding a key to an action or Proc. This is close to what vimrc recognizes such as <CR> <C-a> a-zA-z0-9 <SPACE> Hopefully it should be identical to what vim recognizes in the map command. If the key is not known to this program it returns “UNKNOWN:key” which means this program needs to take care of that combination. FIXME some numbers are missing in between.

Since:

  • 1.2.0



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/canis/core/widgets/rwidget.rb', line 189

def key_tos ch # -- {{{
  x = $key_cache[ch]
  return x if x
  chr = case ch
        when 10,13 , KEY_ENTER
          "<CR>"
        when 9 
          "<TAB>"
        when 0 
          "<C-@>"
        when 27
          "<ESC>"
        when 31
          "<C-/>"
        when 1..30
          x= ch + 96
          "<C-#{x.chr}>"
        when 32 
          "<SPACE>"
        when 41
          "<M-CR>"
        when 33..126
          ch.chr
        when 127,263 
          "<BACKSPACE>"
        when 128..154
          x = ch - 128
          #"<M-C-#{x.chr}>"
          xx = key_tos(x).gsub(/[<>]/,"")
          "<M-#{xx}>"
        when 160..255
          x = ch - 128
          xx = key_tos(x).gsub(/[<>]/,"")
          "<M-#{xx}>"
        when 255
          "<M-BACKSPACE>"
        when 2727
          "<ESC-ESC>"
        else

          chs =  FFI::NCurses::keyname(ch) 
          # remove those ugly brackets around function keys
          if chs && chs[-1]==')'
            chs = chs.gsub(/[()]/,'')
          end
          if chs
            chs = chs.gsub("KEY_","")
            "<#{chs}>"
          else
            "UNKNOWN:#{ch}"
          end
        end
  $key_cache[ch] = chr
  return chr
end

#ORIG_process_key(keycode, object, window) ⇒ Object

e.g. process_key ch, self returns UNHANDLED if no block for it after form handles basic keys, it gives unhandled key to current field, if current field returns unhandled, then it checks this map. added 2009-01-06 19:13 since widgets need to handle keys properly added 2009-01-18 12:58 returns ret val of blk.call so that if block does not handle, the key can still be handled e.g. table last row, last col does not handle, so it will auto go to next field

2010-02-24 13:45 handles 2 key combinations, copied from Form, must be identical in logic
except maybe for window pointer. TODO not tested

Since:

  • 1.2.0



856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
# File 'lib/canis/core/widgets/rwidget.rb', line 856

def ORIG_process_key keycode, object, window
  return :UNHANDLED if @_key_map.nil?
  blk = @_key_map[keycode]
  $log.debug "XXX:  _process key keycode #{keycode} #{blk.class}, #{self.class} "
  return :UNHANDLED if blk.nil?
  if blk.is_a? OrderedHash 
    #Ncurses::nodelay(window.get_window, bf = false)
    # if you set nodelay in ncurses.rb then this will not
    # wait for second key press, so you then must either make it blocking
    # here, or set a wtimeout here.
    #
    # This is since i have removed timeout globally since resize was happeing
    # after a keypress. maybe we can revert to timeout and not worry about resize so much
    Ncurses::wtimeout(window.get_window, 500) # will wait a second on wgetch so we can get gg and qq
    ch = window.getch
    # we should not reset here, resetting should happen in getch itself so it is consistent
    #Ncurses::nowtimeout(window.get_window, true)

    $log.debug " process_key: got #{keycode} , #{ch} "
    # next line ignores function keys etc. C-x F1, thus commented 255 2012-01-11 
    if ch < 0 #|| ch > 255
      return nil
    end
    #yn = ch.chr
    blk1 = blk[ch]
    # FIXME we are only returning the second key, what if form
    # has mapped first and second combo. We should unget keycode and ch. 2011-12-23 
    # check this out first.
    window.ungetch(ch) if blk1.nil? # trying  2011-09-27 
    return :UNHANDLED if blk1.nil? # changed nil to unhandled 2011-09-27 
    $log.debug " process_key: found block for #{keycode} , #{ch} "
    blk = blk1
  end
  if blk.is_a? Symbol
    if respond_to? blk
      return send(blk, *@_key_args[keycode])
    else
      ## 2013-03-05 - 19:50 why the hell is there an alert here, nowhere else
      alert "This ( #{self.class} ) does not respond to #{blk.to_s} [PROCESS-KEY]"
      # added 2013-03-05 - 19:50 so called can know
      return :UNHANDLED 
    end
  else
    $log.debug "rwidget BLOCK called _process_key " if $log.debug? 
    return blk.call object,  *@_key_args[keycode]
  end
  #0
end

#ORIGbind_key(keycode, *args, &blk) ⇒ Object

this is the bindkey that has been working all along. now i am trying a new approach that does not use a hash inside but keeps on key. so it can be manip easily be user

Since:

  • 1.2.0



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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/canis/core/widgets/rwidget.rb', line 397

def ORIGbind_key keycode, *args, &blk # -- {{{
  #$log.debug " #{@name} bind_key received #{keycode} "
  @_key_map ||= {}
  #
  # added on 2011-12-4 so we can pass a description for a key and print it
  # The first argument may be a string, it will not be removed
  # so existing programs will remain as is.
  @key_label ||= {}
  if args[0].is_a?(String) || args[0].is_a?(Symbol)
    @key_label[keycode] = args[0] 
  else
    @key_label[keycode] = :unknown
  end

  if !block_given?
    blk = args.pop
    raise "If block not passed, last arg should be a method symbol" if !blk.is_a? Symbol
    #$log.debug " #{@name} bind_key received a symbol #{blk} "
  end
  case keycode
  when String
    # single assignment
    keycode = keycode.getbyte(0) #if keycode.class==String ##    1.9 2009-10-05 19:40 
    #$log.debug " #{name} Widg String called bind_key BIND #{keycode}, #{keycode_tos(keycode)}  "
    #$log.debug " assigning #{keycode}  " if $log.debug? 
    @_key_map[keycode] = blk
  when Array
    # double assignment
    # for starters lets try with 2 keys only
    raise "A one key array will not work. Pass without array" if keycode.size == 1
    a0 = keycode[0]
    a0 = keycode[0].getbyte(0) if keycode[0].class == String
    a1 = keycode[1]
    a1 = keycode[1].getbyte(0) if keycode[1].class == String
    @_key_map[a0] ||= OrderedHash.new
    #$log.debug " assigning #{keycode} , A0 #{a0} , A1 #{a1} " if $log.debug? 
    @_key_map[a0][a1] = blk
    #$log.debug " XX assigning #{keycode} to  _key_map " if $log.debug? 
  else
    #$log.debug " assigning #{keycode} to  _key_map " if $log.debug? 
    @_key_map[keycode] = blk
  end
  @_key_args ||= {}
  @_key_args[keycode] = args

end

#ORIGkeycode_tos(keycode) ⇒ Object

Deprecated.

needs to move to a keystroke class please use these only for printing or debugging, not comparing I could soon return symbols instead 2010-09-07 14:14 Please move to window.key_tos

Since:

  • 1.2.0



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/canis/core/widgets/rwidget.rb', line 251

def ORIGkeycode_tos keycode # {{{
  $log.warn "XXX:  keycode_tos please move to window.key_tos"
  case keycode
  when 33..126
    return keycode.chr
  when ?\C-a.getbyte(0) .. ?\C-z.getbyte(0)
    return "C-" + (keycode + ?a.getbyte(0) -1).chr 
  when ?\M-A.getbyte(0)..?\M-z.getbyte(0)
    return "M-"+ (keycode - 128).chr
  when ?\M-\C-A.getbyte(0)..?\M-\C-Z.getbyte(0)
    return "M-C-"+ (keycode - 32).chr
  when ?\M-0.getbyte(0)..?\M-9.getbyte(0)
    return "M-"+ (keycode-?\M-0.getbyte(0)).to_s
  when 32
    return "space" # changed to lowercase so consistent
  when 27
    return "esc" # changed to lowercase so consistent
  when ?\C-].getbyte(0)
    return "C-]"
  when 258
    return "down"
  when 259
    return "up"
  when 260
    return "left"
  when 261
    return "right"
  when FFI::NCurses::KEY_F1..FFI::NCurses::KEY_F12
    return "F"+ (keycode-264).to_s
  when 330
    return "delete"
  when 127
    return "bs"
  when 353
    return "btab"
  when 481
    return "M-S-tab"
  when 393..402
    return "M-F"+ (keycode-392).to_s
  when 0
    return "C-space" 
  when 160
    return "M-space" # at least on OSX Leopard now (don't remember this working on PPC)
  when C_LEFT
    return "C-left"
  when C_RIGHT
    return "C-right"
  when S_F9
    return "S_F9"
  else
    others=[?\M--,?\M-+,?\M-=,?\M-',?\M-",?\M-;,?\M-:,?\M-\,, ?\M-.,?\M-<,?\M->,?\M-?,?\M-/,?\M-!]
    others.collect! {|x| x.getbyte(0)  }  ## added 2009-10-04 14:25 for 1.9
    s_others=%w[M-- M-+ M-= M-' M-"   M-;   M-:   M-, M-. M-< M-> M-? M-/ M-!]
    if others.include? keycode
      index = others.index keycode
      return s_others[index]
    end
    # all else failed
    return keycode.to_s
  end
end

Display key bindings for current widget and form in dialog

Since:

  • 1.2.0



715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
# File 'lib/canis/core/widgets/rwidget.rb', line 715

def print_key_bindings *args
  f  = get_current_field
  #labels = [@key_label, f.key_label]
  #labels = [@key_label]
  #labels << f.key_label if f.key_label
  labels = []
  labels << (f.key_label || {}) #if f.key_label
  labels << @key_label
  arr = []
  if get_current_field.help_text 
    arr << get_current_field.help_text 
  end
  labels.each_with_index { |h, i|  
    case i
    when 0
      arr << "  ===  Current widget bindings ==="
    when 1
      arr << "  === Form bindings ==="
    end

    h.each_pair { |name, val| 
      if name.is_a? Fixnum
        name = keycode_tos name
      elsif name.is_a? String
        name = keycode_tos(name.getbyte(0))
      elsif name.is_a? Array
        s = []
        name.each { |e|
          s << keycode_tos(e.getbyte(0))
        }
        name = s
      else
        #$log.debug "XXX: KEY #{name} #{name.class} "
      end
      arr << " %-30s %s" % [name ,val]
      $log.debug "KEY: #{name} : #{val} "
    }
  }
  textdialog arr, :title => "Key Bindings"
end

#repeatmObject

repeats the given action based on how value of universal numerica argument + set using the C-u key. Or in vim-mode using numeric keys

Since:

  • 1.2.0



388
389
390
391
392
393
394
# File 'lib/canis/core/widgets/rwidget.rb', line 388

def repeatm
  $inside_multiplier_action = true
  _multiplier = ( ($multiplier.nil? || $multiplier == 0) ? 1 : $multiplier )
  _multiplier.times { yield }
  $multiplier = 0
  $inside_multiplier_action = false
end

#run_command(cmd) ⇒ Object

executes given command and displays in viewer

Parameters:

  • unix (String)

    command, e.g., git -st

Since:

  • 1.2.0



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/canis/core/include/appmethods.rb', line 65

def run_command cmd
  # http://whynotwiki.com/Ruby_/_Process_management#What_happens_to_standard_error_.28stderr.29.3F
  require 'canis/core/util/viewer'
  begin
    res = `#{cmd} 2>&1`
  rescue => ex
    res = ex.to_s
    res << ex.backtrace.join("\n") 
  end
  res.gsub!("\t","   ")
  # Earlier close key was ENTER but we need that to execute or fire
  Canis::Viewer.view(res.split("\n"), :close_key => 'q', :title => "<q> to close, M-l M-h to scroll")
end

#shell_out(command = nil) ⇒ Object

takes a unix command (system) and executes the same. No output

Returns:

  • return value of system command

Since:

  • 1.2.0



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/canis/core/include/appmethods.rb', line 82

def shell_out command=nil
  $shell_history ||= []
  command ||= get_string("Enter system command:", :maxlen => 50) do |f|
    require 'canis/core/include/rhistory'
    f.extend(FieldHistory)
    f.history($shell_history)
  end
  ##w = @window || @form.window
  #w.hide
  Ncurses.endwin
  ret = system command
  Ncurses.refresh
  #Ncurses.curs_set 0  # why ?
  #w.show
  return ret
end

#shell_outputObject

prompts user for unix command and displays output in viewer

Since:

  • 1.2.0



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/canis/core/include/appmethods.rb', line 49

def shell_output
  $shell_history ||= []
  cmd = get_string("Enter shell command:", :maxlen => 50) do |f|
    require 'canis/core/include/rhistory'
    f.extend(FieldHistory)
    f.history($shell_history)
  end
  if cmd && !cmd.empty?
    run_command cmd
    $shell_history.push(cmd) unless $shell_history.include? cmd
  end
end

#suspendObject

suspends current program and puts user on unix prompt

Since:

  • 1.2.0



36
37
38
39
40
41
42
43
44
# File 'lib/canis/core/include/appmethods.rb', line 36

def suspend
  _suspend(false) do
    system("tput cup 26 0")
    system("tput ed")
    system("echo Enter C-d to return to application")
    system (ENV['PS1']='\s-\v\$ ') if ENV['SHELL']== '/bin/bash'
    system(ENV['SHELL']);
  end
end

#view(what, config = {}, &block) ⇒ Object

view a file or array of strings

Since:

  • 1.2.0



905
906
907
908
# File 'lib/canis/core/widgets/rwidget.rb', line 905

def view what, config={}, &block # :yields: textview for further configuration
  require 'canis/core/util/viewer'
  Canis::Viewer.view what, config, &block
end

#xxxbind_composite_mapping(keycode, *args, &blk) ⇒ Object

Since:

  • 1.2.0



605
606
607
608
609
610
611
612
613
614
# File 'lib/canis/core/widgets/rwidget.rb', line 605

def xxxbind_composite_mapping keycode, *args, &blk
  @_key_composite_map ||= {}
  str = ""
  keycode.each do |e| 
    s = key_tos(e)
    str << s
  end
  $log.debug "  composite map #{keycode} bound as #{str} "
  @_key_composite_map[str] = blk
end