Class: Marvi::Renderer::Curses::Tab
- Inherits:
-
Object
- Object
- Marvi::Renderer::Curses::Tab
- Defined in:
- lib/marvi/renderer/curses/tab.rb
Overview
Per-document state for one open file: source markdown, walked lines, scroll position, search state, and file-watch bookkeeping. All layout inputs (content width, page size) are passed in by the renderer so this class stays free of curses calls and can be tested headlessly.
Instance Attribute Summary collapse
-
#current_match ⇒ Object
readonly
Returns the value of attribute current_match.
-
#file ⇒ Object
readonly
Returns the value of attribute file.
-
#lines ⇒ Object
readonly
Returns the value of attribute lines.
-
#markdown ⇒ Object
readonly
Returns the value of attribute markdown.
-
#matches ⇒ Object
readonly
Returns the value of attribute matches.
-
#scroll ⇒ Object
Returns the value of attribute scroll.
-
#search_query ⇒ Object
readonly
Returns the value of attribute search_query.
Instance Method Summary collapse
-
#check_file_updated ⇒ Object
Returns true when the file changed on disk since the last check and the updated flag was newly raised.
- #clamp_scroll(page_size) ⇒ Object
- #clear_search ⇒ Object
- #commit_search ⇒ Object
- #current_source_line(page_size) ⇒ Object
-
#ensure_walked(width, page_size) ⇒ Object
Walk lazily: tabs that are not visible keep their lines from the last width they were displayed at and re-walk only when shown again.
- #file_updated? ⇒ Boolean
- #highlight_ranges_for(line_index) ⇒ Object
-
#initialize(file: nil, markdown: nil) ⇒ Tab
constructor
A new instance of Tab.
- #jump_match(direction, page_size) ⇒ Object
- #label ⇒ Object
- #mark_reloaded ⇒ Object
- #max_scroll(page_size) ⇒ Object
- #reload(width, page_size) ⇒ Object
- #rewalk(width, page_size) ⇒ Object
- #scroll_by(delta, page_size) ⇒ Object
- #search_hint ⇒ Object
-
#update_search(query, page_size) ⇒ Object
--- search ---.
- #visible_lines(page_size) ⇒ Object
Constructor Details
#initialize(file: nil, markdown: nil) ⇒ Tab
Returns a new instance of Tab.
14 15 16 17 18 19 20 21 22 |
# File 'lib/marvi/renderer/curses/tab.rb', line 14 def initialize(file: nil, markdown: nil) @file = file @markdown = markdown || read_file @scroll = 0 @lines = [] @walked_width = nil clear_search mark_reloaded end |
Instance Attribute Details
#current_match ⇒ Object (readonly)
Returns the value of attribute current_match.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def current_match @current_match end |
#file ⇒ Object (readonly)
Returns the value of attribute file.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def file @file end |
#lines ⇒ Object (readonly)
Returns the value of attribute lines.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def lines @lines end |
#markdown ⇒ Object (readonly)
Returns the value of attribute markdown.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def markdown @markdown end |
#matches ⇒ Object (readonly)
Returns the value of attribute matches.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def matches @matches end |
#scroll ⇒ Object
Returns the value of attribute scroll.
12 13 14 |
# File 'lib/marvi/renderer/curses/tab.rb', line 12 def scroll @scroll end |
#search_query ⇒ Object (readonly)
Returns the value of attribute search_query.
11 12 13 |
# File 'lib/marvi/renderer/curses/tab.rb', line 11 def search_query @search_query end |
Instance Method Details
#check_file_updated ⇒ Object
Returns true when the file changed on disk since the last check and the updated flag was newly raised.
77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/marvi/renderer/curses/tab.rb', line 77 def check_file_updated return false unless @file mtime = current_mtime return false if mtime.nil? || mtime == @last_mtime @last_mtime = mtime return false if @file_updated @file_updated = true true end |
#clamp_scroll(page_size) ⇒ Object
54 55 56 |
# File 'lib/marvi/renderer/curses/tab.rb', line 54 def clamp_scroll(page_size) @scroll = @scroll.clamp(0, max_scroll(page_size)) end |
#clear_search ⇒ Object
111 112 113 114 115 |
# File 'lib/marvi/renderer/curses/tab.rb', line 111 def clear_search @search_query = nil @matches = [] @current_match = nil end |
#commit_search ⇒ Object
107 108 109 |
# File 'lib/marvi/renderer/curses/tab.rb', line 107 def commit_search clear_search if @search_query.to_s.empty? || @matches.empty? end |
#current_source_line(page_size) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/marvi/renderer/curses/tab.rb', line 66 def current_source_line(page_size) visible_lines(page_size).each { |line| return line.source_line if line.source_line } # fall back to searching upward from scroll position @scroll.downto(0) { |i| return @lines[i].source_line if @lines[i]&.source_line } 1 end |
#ensure_walked(width, page_size) ⇒ Object
Walk lazily: tabs that are not visible keep their lines from the last width they were displayed at and re-walk only when shown again.
30 31 32 33 34 35 36 37 |
# File 'lib/marvi/renderer/curses/tab.rb', line 30 def ensure_walked(width, page_size) return if @walked_width == width @walked_width = width @lines = ASTWalker.new.walk(@markdown, max_width: width) clamp_scroll(page_size) refresh_search_after_rewalk(page_size) end |
#file_updated? ⇒ Boolean
90 91 92 |
# File 'lib/marvi/renderer/curses/tab.rb', line 90 def file_updated? @file_updated end |
#highlight_ranges_for(line_index) ⇒ Object
127 128 129 130 131 132 133 134 135 |
# File 'lib/marvi/renderer/curses/tab.rb', line 127 def highlight_ranges_for(line_index) return nil if @matches.empty? ranges = [] @matches.each_with_index do |(li, start, finish), i| ranges << [start, finish, i == @current_match] if li == line_index end ranges.empty? ? nil : ranges end |
#jump_match(direction, page_size) ⇒ Object
117 118 119 120 121 122 123 124 125 |
# File 'lib/marvi/renderer/curses/tab.rb', line 117 def jump_match(direction, page_size) return if @matches.empty? if @current_match.nil? focus_match_from(@scroll, page_size) else set_current_match(@current_match + direction, page_size) end end |
#label ⇒ Object
24 25 26 |
# File 'lib/marvi/renderer/curses/tab.rb', line 24 def label @file ? File.basename(@file) : "(stdin)" end |
#mark_reloaded ⇒ Object
94 95 96 97 |
# File 'lib/marvi/renderer/curses/tab.rb', line 94 def mark_reloaded @last_mtime = current_mtime @file_updated = false end |
#max_scroll(page_size) ⇒ Object
50 51 52 |
# File 'lib/marvi/renderer/curses/tab.rb', line 50 def max_scroll(page_size) [@lines.size - page_size, 0].max end |
#reload(width, page_size) ⇒ Object
44 45 46 47 48 |
# File 'lib/marvi/renderer/curses/tab.rb', line 44 def reload(width, page_size) @markdown = read_file rewalk(width, page_size) mark_reloaded end |
#rewalk(width, page_size) ⇒ Object
39 40 41 42 |
# File 'lib/marvi/renderer/curses/tab.rb', line 39 def rewalk(width, page_size) @walked_width = nil ensure_walked(width, page_size) end |
#scroll_by(delta, page_size) ⇒ Object
58 59 60 |
# File 'lib/marvi/renderer/curses/tab.rb', line 58 def scroll_by(delta, page_size) @scroll = (@scroll + delta).clamp(0, max_scroll(page_size)) end |
#search_hint ⇒ Object
137 138 139 140 141 142 143 |
# File 'lib/marvi/renderer/curses/tab.rb', line 137 def search_hint return " n/N next/prev" if @search_query.nil? || @search_query.empty? return " no matches: #{@search_query}" if @matches.empty? position = @current_match ? @current_match + 1 : 0 " [#{position}/#{@matches.size}] n/N" end |
#update_search(query, page_size) ⇒ Object
--- search ---
101 102 103 104 105 |
# File 'lib/marvi/renderer/curses/tab.rb', line 101 def update_search(query, page_size) @search_query = query recompute_matches focus_match_from(@scroll, page_size) unless @matches.empty? end |
#visible_lines(page_size) ⇒ Object
62 63 64 |
# File 'lib/marvi/renderer/curses/tab.rb', line 62 def visible_lines(page_size) @lines[@scroll, page_size] || [] end |