class Listpager::ClientTerminal
Attributes
list[R]
locked[R]
self_pipe[R]
tty[R]
Public Class Methods
new()
click to toggle source
# File lib/listpager/client_terminal.rb, line 18 def initialize @tty = File.open('/dev/tty', 'r+') @self_pipe = IO.pipe @locked = false [@tty, *self_pipe].each do |io| io.sync = true end initialize_curses @list = List.new(Ncurses.stdscr) connect_list @buffer = '' @locked_buffer = [] end
Public Instance Methods
cmd!(*args, observe_lock: false)
click to toggle source
# File lib/listpager/client_terminal.rb, line 92 def cmd!(*args, observe_lock: false) line!('%' + Shellwords.join(args.map(&:to_s)), observe_lock: observe_lock) end
connect_list()
click to toggle source
# File lib/listpager/client_terminal.rb, line 49 def connect_list cterm = self list.define_singleton_method :on_select_change do cterm.cmd!('selected-is', selected, selected_value, observe_lock: true) end list.define_singleton_method :on_key_press do |k| cterm.cmd!('key-pressed', cterm.key_name(k), selected, selected_value, observe_lock: true) end end
consume_self_pipe(handles, fd)
click to toggle source
We get a character from self_pipe
here telling us the window has resized.
# File lib/listpager/client_terminal.rb, line 202 def consume_self_pipe(handles, fd) code = fd.read(1) case code when 'R' new_size = IO.console.winsize Ncurses.resizeterm(*new_size) Ncurses.stdscr.clear list.dirty! list.render Ncurses.refresh end end
consume_stdin(handles, fd)
click to toggle source
# File lib/listpager/client_terminal.rb, line 168 def consume_stdin(handles, fd) loop do begin @buffer << fd.read_nonblock(512) rescue EOFError handles.delete(fd) break rescue IO::WaitReadable break end end unless @buffer.empty? used = 0 StringIO.new(@buffer).each_line do |line| if line[-1] == "\n" process_line(line.chomp) used += line.size else break end end @buffer = @buffer[used...-1] end end
consume_tty(handles, fd)
click to toggle source
# File lib/listpager/client_terminal.rb, line 194 def consume_tty(handles, fd) while (ch = Ncurses.getch) != -1 list.key_input(ch) end end
deinitialize()
click to toggle source
# File lib/listpager/client_terminal.rb, line 75 def deinitialize Ncurses.echo Ncurses.nocbreak Ncurses.nl Ncurses.endwin @tty.close end
dispatch_fd(handles, fd)
click to toggle source
# File lib/listpager/client_terminal.rb, line 215 def dispatch_fd(handles, fd) case fd when $stdin consume_stdin(@handles, fd) when tty consume_tty(@handles, fd) when self_pipe[0] consume_self_pipe(@handles, fd) end end
initialize_curses()
click to toggle source
# File lib/listpager/client_terminal.rb, line 61 def initialize_curses screen = Ncurses.newterm(nil, @tty, @tty) Ncurses.set_term(screen) Ncurses.start_color Color.init Ncurses.use_default_colors Ncurses.cbreak Ncurses.stdscr.scrollok(false) Ncurses.stdscr.keypad(true) Ncurses.curs_set(0) Ncurses.noecho Ncurses.timeout(0) end
key_name(v)
click to toggle source
# File lib/listpager/client_terminal.rb, line 36 def key_name(v) @m ||= { 27 => 'esc', 10 => 'enter', 260 => 'left', 261 => 'right', 127 => 'backspace', 330 => 'delete', ' ' => 'space', } @m[v] || (v < 255 && v.chr.match(/[[:print:]]/) ? v.chr : "\##{v}") end
line!(line, observe_lock: false)
click to toggle source
# File lib/listpager/client_terminal.rb, line 83 def line!(line, observe_lock: false) if observe_lock && @locked @locked_buffer.push(line) else $stdout.puts line $stdout.flush end end
process_command(argv)
click to toggle source
# File lib/listpager/client_terminal.rb, line 97 def process_command(argv) cmd, *args = argv case cmd # TODO: This to be refactored into CommandProcessor when 'quit' raise Interrupt when 'clear' list.values = [] list.selected = 0 list.dirty! wake_up when 'append' list.values.push(args.fetch(0)) list.dirty! when 'lock' @locked = true cmd! 'lock' when 'unlock' @locked = false cmd! 'unlock' @locked_buffer.each do |line| line!(line) end @locked_buffer = [] when 'get-title' cmd! 'title-is', @list.title when 'set-title' @list.title = args[0] cmd! 'title-is', @list.title when 'get-selected' cmd! 'selected-is', list.selected, list.selected_value when 'set-selected' list.selected = args.fetch(0).to_i when 'get-item' cmd! 'item-is', args.fetch(0), list.values[args.fetch(0).to_i] when 'set-item' list.values[args.fetch(0).to_i] = args.fetch(1) list.dirty! cmd! 'item-is', args.fetch(0), list.values[args.fetch(0).to_i] end end
process_events()
click to toggle source
# File lib/listpager/client_terminal.rb, line 226 def process_events @handles ||= [$stdin, tty, self_pipe[0]] return if @handles.empty? res = IO.select(@handles) if res && (readers = res[0]) readers.each do |fd| dispatch_fd(@handles, fd) end end end
process_line(line)
click to toggle source
# File lib/listpager/client_terminal.rb, line 155 def process_line(line) if line[0] == '%' && line[1] != '%' cmd = Shellwords.split(line[1..-1]) process_command(cmd) else if line[0] == '%' line = line[1..-1] end list.values.push(line) list.dirty! end end
run()
click to toggle source
# File lib/listpager/client_terminal.rb, line 239 def run trap 'WINCH' do wake_up end begin loop do process_events if list.render Ncurses.redrawwin(list.window) Ncurses.refresh end end ensure deinitialize end end
wake_up()
click to toggle source
# File lib/listpager/client_terminal.rb, line 146 def wake_up self_pipe[1].tap do |fd| fd.nonblock do fd.write('R') fd.flush end end end