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_callbacks_m = Mutex.new
19 @load_more_callbacks_active = false
30 ## callbacks when the cursor is asked to go beyond the bottom
32 @load_more_callbacks << b
35 def draw_line ln, opts={}
37 super ln, :highlight => true, :debug => opts[:debug]
43 def ensure_mode_validity
45 raise @curpos.inspect unless @curpos.is_a?(Integer)
46 c = @curpos.clamp topline, botline - 1
47 c = @cursor_top if c < @cursor_top
48 buffer.mark_dirty unless c == @curpos
53 return if @curpos == p
54 @curpos = p.clamp @cursor_top, lines
58 ## override search behavior to be cursor-based. this is a stupid
59 ## implementation and should be made better. TODO: improve.
60 def search_goto_line line
61 page_down while line >= botline
62 page_up while line < topline
66 def search_start_line; @curpos end
68 def line_down # overwrite scrollmode
70 call_load_more_callbacks([topline + buffer.content_height - lines, 10].max) if topline + buffer.content_height > lines
71 set_cursor_pos topline if @curpos < topline
74 def line_up # overwrite scrollmode
76 set_cursor_pos botline - 1 if @curpos > botline - 1
80 call_load_more_callbacks buffer.content_height if @curpos == lines - 1
81 return false unless @curpos < lines - 1
83 if @curpos >= botline - 1
85 set_cursor_pos topline
99 return false unless @curpos > @cursor_top
100 if @curpos == topline
101 old_topline = topline
103 set_cursor_pos [old_topline - 1, topline].max
107 draw_line @curpos + 1
116 def page_up # overwrite
117 if topline <= @cursor_top
118 set_cursor_pos @cursor_top
120 relpos = @curpos - topline
122 set_cursor_pos topline + relpos
126 ## more complicated than one might think. three behaviors.
128 ## if we're on the last page, and it's not a full page, just move
129 ## the cursor down to the bottom and assume we can't load anything
130 ## else via the callbacks.
131 if topline > lines - buffer.content_height
132 set_cursor_pos(lines - 1)
134 ## if we're on the last page, and it's a full page, try and load
135 ## more lines via the callbacks and then shift the page down
136 elsif topline == lines - buffer.content_height
137 call_load_more_callbacks buffer.content_height
140 ## otherwise, just move down
142 relpos = @curpos - topline
144 set_cursor_pos [topline + relpos, lines - 1].min
150 set_cursor_pos @cursor_top
154 super if topline < (lines - buffer.content_height)
155 set_cursor_pos(lines - 1)
162 @status = l > 0 ? "line #{@curpos + 1} of #{l}" : ""
165 def call_load_more_callbacks size
167 @load_more_callbacks_m.synchronize do
168 if @load_more_callbacks_active
171 @load_more_callbacks_active = true
177 @load_more_callbacks.each { |c| c.call size }
178 @load_more_callbacks_active = false