class SugarCane::Menu

Produces a ncurses menu that the user can navigate with:

J/  K: Move up/down
    Q: Quit
Enter: Open violation in text editor

Constructor Parameters:

checks: like ones produced from style_check.rb or doc_check.rb
opts: command-line parsed options applied to each check
height: the maximum number of items that can be in the menu

Constants

KEY_C

Don't trust ncursew keys as they don't always work

KEY_DOWN
KEY_ENTER
KEY_J
KEY_K
KEY_O
KEY_Q
KEY_S
KEY_SPACE
KEY_UP
KEY_W
KEY_X
TITLE

Public Class Methods

new(checks, options, height = 30) click to toggle source
# File lib/sugarcane/menu.rb, line 38
def initialize(checks, options, height = 30)
  @checks = checks
  @options = options
  @height = height
  check_violations
end

Public Instance Methods

check_violations() click to toggle source
# File lib/sugarcane/menu.rb, line 211
def check_violations
  violations = @checks.
    map {|check| check.new(@options).violations }.
    flatten
  @data = violations
  @height = [@data.size,@height].min
  @size = @data.size
  @min_position = 0
  @max_position = @height - 1
  @data_position ||= 0
  @menu_position ||= 0
  if @data_position > @size - 1
    @data_position = @size - 1
  end
  return violations
end
clean_up() click to toggle source
# File lib/sugarcane/menu.rb, line 168
def clean_up
  Ncurses.stdscr.clear
  Ncurses.stdscr.refresh
  Ncurses.echo
  Ncurses.nocbreak
  Ncurses.nl
  Ncurses.endwin
end
draw_fix_window(window) click to toggle source
# File lib/sugarcane/menu.rb, line 138
def draw_fix_window(window)
  window.clear
  window.border(*([0]*8))
  window.move(1, 1)
  line = "Violations left: #{@data.size}"
  window.addstr(line)
  window.refresh
end
draw_menu(menu, active_index=nil) click to toggle source
# File lib/sugarcane/menu.rb, line 89
def draw_menu(menu, active_index=nil)
  Ncurses.stdscr.border(*([0]*8))
  Ncurses.stdscr.refresh
  menu.clear
  menu.border(*([0]*8))
  @height.times do |i|
    menu.move(i + 1, 1)
    position = i + @data_position - @menu_position
    file = @data[position][:file]
    if @data[position][:line]
      line = " #{@data[position][:line]}: "
    else
      line = " "
    end
    desc = @data[position][:menu_description] || ""
    if desc.length > Ncurses.COLS - 10
      desc << "..."
    end
    if i == active_index
      style = Ncurses::A_STANDOUT
      menu.attrset(style)
      menu.addstr(file)
      menu.addstr(line)
      menu.addstr(desc)
      menu.attrset(Ncurses::A_NORMAL)
    else
      menu.attrset(Ncurses.COLOR_PAIR(2))
      menu.addstr(file)
      menu.attrset(Ncurses.COLOR_PAIR(3))
      menu.addstr(line)
      menu.attrset(Ncurses.COLOR_PAIR(4))
      menu.addstr(desc)
      # menu.attrset(Ncurses.COLOR_PAIR(1))
      menu.attrset(Ncurses::A_NORMAL)
    end
  end
  menu.refresh
  Ncurses.keypad(menu, true)
end
draw_title_window(window) click to toggle source
# File lib/sugarcane/menu.rb, line 129
def draw_title_window(window)
  window.clear
  # window.border(*([0]*8))
  window.attrset(Ncurses.COLOR_PAIR(5))
  window.addstr(TITLE)
  window.attrset(Ncurses.COLOR_PAIR(1))
  window.refresh
end
edit_file(file, line) click to toggle source
# File lib/sugarcane/menu.rb, line 177
def edit_file(file, line)
  if @options[:editor]
    system("#{@options[:editor]} +#{line} #{file}")
  # If someone purchased sublime, they probably want to use it
  elsif program_exist? "subl"
    system("subl #{file}:#{line}")
  elsif ENV['VISUAL']
    system("#{ENV['VISUAL']} +#{line} #{file}")
  elsif program_exist? "vim"
    system("vim +#{line} #{file}")
  elsif program_exist? "gedit"
    system("gedit +#{line} #{file}")
  elsif program_exist? "nano"
    system("nano +#{line} #{file}")
  elsif program_exist? "geany"
    system("geany +#{line} #{file}")
  else
    # :(
    system("notepad.exe #{file}")
  end
end
init_ncurses() click to toggle source
# File lib/sugarcane/menu.rb, line 147
def init_ncurses
  Ncurses.cbreak
  Ncurses.start_color
  Ncurses.noecho
  Ncurses.nonl
  Ncurses.curs_set(0)

  if Ncurses.has_colors?
    @background_color = Ncurses::COLOR_BLACK
    Ncurses.init_pair(1, Ncurses::COLOR_WHITE, @background_color)
    Ncurses.init_pair(2, Ncurses::COLOR_BLUE, @background_color)
    Ncurses.init_pair(3, Ncurses::COLOR_CYAN, @background_color)
    Ncurses.init_pair(4, Ncurses::COLOR_RED, @background_color)
    Ncurses.init_pair(5, Ncurses::COLOR_GREEN, @background_color)
  end

  @title_window = Ncurses::WINDOW.new(5, Ncurses.COLS - 2,2,1)
  @menu = Ncurses::WINDOW.new(@height + 2, Ncurses.COLS - 2,7,1)
  @fix_window = Ncurses::WINDOW.new(3, Ncurses.COLS - 2,@height+9,1)
end
program_exist?(command) click to toggle source

Allegedly cross-platform way to determine if an executable is in PATH

# File lib/sugarcane/menu.rb, line 200
def program_exist?(command)
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
  ENV['PATH'].split(::File::PATH_SEPARATOR).each do |path|
    exts.each { |ext|
      exe = ::File.join(path, "#{command}#{ext}")
      return exe if ::File.executable? exe
    }
  end
  return nil
end
run() click to toggle source
# File lib/sugarcane/menu.rb, line 45
def run
  if @data.nil? or @data.empty?
    return nil
  end
  begin
    # can't go in separate function because redeclares constants
    Ncurses.initscr
    init_ncurses
    draw_menu(@menu, @menu_position)
    draw_fix_window(@fix_window)
    draw_title_window(@title_window)
    while ch = @menu.wgetch
      case ch
      when KEY_K, KEY_W, KEY_UP
        # draw menu, 'move up'
        @menu_position -= 1 unless @menu_position == @min_position
        @data_position -= 1 unless @data_position == 0
      when KEY_J, KEY_S, KEY_DOWN
        # draw_info 'move down'
        @menu_position += 1 unless @menu_position == @max_position
        @data_position += 1 unless @data_position == @size - 1
      when KEY_O, KEY_ENTER, KEY_SPACE
        clean_up
        selected = @data[@data_position]
        edit_file(selected[:file], selected[:line])
        init_ncurses
        check_violations
      when KEY_Q, KEY_X
        clean_up
        break
      end
      # For cycling through the options but is buggy
      # @data_position = @size - 1 if @data_position < 0
      # @data_position = 0 if @data_position > @size - 1
      draw_menu(@menu, @menu_position)
      draw_fix_window(@fix_window)
      draw_title_window(@title_window)
    end
    return @data[@data_position]
  ensure
    clean_up
  end
end