3 ## extends ScrollMode to have a line-based cursor.
4 class LineCursorMode < ScrollMode
6 ## overwrite scrollmode binding on arrow keys for cursor movement
7 ## but j and k still scroll!
8 k.add :cursor_down, "Move cursor down one line", :down, 'j'
9 k.add :cursor_up, "Move cursor up one line", :up, 'k'
10 k.add :select, "Select this item", :enter
15 def initialize opts={}
16 @cursor_top = @curpos = opts.delete(:skip_top_rows) || 0
17 @load_more_callbacks = []
18 @load_more_q = Queue.new
19 @load_more_thread = ::Thread.new do
22 debug "calling callbacks on #{e.inspect}"
23 @load_more_callbacks.each { |c| c.call e }
31 @load_more_thread.kill
32 debug "killing thread"
43 ## callbacks when the cursor is asked to go beyond the bottom
45 @load_more_callbacks << b
48 def draw_line ln, opts={}
50 super ln, :highlight => true, :debug => opts[:debug]
56 def ensure_mode_validity
58 raise @curpos.inspect unless @curpos.is_a?(Integer)
59 c = @curpos.clamp topline, botline - 1
60 c = @cursor_top if c < @cursor_top
61 buffer.mark_dirty unless c == @curpos
66 return if @curpos == p
67 @curpos = p.clamp @cursor_top, lines
71 ## override search behavior to be cursor-based. this is a stupid
72 ## implementation and should be made better. TODO: improve.
73 def search_goto_line line
74 page_down while line >= botline
75 page_up while line < topline
79 def search_start_line; @curpos end
81 def line_down # overwrite scrollmode
83 call_load_more_callbacks([topline + buffer.content_height - lines, 10].max) if topline + buffer.content_height > lines
84 set_cursor_pos topline if @curpos < topline
87 def line_up # overwrite scrollmode
89 set_cursor_pos botline - 1 if @curpos > botline - 1
93 call_load_more_callbacks buffer.content_height if @curpos >= lines - [buffer.content_height/2,1].max
94 return false unless @curpos < lines - 1
96 if @curpos >= botline - 1
98 set_cursor_pos topline
102 draw_line @curpos - 1
112 return false unless @curpos > @cursor_top
113 if @curpos == topline
114 old_topline = topline
116 set_cursor_pos [old_topline - 1, topline].max
120 draw_line @curpos + 1
129 def page_up # overwrite
130 if topline <= @cursor_top
131 set_cursor_pos @cursor_top
133 relpos = @curpos - topline
135 set_cursor_pos topline + relpos
139 ## more complicated than one might think. three behaviors.
141 ## if we're on the last page, and it's not a full page, just move
142 ## the cursor down to the bottom and assume we can't load anything
143 ## else via the callbacks.
144 if topline > lines - buffer.content_height
145 set_cursor_pos(lines - 1)
147 ## if we're on the last page, and it's a full page, try and load
148 ## more lines via the callbacks and then shift the page down
149 elsif topline == lines - buffer.content_height
150 call_load_more_callbacks buffer.content_height
153 ## otherwise, just move down
155 relpos = @curpos - topline
157 set_cursor_pos [topline + relpos, lines - 1].min
163 set_cursor_pos @cursor_top
167 super if topline < (lines - buffer.content_height)
168 set_cursor_pos(lines - 1)
175 @status = l > 0 ? "line #{@curpos + 1} of #{l}" : ""
178 def call_load_more_callbacks size
179 @load_more_q.push size