class Eclair::Grid

Attributes

mode[R]

Public Class Methods

new(keyword = "") click to toggle source
# File lib/eclair/grid.rb, line 9
def initialize keyword = ""
  case config.provider
  when :ec2
    require "eclair/providers/ec2"
    @provider = EC2Provider
  when :k8s
    require "eclair/providers/k8s"
    @provider = K8sProvider
  when :gce
    require "eclair/providers/gce"
    @provider = GCEProvider
  end
  @item_class = @provider.item_class

  @scroll = config.columns.times.map{0}
  @header_rows = 4
  @cursor = [0,0]
  @cell_width = Curses.stdscr.maxx/config.columns
  @maxy = Curses.stdscr.maxy - @header_rows
  @mode = :assign
  @search_buffer = ""

  @provider.prepare keyword
  assign
  at(*@cursor).select(true)
  draw_all
  transit_mode(:nav)
end

Public Instance Methods

action() click to toggle source
# File lib/eclair/grid.rb, line 83
def action
  targets = @provider.items.select{|i| i.selected && i.connectable?}

  return if targets.empty?
  Curses.close_screen

  if targets.length == 1
    cmd = targets.first.command
  else
    cmds = []
    target_cmd = ""

    targets.each_with_index do |target, i|
      if i == 0
        if ENV['TMUX'] # Eclair called inside of tmux
          # Create new session and save window id
          window_name = `tmux new-window -P -- '#{target.command}'`.strip
          target_cmd = "-t #{window_name}"
        else # Eclair called from outside of tmux
          # Create new session and save session
          session_name = "eclair#{Time.now.to_i}"
          target_cmd = "-t #{session_name}"
          `tmux new-session -d -s #{session_name} -- '#{target.command}'`
        end
      else # Split layout and
        cmds << "split-window #{target_cmd} -- '#{target.command}'"
        cmds << "select-layout #{target_cmd} tiled"
      end
    end
    cmds << "set-window-option #{target_cmd} synchronize-panes on"
    cmds << "attach #{target_cmd}" unless ENV['TMUX']
    cmd = "tmux #{cmds.join(" \\; ")}"
  end
  system(cmd)
  exit()
  resize
end
move(key) click to toggle source
# File lib/eclair/grid.rb, line 38
def move key
  return unless at(*@cursor)
  x,y = @cursor
  mx,my = {
    Curses::KEY_UP => [0,-1],
    ?k => [0,-1],
    Curses::KEY_DOWN => [0,1],
    ?j => [0,1],
    Curses::KEY_LEFT => [-1,0],
    ?h => [-1,0],
    Curses::KEY_RIGHT => [1,0],
    ?l => [1,0],
  }[key]

  newx = x
  loop do
    newx = (newx + mx) % @grid.length
    break if @grid[newx].length > 0
  end
  newy = (y + my - @scroll[x] + @scroll[newx])
  if my != 0
    newy %= @grid[newx].length
  end
  if newy >= @grid[newx].length
    newy = @grid[newx].length-1
  end

  move_cursor(newx, newy)
end
resize() click to toggle source
# File lib/eclair/grid.rb, line 121
def resize
  Curses.clear
  @scroll.fill(0)
  @cell_width = Curses.stdscr.maxx/config.columns
  @maxy = Curses.stdscr.maxy - @header_rows
  rescroll(*@cursor)
  draw_all
end
space() click to toggle source
# File lib/eclair/grid.rb, line 68
def space
  if @mode == :nav
    transit_mode(:sel)
  end

  at(*@cursor)&.toggle_select

  if @mode == :sel && @provider.items.all?{|i| !i.selected}
    transit_mode(:nav)
  end


  draw(*@cursor)
end
transit_mode(to) click to toggle source
# File lib/eclair/grid.rb, line 130
def transit_mode to
  return if to == @mode

  case @mode
  when :nav
    at(*@cursor)&.select(false)
  when :sel
  when :search
  when :assign
  end

  @mode = to

  case @mode
  when :nav
    at(*@cursor)&.select(true)
  when :sel
  when :search
  when :assign
    move_cursor(0,0)
  end

  draw_all
end

Private Instance Methods

assign() click to toggle source
# File lib/eclair/grid.rb, line 302
def assign
  old_mode = @mode
  transit_mode(:assign)
  @grid = config.columns.times.map{[]}
  visible_items = @provider.filter_items(@search_buffer)
  @groups = visible_items.group_by(&config.group_by)
  @groups.each do |name, items|
    group_name = "#{name} (#{items.length})"
    target = @grid.min_by(&:length)
    target << @provider.group_class.new(group_name, items)
    items.sort_by(&:label).each do |item|
      target << item
    end
  end
  transit_mode(old_mode)
end
at(x, y) click to toggle source
# File lib/eclair/grid.rb, line 247
def at x, y
  @grid[x][y]
end
color(x, y) click to toggle source
# File lib/eclair/grid.rb, line 269
def color x, y
  if @cursor == [x,y]
    Color.fetch(Curses::COLOR_BLACK, Curses::COLOR_CYAN)
  else
    Color.fetch(*@grid[x][y].color)
  end
end
config() click to toggle source
# File lib/eclair/grid.rb, line 319
def config
  Eclair.config
end
draw(x, y) click to toggle source
# File lib/eclair/grid.rb, line 292
def draw x, y
  target = @grid[x][y]
  draw_item(x, y)
  if target.is_a?(GroupItem)
    (y+1).upto(y+target.length).each do |ny|
      draw_item(x, ny)
    end
  end
end
draw_all() click to toggle source
# File lib/eclair/grid.rb, line 257
def draw_all
  @grid.each_with_index do |column, x|
    column.each_with_index do |_, y|
      draw_item(x,y)
    end
  end
  case @mode
  when :nav, :sel
    update_header(at(*@cursor)&.header || "No Match")
  end
end
draw_item(x, y) click to toggle source
# File lib/eclair/grid.rb, line 277
def draw_item x, y
  target = @grid[x].select{|item| item.visible}[y]

  drawy = y - @scroll[x]
  if drawy < 0 || drawy + @header_rows >= Curses.stdscr.maxy
    return
  end
  cell_color = color(x,y)
  Curses.setpos(drawy + @header_rows, x * @cell_width)
  Curses.attron(cell_color) do
    Curses.addstr make_label(target)
  end
  Curses.refresh
end
make_label(target) click to toggle source
# File lib/eclair/grid.rb, line 251
def make_label target
  ind = (@mode != :nav && target.selected) ? "*" : " "
  label = "#{target.label} #{ind}"
  label.slice(0, @cell_width).ljust(@cell_width)
end
move_cursor(x, y) click to toggle source
# File lib/eclair/grid.rb, line 192
def move_cursor x, y
  prev = @cursor.dup
  @cursor = [x, y]

  prev_item = at(*prev)
  curr_item = at(*@cursor)
  rescroll(*@cursor)
  if @mode == :nav
    prev_item.select(false)
    curr_item.select(true)
  end
  draw(*prev) if prev_item
  draw(*@cursor) if curr_item
  update_header(curr_item.header) if curr_item
end
rescroll(x, y) click to toggle source
# File lib/eclair/grid.rb, line 234
def rescroll x, y
  unless (@scroll[x]...@maxy+@scroll[x]).include? y
    if y < @scroll[x]
      @scroll[x] = y
    elsif y >= @maxy
      @scroll[x] = y - @maxy + 1
    end
    (@scroll[x]...@maxy+@scroll[x]).each do |ty|
      draw_item(x, ty)
    end
  end
end
update_header(str, pos = 0) click to toggle source
# File lib/eclair/grid.rb, line 209
def update_header str, pos = 0
  Curses.setpos(0, 0)
  Curses.clrtoeol
  Curses.addstr(@mode.to_s)
  str.split("\n").map(&:strip).each_with_index do |line, i|
    Curses.setpos(i + pos + 1, 0)
    Curses.clrtoeol
    Curses.addstr(line)
  end
end