Class: Typr::Text

Inherits:
Stack show all
Defined in:
lib/text.rb

Overview

A vertically scrollable text viewer with word-wrapping, header bar, row selection via hint characters, and search.

Accepts String, IO, or StringIO input. Content is split into display rows by newlines and line width, then rendered as a sliding window.

Example

text = Typr::Text.new(
input: StringIO.new("Hello\nworld"),
header: "My Doc",
top: 2, left: 0.1, right: 0.9, bottom: -4,
border: :round,
colors: { header: [:yellow, :grey30] }
)
text.draw

Constant Summary

Constants included from Typr

COLORS, INPUT, KEY_DELETE, KEY_ENTER, KEY_ESCAPE, KEY_INSERT, KEY_PAGEDOWN, KEY_PAGEUP, KEY_RETURN, KEY_TAB, MIMETYPES, MODES, OUTPUT

Instance Attribute Summary collapse

Attributes inherited from Stack

#header, #hints, #hints_start, #keymap, #selected, #separator, #start

Attributes inherited from Space

#borders, #bottom, #colors, #interval, #left, #margin, #right, #top

Instance Method Summary collapse

Methods inherited from Stack

#cycle, #down, #draw_hints, #headspace, #height, #page, #page_down, #page_up, #pick, #reset, #send, #to_bottom, #to_top, #up

Methods inherited from Space

#border=, #draw_border, #height, #start, #stop, #width

Methods included from Typr

#background, clear, #color, #color_code, column, exit, #fade, #foreground, #get_background, #get_foreground, height, init, #mode, #mode_code, #move, #move_code, position, #prepare, #printables, read, #real_size, row, #show, size, width

Constructor Details

#initialize(args = {}) ⇒ Text

Creates a new Text widget.

text = Typr::Text.new(input: "hello", header: "Title")
text = Typr::Text.new(input: $stdin, tabspace: 4)


130
131
132
133
134
135
136
137
# File 'lib/text.rb', line 130

def initialize args={}
  @tabspace = 2
  @data, @lines, @tail = "", [0], ""
  super args
  @colors = { header: :yellow }.merge( @colors || {} )
  @lastwidth = width
  self << @input
end

Instance Attribute Details

#tabspaceObject

Tabstop width in spaces. Default: 2.



30
31
32
# File 'lib/text.rb', line 30

def tabspace
  @tabspace
end

Instance Method Details

#build(input = nil) ⇒ Object Also known as: <<

Rebuilds the internal line buffer from input. Splits text at newlines and word boundaries to fit the current width. Pass nil to re-parse from the existing buffer (triggered on resize).

text.build("one\ntwo three")  # => #<Typr::Text ...>
text << "appended line"       # alias for build


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/text.rb', line 39

def build input=nil
  ( @lines = [0]; input = "" ) if rebuild = !input
  return self if rebuild && input == ""
  input = StringIO.new( input.to_s.dup ) unless input.respond_to?(:read)
  @tail = ""
  until input.closed? or input.eof?
    capacity = width - @margin.size - @tail.length
    chunk = (capacity < 1) ? "x" : capacity
    line = @tail + input.read(chunk)
    if line.empty?
      break
    else
      wrap_idx = line.index("\n") || line.rindex(" ") || line.length
      wrap = [wrap_idx, line.length].min + 1
      @data += line[0...wrap]
      if wrap < line.length
        @tail = line[wrap..-1]
        @lines << @data.length
      else
        @tail = ""
      end
    end
    break if rebuild && line[-1] == "\n"
  end
  until @tail.empty?
    wrap_idx = @tail.index("\n") || @tail.rindex(" ") || @tail.length
    wrap = [wrap_idx, @tail.length].min + 1
    @data += @tail[0...wrap]
    if wrap < @tail.length
      @lines << @data.length
      @tail = @tail[wrap..-1]
    else
      @tail = ""
    end
  end
  @lines << @data.length unless @lines.last == @data.length
end

#drawObject

Full draw cycle: rebuilds on resize, computes visible lines, and renders the viewport with borders and hints.

text.draw


104
105
106
107
108
109
110
# File 'lib/text.rb', line 104

def draw
  (build; @lastwidth = width) if width != @lastwidth
  range = @lines[@start..@start+height]
  page = StringIO.new @data[range.first..range.last]
  @page=range[1..-1].map{|pos| page.read(pos-range.first-page.pos).rstrip}
  super
end

#positions(row) ⇒ Object

Returns word-boundary column offsets for a given page row. Used internally to place hint markers between words.

text.positions(2)  # => [0, 6, 10, ...]


95
96
97
# File 'lib/text.rb', line 95

def positions row
  [0] + @page[row-1].chars.map.with_index{|c,i| i+1 if c == @separator}.compact
end

Renders a single display row. Pass an Integer for a content row or :header for the header bar.

text.print(:header)  # renders the header bar
text.print(3)        # renders row 3 of the current page


84
85
86
87
88
# File 'lib/text.rb', line 84

def print row=nil
  header = ( row == :header )
  return super unless row and @lines[ row + 1 ] unless header
  show prepare( ( header ? @header : @page[ row-@start ] ), width )
end

#rowsObject

Total number of text lines in the buffer.

text.rows  # => 42


116
# File 'lib/text.rb', line 116

def rows; @lines.count end

#search(query) ⇒ Object

Placeholder for text search. Currently unimplemented.

text.search("query")  # => nil


122
123
# File 'lib/text.rb', line 122

def search query
end