3 class ScrollMode < Mode
4 ## we define topline and botline as the top and bottom lines of any
5 ## content in the currentview.
7 ## we left leftcol and rightcol as the left and right columns of any
8 ## content in the current view. but since we're operating in a
9 ## line-centric fashion, rightcol is always leftcol + the buffer
10 ## width. (whereas botline is topline + at most the buffer height,
11 ## and can be == to topline in the case that there's no content.)
13 attr_reader :status, :topline, :botline, :leftcol
17 register_keymap do |k|
18 k.add :line_down, "Down one line", :down, 'j', 'J'
19 k.add :line_up, "Up one line", :up, 'k', 'K'
20 k.add :col_left, "Left one column", :left, 'h'
21 k.add :col_right, "Right one column", :right, 'l'
22 k.add :page_down, "Down one page", :page_down, 'n', ' '
23 k.add :page_up, "Up one page", :page_up, 'p', :backspace
24 k.add :jump_to_start, "Jump to top", :home, '^', '1'
25 k.add :jump_to_end, "Jump to bottom", :end, '$', '0'
26 k.add :jump_to_left, "Jump to the left", '['
27 k.add :search_in_buffer, "Search in current buffer", '/'
28 k.add :continue_search_in_buffer, "Jump to next search occurrence in buffer", BufferManager::CONTINUE_IN_BUFFER_SEARCH_KEY
31 def initialize opts={}
32 @topline, @botline, @leftcol = 0, 0, 0
33 @slip_rows = opts[:slip_rows] || 0 # when we pgup/pgdown,
34 # how many lines do we keep?
35 @twiddles = opts.member?(:twiddles) ? opts[:twiddles] : true
41 def rightcol; @leftcol + buffer.content_width; end
45 (@topline ... @botline).each { |ln| draw_line ln }
46 ((@botline - @topline) ... buffer.content_height).each do |ln|
48 buffer.write ln, 0, "~", :color => :twiddle_color
50 buffer.write ln, 0, ""
53 @status = "lines #{@topline + 1}:#{@botline}/#{lines}"
56 def in_search?; @search_line end
58 def cancel_search!; @search_line = nil end
60 def continue_search_in_buffer
62 BufferManager.flash "No current search!"
66 if(line = find_text(@search_query, @search_line || search_start_line))
67 @search_line = line + 1
71 BufferManager.flash "Not found!"
76 query = BufferManager.ask(:search, "query: ") or return
77 @search_query = Regexp.escape query
78 continue_search_in_buffer
81 ## subclasses can override these two!
82 def search_goto_line line; jump_to_line line end
83 def search_start_line; @topline end
86 return unless @leftcol > 0
97 buffer.mark_dirty unless @leftcol == col
101 def jump_to_left; jump_to_col 0; end
105 l = l.clamp 0, lines - 1
106 return if @topline == l
108 @botline = [l + buffer.content_height, lines].min
112 def at_top?; @topline == 0 end
113 def at_bottom?; @botline == lines end
115 def line_down; jump_to_line @topline + 1; end
116 def line_up; jump_to_line @topline - 1; end
117 def page_down; jump_to_line @topline + buffer.content_height - @slip_rows; end
118 def page_up; jump_to_line @topline - buffer.content_height + @slip_rows; end
119 def jump_to_start; jump_to_line 0; end
120 def jump_to_end; jump_to_line lines - buffer.content_height; end
122 def ensure_mode_validity
123 @topline = @topline.clamp 0, [lines - 1, 0].max
124 @botline = [@topline + buffer.content_height, lines].min
134 def find_text query, start_line
136 (start_line ... lines).each do |i|
139 return i if s =~ regex
141 return i if s.any? { |color, string| string =~ regex }
147 def draw_line ln, opts={}
148 regex = /(#{@search_query})/i
152 draw_line_from_array ln, matching_text_array(s, regex), opts
154 draw_line_from_string ln, s, opts
158 ## seems like there ought to be a better way of doing this
160 s.each do |color, text|
162 array += matching_text_array text, regex, color
164 array << [color, text]
167 draw_line_from_array ln, array, opts
169 draw_line_from_array ln, s, opts
172 raise "unknown drawable object: #{s.inspect}" # good for debugging
176 # str = s.map { |color, text| text }.join
177 # buffer.write ln - @topline, 0, str, :color => :none, :highlight => opts[:highlight]
181 def matching_text_array s, regex, oldcolor=:none
182 s.split(regex).map do |text|
185 [:search_highlight_color, text]
189 end.compact + [[oldcolor, ""]]
192 def draw_line_from_array ln, a, opts
194 a.each do |color, text|
195 raise "nil text for color '#{color}'" if text.nil? # good for debugging
197 if xpos + text.length < @leftcol
198 buffer.write ln - @topline, 0, "", :color => color,
199 :highlight => opts[:highlight]
201 elsif xpos < @leftcol
203 buffer.write ln - @topline, 0, text[(@leftcol - xpos) .. -1],
205 :highlight => opts[:highlight]
208 buffer.write ln - @topline, xpos - @leftcol, text,
209 :color => color, :highlight => opts[:highlight]
215 def draw_line_from_string ln, s, opts
216 buffer.write ln - @topline, 0, s[@leftcol .. -1], :highlight => opts[:highlight]