]> git.cworth.org Git - sup/blobdiff - lib/sup/modes/line-cursor-mode.rb
Merge branch 'alignment-tweaks' into next
[sup] / lib / sup / modes / line-cursor-mode.rb
index f8a46e951d881c595359a42f91591794f5ae85b4..246f2b5461c69a7a53241d237fa7a647d14371fc 100644 (file)
@@ -1,5 +1,6 @@
 module Redwood
 
+## extends ScrollMode to have a line-based cursor.
 class LineCursorMode < ScrollMode
   register_keymap do |k|
     ## overwrite scrollmode binding on arrow keys for cursor movement
@@ -11,9 +12,11 @@ class LineCursorMode < ScrollMode
 
   attr_reader :curpos
 
-  def initialize cursor_top=0, opts={}
-    @cursor_top = cursor_top
-    @curpos = cursor_top
+  def initialize opts={}
+    @cursor_top = @curpos = opts.delete(:skip_top_rows) || 0
+    @load_more_callbacks = []
+    @load_more_callbacks_m = Mutex.new
+    @load_more_callbacks_active = false
     super opts
   end
 
@@ -24,6 +27,11 @@ class LineCursorMode < ScrollMode
 
 protected
 
+  ## callbacks when the cursor is asked to go beyond the bottom
+  def to_load_more &b
+    @load_more_callbacks << b
+  end
+
   def draw_line ln, opts={}
     if ln == @curpos
       super ln, :highlight => true, :debug => opts[:debug]
@@ -47,8 +55,19 @@ protected
     buffer.mark_dirty
   end
 
+  ## override search behavior to be cursor-based. this is a stupid
+  ## implementation and should be made better. TODO: improve.
+  def search_goto_line line
+    page_down while line >= botline
+    page_up while line < topline
+    set_cursor_pos line
+  end
+
+  def search_start_line; @curpos end
   def line_down # overwrite scrollmode
     super
+    call_load_more_callbacks([topline + buffer.content_height - lines, 10].max) if topline + buffer.content_height > lines
     set_cursor_pos topline if @curpos < topline
   end
 
@@ -58,10 +77,12 @@ protected
   end
 
   def cursor_down
+    call_load_more_callbacks buffer.content_height if @curpos == lines - 1
     return false unless @curpos < lines - 1
+
     if @curpos >= botline - 1
       page_down
-      set_cursor_pos [topline + 1, botline].min
+      set_cursor_pos topline
     else
       @curpos += 1
       unless buffer.dirty?
@@ -77,9 +98,9 @@ protected
   def cursor_up
     return false unless @curpos > @cursor_top
     if @curpos == topline
+      old_topline = topline
       page_up
-      set_cursor_pos [botline - 2, topline].max
-#      raise "cursor position now #@curpos, topline #{topline} botline #{botline}"
+      set_cursor_pos [old_topline - 1, topline].max
     else
       @curpos -= 1
       unless buffer.dirty?
@@ -102,9 +123,21 @@ protected
     end
   end
 
+  ## more complicated than one might think. three behaviors.
   def page_down
-    if topline >= lines - buffer.content_height
+    ## if we're on the last page, and it's not a full page, just move
+    ## the cursor down to the bottom and assume we can't load anything
+    ## else via the callbacks.
+    if topline > lines - buffer.content_height
       set_cursor_pos(lines - 1)
+
+    ## if we're on the last page, and it's a full page, try and load
+    ## more lines via the callbacks and then shift the page down
+    elsif topline == lines - buffer.content_height
+      call_load_more_callbacks buffer.content_height
+      super
+
+    ## otherwise, just move down
     else
       relpos = @curpos - topline
       super
@@ -112,7 +145,7 @@ protected
     end
   end
 
-  def jump_to_home
+  def jump_to_start
     super
     set_cursor_pos @cursor_top
   end
@@ -125,9 +158,26 @@ protected
 private
 
   def set_status
-    @status = "line #{@curpos + 1} of #{lines}"
+    l = lines
+    @status = l > 0 ? "line #{@curpos + 1} of #{l}" : ""
   end
 
+  def call_load_more_callbacks size
+    go = 
+      @load_more_callbacks_m.synchronize do
+        if @load_more_callbacks_active
+          false
+        else
+          @load_more_callbacks_active = true
+        end
+    end
+
+    return unless go
+
+    @load_more_callbacks.each { |c| c.call size }
+    @load_more_callbacks_active = false
+  end    
+
 end
 
 end