class Zashoku::Viewer

Main class for the zashoku application

Constants

CMD_HISTORY
COMMANDS
SRCH_HISTORY

Public Class Methods

new(host:, port:) click to toggle source
# File lib/viewer.rb, line 57
def initialize(host:, port:)
  @host, @port = host, port
  @semaphore = Mutex.new

  Zashoku.logger = Logger.new(
    File.join(Zashoku::CConf[:app][:root], "#{Zashoku::CConf[:app][:name]}.log")
  )
  Zashoku.logger.level = Zashoku::CConf[:app][:log_level][:viewer]

  Zashoku.conf = ViewConfig.new

  Zashoku.modules = Zashoku::Module.load(Zashoku::CConf[:app][:modules][:viewer])
  Zashoku.modules.merge!('conf' => Conf)
  Zashoku.conf.reload

  # note: start daemon if not running
  Zashoku.client = Net::Client.new(host, port)
  Zashoku.client.callbacks << method(:handle_event)

  @server_modules = Zashoku.client.command('modules')

  @views = Zashoku.modules.keys.zip(Zashoku.modules.map do |_k, m|
    m.view
  end).to_h
  @view = @views.keys.first

  @statusline = Statusline.new
  @statusline.add_observer(self, :draw_statusline)

  @cmdline = Util::Readline.new(
    ':',
    ac_tree:
        @views.map { |k, v| [k, v.methods - Object.methods] }.to_h
        .merge(COMMANDS.map { |k, _v| [k, nil] }.to_h)
        .merge({'conf' => Zashoku.conf.methods - Object.methods })
        .merge(@server_modules.map { |m| ['remote::' + m, nil] }.to_h),
    history: Util.get_yaml(CMD_HISTORY, [])
  )
  @searchline = Util::Readline.new('/', history: Util.get_yaml(SRCH_HISTORY, []))

  init_screen
  lay_traps!
  Thread.abort_on_exception = true
  Thread.new { scan_keyboard! }

  init_view(@view) if @view
  @statusline.draw
  sleep
end

Public Instance Methods

builtin_command(cmd, *args) click to toggle source
# File lib/viewer.rb, line 217
def builtin_command(cmd, *args)
  Zashoku.logger.debug("executing builtin #{cmd}(#{args})")
  send(COMMANDS[cmd], *args)
end
change_view(new_view) click to toggle source
# File lib/viewer.rb, line 119
def change_view(new_view)
  Zashoku.logger.debug("Changing view to #{new_view}")
  @views[@view].delete_observers
  #@views[new_view].change_screen_size(redraw: false)
  #@views[new_view].expand(-1)
  @view = new_view
  init_view(@view)
end
cleanup() click to toggle source
# File lib/viewer.rb, line 151
def cleanup
  Zashoku.client.disconnect
  @views.each do |m, v|
    Zashoku.logger.debug("sending cleanup to #{m} #{v}")
    v&.send(:cleanup)
  end
  @key_thread&.exit
  Curses.close_screen

  unless Zashoku::CConf[:app][:persistent_daemon]
    Zashoku.command_server('stop')
  end

  if Zashoku::Conf.save?
    Util.put_yaml(CMD_HISTORY, @cmdline.history)
    Util.put_yaml(SRCH_HISTORY, @searchline.history)
  end
ensure
  Term.show_cursor
  exit!
end
command(mod, meth, *args) click to toggle source
# File lib/viewer.rb, line 180
def command(mod, meth, *args)
  if /^remote::.*/.match?(mod)
    Zashoku.command(mod: mod, meth: meth, args: args)
  elsif @views.key?(mod) && @views[mod].respond_to?(meth)
    @views[mod].send(meth, *args)
  elsif @views.key?(mod)
    raise "#{mod} has no method '#{meth}'"
  else
    raise "module '#{mod}' not loaded"
  end
end
draw_statusline() click to toggle source
# File lib/viewer.rb, line 273
def draw_statusline
  @statusline.draw
end
draw_view() click to toggle source
# File lib/viewer.rb, line 269
def draw_view
  @views[@view].draw
end
get_user_command() click to toggle source
# File lib/viewer.rb, line 192
def get_user_command
  cmd = @cmdline.read
  return unless cmd
  return builtin_command(*cmd.split) if COMMANDS.key?(cmd.split.first)
  raise "no such command" if cmd.split.length == 1
  command(*cmd.split) unless cmd.empty?
rescue StandardError => e
  Zashoku.logger.error("#{cmd.split} raised an error '#{e}'")
  Util.alert("Error: #{e}")
end
handle_event(event) click to toggle source
# File lib/viewer.rb, line 208
def handle_event(event)
  return @statusline.event(event) if event['statusline']

  case event['event']
  when 'items'
    command(event['sender'], :refresh)
  end
end
init_screen() click to toggle source
# File lib/viewer.rb, line 173
def init_screen
  Curses.noecho
  Curses.init_screen
  Term.hide_cursor
  Curses.stdscr.keypad(true)
end
init_view(view) click to toggle source
# File lib/viewer.rb, line 128
def init_view(view)
  @views[view].add_observer(self, :draw_view)
  @views[view].refresh
  @views[view].dirty_all_lines
  draw_view
end
lay_traps!() click to toggle source
# File lib/viewer.rb, line 135
def lay_traps!
  Signal.trap('WINCH') do
    Thread.new do
      @semaphore.synchronize do
        @views[@view].change_screen_size
        @statusline.change_screen_size
      end
    end
  end
  Signal.trap('INT') do
    Thread.new do
      @semaphore.synchronize { Util.alert(Zashoku::CConf[:app][:msg][:quit]) }
    end
  end
end
map_key(key, mod, *command) click to toggle source
# File lib/viewer.rb, line 222
def map_key(key, mod, *command)
  Zashoku.conf.set(['keymaps', mod, key], command.join(' '))
end
print_version() click to toggle source
reconnect_client() click to toggle source
# File lib/viewer.rb, line 107
def reconnect_client
    loop do
      @socket = connect(@host, @port, loud_fail: false)
      break if @socket
      sleep 1
    end

    @alive = true
    start_threads
    Util.alert('regained connection!')
end
scan_keyboard!() click to toggle source
# File lib/viewer.rb, line 230
def scan_keyboard!
  loop do
    key  = Curses.getch
    maps = Zashoku.conf.get(%w[keymaps])
    cmd =
      if maps['global'].key?(key)
        maps['global'][key]
      elsif maps[@view]&.key?(key)
        maps[@view][key]
      else
        ''
      end

    if COMMANDS.key?(cmd.split.first)
      builtin_command(*cmd.split)
      next
    end

    mod, meth, *args = cmd.split
    mod = mod == '$current_view' ? @view : mod
    args.map! do |arg|
      if arg.chr == '$'
        arg = arg[1..-1]
        chain = arg.split('.')
        chain[1..-1].reduce(@views[@view].send(chain.first)) do |m, a|
          m.send(a)
        end
      else
        arg
      end
    end
    begin
      command(mod, meth, *args)
    rescue Exception => e
      Zashoku.logger.error("#{[mod, meth, args].join(', ')} raised #{e}")
    end
  end
end