Class: Typr::Text
Overview
) text.show
Constant Summary
Constants included from Typr
COLORS, COLOR_MAP, ERASE_LINE, INPUT, KEY_ESCAPE, KEY_PAGEDOWN, KEY_PAGEUP, KEY_RETURN, KEY_TAB, MIMETYPES, MODES
Instance Attribute Summary collapse
-
#tabspace ⇒ Object
Tabstop width in spaces.
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
-
#build(input = nil) ⇒ Object
(also: #<<)
Rebuilds the internal line buffer from
input. -
#highlight ⇒ Object
Recompute the set of lines containing the current pattern.
-
#highlight_clear ⇒ Object
Clear the search pattern and all match highlights.
-
#initialize(args = {}) ⇒ Text
constructor
Creates a new Text widget.
-
#positions(row) ⇒ Object
Returns word-boundary column offsets for a given page row.
-
#print(row = nil) ⇒ Object
Renders a single display row.
- #reset(type = :all) ⇒ Object
-
#rows ⇒ Object
Total number of text lines in the buffer.
-
#search(query = nil, dir = :forward) ⇒ Object
Pager-style search over the buffer, modeled after less/vim.
-
#search_next ⇒ Object
Jump to the next match of the last search (wrap-around).
-
#search_prev ⇒ Object
Jump to the previous match of the last search (wrap-around).
-
#show ⇒ Object
Full draw cycle: rebuilds on resize, computes visible lines, and renders the viewport with borders and hints.
Methods inherited from Stack
#cycle, #down, #draw_hints, #headspace, #height, #page, #page_down, #page_up, #pick, #send, #to_bottom, #to_top, #up
Methods inherited from Space
#border=, #draw_border, #height, #start, #stop, #symbolize, #width
Methods included from Typr
#background, clear, #clip, #coerce_type, #color, #color_code, column, #draw, exit, #fade, #foreground, #get_background, #get_foreground, height, init, #mode, #mode_code, #move, #move_code, on_resize, position, #prepare, #printables, read_key, read_line, #real_size, row, size, text_width, width, word_next, word_prev
Constructor Details
#initialize(args = {}) ⇒ Text
183 184 185 186 187 188 189 190 191 192 |
# File 'lib/text.rb', line 183 def initialize args={} @tabspace = 2 @data, @lines, @tail = "", [0], "" @search = { pattern: nil, dir: :forward, last: nil, matches: [] } super args @colors = { header: :yellow, search: :grey20 }.merge( @colors || {} ) @keymap = { search: ?/, search_next: ?n, search_prev: ?p }.merge @keymap @lastwidth = width self << @input end |
Instance Attribute Details
#tabspace ⇒ Object
Tabstop width in spaces. Default: 2.
26 27 28 |
# File 'lib/text.rb', line 26 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
35 36 37 38 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 |
# File 'lib/text.rb', line 35 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 highlight if @re end |
#highlight ⇒ Object
Recompute the set of lines containing the current pattern.
162 163 164 165 166 167 |
# File 'lib/text.rb', line 162 def highlight @search[:matches] = @re ? @lines[0...-1].each_index.select{ |i| @data[ @lines[i] ... @lines[i+1] ][ @re ] } : [] return end |
#highlight_clear ⇒ Object
Clear the search pattern and all match highlights.
171 172 173 174 175 176 |
# File 'lib/text.rb', line 171 def highlight_clear @re = @search[:pattern] = nil @search[:matches] = [] @search[:last] = nil return 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, ...]
99 100 101 |
# File 'lib/text.rb', line 99 def positions row [0] + @page[row-1].chars.map.with_index{|c,i| i+1 if c == @separator}.compact end |
#print(row = nil) ⇒ Object
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
81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/text.rb', line 81 def print row=nil header = ( row == :header ) return super unless row and @lines[ row + 1 ] unless header text = ( header ? @header : @page[ row-@start ] ) if row.is_a?(Integer) and @search[:matches].include? row background @colors[:search] draw prepare( text, width ) background else draw prepare( text, width ) end end |
#reset(type = :all) ⇒ Object
194 195 196 197 198 199 200 |
# File 'lib/text.rb', line 194 def reset type=:all case type when :search; highlight_clear when :all; reset [:position, :selection, :search]; return end super end |
#rows ⇒ Object
Total number of text lines in the buffer.
text.rows # => 42
120 |
# File 'lib/text.rb', line 120 def rows; @lines.count end |
#search(query = nil, dir = :forward) ⇒ Object
Pager-style search over the buffer, modeled after less/vim.
With a query (String, matched literally, or Regexp) it stores the
pattern, highlights every matching line, and scrolls to the first
match from the current position. dir is :forward or :backward.
Returns the matched line id, or nil when nothing matches.
With no argument it prompts interactively for a pattern at the bottom of the screen (pressing Return searches, Escape aborts).
Matching is smart-case: lowercase queries are case-insensitive; a query containing an uppercase letter is case-sensitive.
text.search "needle" # => 12 (or nil)
text.search /^TODO/ # => 3
text.search "needle", :backward # search upward
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/text.rb', line 140 def search query=nil, dir=:forward return search_prompt if query.nil? @search[:pattern] = query @search[:dir] = dir @search[:last] = nil @re = query.is_a?(Regexp) ? query : Regexp.new( Regexp.escape( query ), ( query[/[A-Z]/] ? 0 : Regexp::IGNORECASE ) ) highlight step end |
#search_next ⇒ Object
Jump to the next match of the last search (wrap-around). Returns its line id or nil.
154 |
# File 'lib/text.rb', line 154 def search_next; @search[:dir] = :forward; step end |
#search_prev ⇒ Object
Jump to the previous match of the last search (wrap-around). Returns its line id or nil.
158 |
# File 'lib/text.rb', line 158 def search_prev; @search[:dir] = :backward; step end |
#show ⇒ Object
Full draw cycle: rebuilds on resize, computes visible lines, and renders the viewport with borders and hints.
text.show
108 109 110 111 112 113 114 |
# File 'lib/text.rb', line 108 def show (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 |