]> git.notmuchmail.org Git - sup/blob - lib/sup/modes/scroll-mode.rb
31ccef0a17728144f40bbc7b6198252a75a6fd1f
[sup] / lib / sup / modes / scroll-mode.rb
1 module Redwood
2
3 class ScrollMode < Mode
4   ## we define topline and botline as the top and bottom lines of any
5   ## content in the currentview.
6   
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.)
12
13   attr_reader :status, :topline, :botline, :leftcol
14
15   COL_JUMP = 2
16
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_home, "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   end
28
29   def initialize opts={}
30     @topline, @botline, @leftcol = 0, 0, 0
31     @slip_rows = opts[:slip_rows] || 0 # when we pgup/pgdown,
32                                        # how many lines do we keep?
33     @twiddles = opts.member?(:twiddles) ? opts[:twiddles] : true
34     super()
35   end
36
37   def rightcol; @leftcol + buffer.content_width; end
38
39   def draw
40     ensure_mode_validity
41     (@topline ... @botline).each { |ln| draw_line ln }
42     ((@botline - @topline) ... buffer.content_height).each do |ln|
43       if @twiddles
44         buffer.write ln, 0, "~", :color => :twiddle_color
45       else
46         buffer.write ln, 0, ""
47       end
48     end
49     @status = "lines #{@topline + 1}:#{@botline}/#{lines}"
50   end
51
52   def col_left
53     return unless @leftcol > 0
54     @leftcol -= COL_JUMP
55     buffer.mark_dirty
56   end
57
58   def col_right
59     @leftcol += COL_JUMP
60     buffer.mark_dirty
61   end
62
63   def jump_to_col col
64     buffer.mark_dirty unless @leftcol == col
65     @leftcol = col
66   end
67
68   def jump_to_left; jump_to_col 0; end
69
70   ## set top line to l
71   def jump_to_line l
72     l = l.clamp 0, lines - 1
73     return if @topline == l
74     @topline = l
75     @botline = [l + buffer.content_height, lines].min
76     buffer.mark_dirty
77   end
78
79   def line_down; jump_to_line @topline + 1; end
80   def line_up;  jump_to_line @topline - 1; end
81   def page_down; jump_to_line @topline + buffer.content_height - @slip_rows; end
82   def page_up; jump_to_line @topline - buffer.content_height + @slip_rows; end
83   def jump_to_home; jump_to_line 0; end
84   def jump_to_end; jump_to_line lines - buffer.content_height; end
85
86
87   def ensure_mode_validity
88     @topline = @topline.clamp 0, lines - 1
89     @topline = 0 if @topline < 0 # empty 
90     @botline = [@topline + buffer.content_height, lines].min
91   end
92
93   def resize *a
94     super(*a)
95     ensure_mode_validity
96   end
97
98 protected
99
100   def draw_line ln, opts={}
101     case(s = self[ln])
102     when String
103       buffer.write ln - @topline, 0, s[@leftcol .. -1],
104                    :highlight => opts[:highlight]
105     when Array
106       xpos = 0
107
108       ## speed test
109       # str = s.map { |color, text| text }.join
110       # buffer.write ln - @topline, 0, str, :color => :none, :highlight => opts[:highlight]
111       # return
112
113       s.each do |color, text|
114         raise "nil text for color '#{color}'" if text.nil? # good for debugging
115         if xpos + text.length < @leftcol
116           buffer.write ln - @topline, 0, "", :color => color,
117                        :highlight => opts[:highlight]
118           xpos += text.length
119         elsif xpos < @leftcol
120           ## partial
121           buffer.write ln - @topline, 0, text[(@leftcol - xpos) .. -1],
122                        :color => color,
123                        :highlight => opts[:highlight]
124           xpos += text.length
125         else
126           buffer.write ln - @topline, xpos - @leftcol, text,
127                        :color => color, :highlight => opts[:highlight]
128           xpos += text.length
129         end
130
131       end
132     end
133   end
134 end
135
136 end