Class: TerminalLayout::TerminalRenderer

Inherits:
Object
  • Object
show all
Includes:
HighLine::SystemExtensions, EventEmitter
Defined in:
lib/terminal_layout.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from EventEmitter

#_callbacks, #emit, #on, #unsubscribe

Constructor Details

#initialize(output: $stdout) ⇒ TerminalRenderer

Returns a new instance of TerminalRenderer.



526
527
528
529
530
531
# File 'lib/terminal_layout.rb', line 526

def initialize(output: $stdout)
  @output = output
  @term_info = TermInfo.new ENV["TERM"], @output
  @previously_printed_lines = []
  @x, @y = 0, 0
end

Instance Attribute Details

#term_infoObject (readonly)

Returns the value of attribute term_info.



524
525
526
# File 'lib/terminal_layout.rb', line 524

def term_info
  @term_info
end

Instance Method Details

#clear_screenObject



657
# File 'lib/terminal_layout.rb', line 657

def clear_screen ; term_info.control "clear" ; end

#clear_screen_downObject



658
# File 'lib/terminal_layout.rb', line 658

def clear_screen_down ; term_info.control "ed" ; end

#clear_to_beginning_of_lineObject



656
# File 'lib/terminal_layout.rb', line 656

def clear_to_beginning_of_line ; term_info.control "el1" ; end

#dumb_render(object, reset: false) ⇒ Object



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/terminal_layout.rb', line 603

def dumb_render(object, reset: false)
  if reset
    @y = 0
    @previously_printed_lines.clear
  end
  @output.print @term_info.control_string "civis"
  move_up_n_rows @y
  move_to_beginning_of_row

  object = find_top_of_tree(object)

  object_width = object.width

  rendered_content = object.render
  printable_content = rendered_content.sub(/\s*\Z/m, '')

  printable_lines = printable_content.split(/\n/).each_with_object([]) do |line, results|
    if line.empty?
      results << line
    else
      results.concat line.scan(/.{1,#{terminal_width}}/)
    end
  end

  printable_lines.zip(@previously_printed_lines) do |new_line, previous_line|
    if new_line != previous_line
      # be sure to reset the terminal at the outset of every line
      # because we don't know what state the previous line ended in
      line2print = "#{new_line}\e[0m"
      term_info.control "el"
      move_to_beginning_of_row
      term_info.control "el"
      Treefell['render'].puts "printing line=#{line2print.inspect}"
      @output.puts line2print
    else
      move_down_n_rows 1
    end
  end
  move_to_beginning_of_row
  clear_screen_down

  # calculate lines drawn so we know where we are
  lines_drawn = (printable_content.length / object_width.to_f).ceil
  @y = lines_drawn

  input_box = object.box.find_child_of_type(InputBox) do |box|
    box.focused?
  end
  render_cursor(input_box)

  @previously_printed_lines = printable_lines
end

#find_top_of_tree(object) ⇒ Object



595
596
597
598
599
600
601
# File 'lib/terminal_layout.rb', line 595

def find_top_of_tree(object)
  loop do
    break unless object.parent
    object = object.parent
  end
  object
end

#move_down_n_rows(n) ⇒ Object



666
# File 'lib/terminal_layout.rb', line 666

def move_down_n_rows(n) ; n.times { term_info.control "cud1" } ; end

#move_leftObject



660
# File 'lib/terminal_layout.rb', line 660

def move_left ; move_left_n_characters 1 ; end

#move_left_n_characters(n) ⇒ Object



661
# File 'lib/terminal_layout.rb', line 661

def move_left_n_characters(n) ; n.times { term_info.control "cub1" } ; end

#move_right_n_characters(n) ⇒ Object



662
# File 'lib/terminal_layout.rb', line 662

def move_right_n_characters(n) ; n.times { term_info.control "cuf1" } ; end

#move_to_beginning_of_rowObject



659
# File 'lib/terminal_layout.rb', line 659

def move_to_beginning_of_row ; move_to_column 0 ; end

#move_to_column(n) ⇒ Object



664
# File 'lib/terminal_layout.rb', line 664

def move_to_column(n) ; term_info.control "hpa", n ; end

#move_to_column_and_row(column, row) ⇒ Object



663
# File 'lib/terminal_layout.rb', line 663

def move_to_column_and_row(column, row) ; term_info.control "cup", column, row ; end

#move_up_n_rows(n) ⇒ Object



665
# File 'lib/terminal_layout.rb', line 665

def move_up_n_rows(n) ; n.times { term_info.control "cuu1" } ; end

#render(object, reset: false) ⇒ Object



591
592
593
# File 'lib/terminal_layout.rb', line 591

def render(object, reset: false)
  dumb_render(object, reset: reset)
end

#render_cursor(input_box) ⇒ Object



533
534
535
536
537
538
539
540
541
542
543
544
545
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
# File 'lib/terminal_layout.rb', line 533

def render_cursor(input_box)
  Treefell['render'].puts "render cursor at box=#{input_box.inspect} computed=#{input_box.computed.inspect}"

  move_up_n_rows @y
  move_to_beginning_of_row

  position = input_box.position

  cursor_position = input_box.cursor_position
  cursor_x = cursor_position.x
  cursor_y = cursor_position.y

  relative_position_on_row = position
  initial_offset_x = input_box.computed[:x] + (input_box.computed[:y] * terminal_width)
  cursor_x = 0
  cursor_y = 0

  absolute_position_on_row = relative_position_on_row + initial_offset_x
  loop do
    if absolute_position_on_row >= terminal_width
      # reset offset
      initial_offset_x = 0

      absolute_position_on_row -= terminal_width

      # move down a line
      cursor_y += 1
    else
      # we fit on the current line
      cursor_x = absolute_position_on_row
      break
    end
  end

  if @y < cursor_y
    # moving backwards
    move_up_n_rows(@y - cursor_y)
  elsif @y > cursor_y
    # moving forwards
    move_down_n_rows(cursor_y - @y)
  end

  move_down_n_rows cursor_y
  move_to_beginning_of_row
  move_right_n_characters cursor_x

  @x = cursor_x
  @y = cursor_y

  Treefell['render'].puts "rendering cursor at x=#{@x} y=#{@y}"

  if input_box.style[:cursor] == 'none'
    @output.print @term_info.control_string "civis"
  else
    @output.print @term_info.control_string "cnorm"
  end
end

#terminal_heightObject



672
673
674
# File 'lib/terminal_layout.rb', line 672

def terminal_height
  terminal_size[1]
end

#terminal_widthObject



668
669
670
# File 'lib/terminal_layout.rb', line 668

def terminal_width
  terminal_size[0]
end