lib/sup/modes/line_cursor_mode.rb (4970B) - raw
1 module Redwood
2
3 ## extends ScrollMode to have a line-based cursor.
4 class LineCursorMode < ScrollMode
5 register_keymap do |k|
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
11 end
12
13 attr_reader :curpos
14
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
20 while true
21 e = @load_more_q.pop
22 @load_more_callbacks.each { |c| c.call e }
23 hysteresis = $config[:load_more_threads_hysteresis] || 0.5
24 if hysteresis > 0 then
25 sleep hysteresis
26 @load_more_q.pop until @load_more_q.empty?
27 end
28 end
29 end
30
31 super opts
32 end
33
34 def spawned; call_load_more_callbacks buffer.content_height + 1; end
35
36 def cleanup
37 @load_more_thread.kill
38 super
39 end
40
41 def draw
42 super
43 set_status
44 end
45
46 protected
47
48 ## callbacks when the cursor is asked to go beyond the bottom
49 def to_load_more &b
50 @load_more_callbacks << b
51 end
52
53 def draw_line ln, opts={}
54 if ln == @curpos
55 super ln, :highlight => true, :debug => opts[:debug], :color => :text_color
56 else
57 super ln, :color => :text_color
58 end
59 end
60
61 def ensure_mode_validity
62 super
63 raise @curpos.inspect unless @curpos.is_a?(Integer)
64 c = @curpos.clamp topline, botline - 1
65 c = @cursor_top if c < @cursor_top
66 buffer.mark_dirty unless c == @curpos
67 @curpos = c
68 end
69
70 def set_cursor_pos p
71 return if @curpos == p
72 @curpos = p.clamp @cursor_top, lines
73 buffer.mark_dirty if buffer # not sure why the buffer is gone
74 set_status
75 end
76
77 ## override search behavior to be cursor-based. this is a stupid
78 ## implementation and should be made better. TODO: improve.
79 def search_goto_line line
80 page_down while line >= botline
81 page_up while line < topline
82 set_cursor_pos line
83 end
84
85 def search_start_line; @curpos end
86
87 def line_down # overwrite scrollmode
88 super
89 call_load_more_callbacks([topline + buffer.content_height - lines, 10].max) if topline + buffer.content_height > lines
90 set_cursor_pos topline if @curpos < topline
91 end
92
93 def line_up # overwrite scrollmode
94 super
95 set_cursor_pos botline - 1 if @curpos > botline - 1
96 end
97
98 def cursor_down
99 call_load_more_callbacks buffer.content_height if @curpos >= lines - [buffer.content_height/2,1].max
100 return false unless @curpos < lines - 1
101
102 if $config[:continuous_scroll] and (@curpos == botline - 3 and @curpos < lines - 3)
103 # load more lines, one at a time.
104 jump_to_line topline + 1
105 @curpos += 1
106 unless buffer.dirty?
107 draw_line @curpos - 1
108 draw_line @curpos
109 set_status
110 buffer.commit
111 end
112 elsif @curpos >= botline - 1
113 page_down
114 set_cursor_pos topline
115 else
116 @curpos += 1
117 unless buffer.dirty?
118 draw_line @curpos - 1
119 draw_line @curpos
120 set_status
121 buffer.commit
122 end
123 end
124 true
125 end
126
127 def cursor_up
128 return false unless @curpos > @cursor_top
129
130 if $config[:continuous_scroll] and (@curpos == topline + 2)
131 jump_to_line topline - 1
132 @curpos -= 1
133 unless buffer.dirty?
134 draw_line @curpos + 1
135 draw_line @curpos
136 set_status
137 buffer.commit
138 end
139 elsif @curpos == topline
140 old_topline = topline
141 page_up
142 set_cursor_pos [old_topline - 1, topline].max
143 else
144 @curpos -= 1
145 unless buffer.dirty?
146 draw_line @curpos + 1
147 draw_line @curpos
148 set_status
149 buffer.commit
150 end
151 end
152 true
153 end
154
155 def page_up # overwrite
156 if topline <= @cursor_top
157 set_cursor_pos @cursor_top
158 else
159 relpos = @curpos - topline
160 super
161 set_cursor_pos topline + relpos
162 end
163 end
164
165 def half_page_up
166 super
167 set_cursor_pos [botline, @curpos].min
168 end
169
170 def page_down
171 relpos = @curpos - topline
172 super
173 set_cursor_pos [topline + relpos, lines - 1].min
174 call_load_more_callbacks buffer.content_height if lines < topline + buffer.content_height
175 end
176
177 def half_page_down
178 super
179 set_cursor_pos [topline, @curpos].max
180 call_load_more_callbacks buffer.content_height if lines < topline + buffer.content_height
181 end
182
183 def jump_to_start
184 super
185 set_cursor_pos @cursor_top
186 end
187
188 def jump_to_end
189 super if topline < (lines - buffer.content_height)
190 set_cursor_pos(lines - 1)
191 call_load_more_callbacks buffer.content_height
192 end
193
194 private
195
196 def set_status
197 l = lines
198 @status = l > 0 ? "line #{@curpos + 1} of #{l}" : ""
199 end
200
201 def call_load_more_callbacks size
202 @load_more_q.push size if $config[:load_more_threads_when_scrolling]
203 end
204 end
205 end