Class: Typr::Text
Overview
) text.show
Constant Summary
Constants included from Typr
ALT_SCREEN_OFF, ALT_SCREEN_ON, COLORS, COLOR_MAP, DEFAULT_KEYS, ERASE_LINE, INPUT, KEY_ALT_BACKSPACE, KEY_ALT_LEFT, KEY_ALT_RIGHT, KEY_BACK_TAB, KEY_ESCAPE, KEY_PAGEDOWN, KEY_PAGEUP, KEY_RETURN, KEY_TAB, MIMETYPES, MODES, MOUSE_OFF, MOUSE_ON, ORIG_COLORS, TERMINFO
Instance Attribute Summary collapse
-
#tabspace ⇒ Object
Tabstop width in spaces.
Attributes inherited from Stack
#header, #hints, #hints_start, #keymap, #modifier, #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
Reset state:
:searchclears the pattern and highlights;:allresets position, selection, and search; else falls through to Stack#reset. -
#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, #cycle_back, #data_at, #down, #draw_hints, #headspace, #height, #hit, #page, #page_down, #page_up, #pick, #send, #to_bottom, #to_top, #up
Methods inherited from Space
#border=, #data_at, #draw_border, #extract_key, #height, #start, #stop, #symbolize, #width
Methods included from Typr
#background, clear, #clip, #coerce_type, #color, #color_code, column, decode_mouse, #draw, exit, #fade, #foreground, #get_background, #get_foreground, height, init, #mode, #mode_code, #move, #move_code, on_resize, position, #prepare, read_key, read_line, #real_size, row, #sanitize, size, slice_width, text_width, width, word_next, word_prev
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)
195 196 197 198 199 200 201 202 203 204 |
# File 'lib/text.rb', line 195 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 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/text.rb', line 35 def build input=nil ( input, @data, @lines = @data, "", [0] ) if rebuild = !input return self if rebuild && input == "" str = input.respond_to?(:read) ? input.read : input.to_s @tail = "" pos = 0 while pos < str.size || !@tail.empty? capacity = width - @margin.size - real_size(@tail) cap = [capacity, 1].max added = 0; cells = 0 while pos + added < str.size c = str[pos + added] if c == ?\e seq = str[(pos+added)..][/\A\e\[[0-9;]*m/] added += seq ? seq.size : 1 elsif c == ?\n added += 1; break else cw = Unicode::DisplayWidth.of(c) break if cells + cw > cap cells += cw; added += 1 end end line = @tail + str[pos, added] pos += added break if line.empty? 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] else @tail = "" end @lines << @data.length if wrap < line.length || line.include?("\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.
174 175 176 177 178 179 |
# File 'lib/text.rb', line 174 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.
183 184 185 186 187 188 |
# File 'lib/text.rb', line 183 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, ...]
111 112 113 |
# File 'lib/text.rb', line 111 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
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/text.rb', line 93 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 - @margin.size ) background else draw prepare( text, width - @margin.size ) end end |
#reset(type = :all) ⇒ Object
Reset state: :search clears the pattern and highlights; :all resets
position, selection, and search; else falls through to Stack#reset.
208 209 210 211 212 213 214 |
# File 'lib/text.rb', line 208 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
132 |
# File 'lib/text.rb', line 132 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
152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/text.rb', line 152 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.
166 |
# File 'lib/text.rb', line 166 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.
170 |
# File 'lib/text.rb', line 170 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
120 121 122 123 124 125 126 |
# File 'lib/text.rb', line 120 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 |