]> git.cworth.org Git - sup/blobdiff - lib/sup/modes/thread-index-mode.rb
Merge branch 'update-fix' into next
[sup] / lib / sup / modes / thread-index-mode.rb
index dbb3f1903beef08d6bea2bd3d97239b807a4b0ef..1606d784dbd31b350f5483a48049bdc1cdabea4a 100644 (file)
@@ -16,6 +16,7 @@ EOS
 
   register_keymap do |k|
     k.add :load_threads, "Load #{LOAD_MORE_THREAD_NUM} more threads", 'M'
+    k.add :cancel_search, "Cancel current search", :ctrl_g
     k.add :reload, "Refresh view", '@'
     k.add :toggle_archived, "Toggle archived status", 'a'
     k.add :toggle_starred, "Star or unstar all messages in thread", '*'
@@ -31,8 +32,9 @@ EOS
     k.add :forward, "Forward latest message in a thread", 'f'
     k.add :toggle_tagged, "Tag/untag selected thread", 't'
     k.add :toggle_tagged_all, "Tag/untag all threads", 'T'
-    k.add :tag_matching, "Tag/untag all threads", 'g'
+    k.add :tag_matching, "Tag matching threads", 'g'
     k.add :apply_to_tagged, "Apply next command to all tagged threads", ';'
+    k.add :join_threads, "Force tagged threads to be joined into the same thread", '#'
   end
 
   def initialize hidden_labels=[], load_thread_opts={}
@@ -49,6 +51,8 @@ EOS
     @load_thread_opts = load_thread_opts
     @hidden_labels = hidden_labels + LabelManager::HIDDEN_RESERVED_LABELS
     @date_width = DATE_WIDTH
+
+    @interrupt_search = false
     
     initialize_threads # defines @ts and @ts_mutex
     update # defines @text and @lines
@@ -75,7 +79,7 @@ EOS
   end
 
   ## open up a thread view window
-  def select t=nil
+  def select t=nil, when_done=nil
     t ||= cursor_thread or return
 
     Redwood::reporting_thread("load messages for thread-view-mode") do
@@ -88,22 +92,38 @@ EOS
           m.load_from_source! 
         end
       end
-      mode = ThreadViewMode.new t, @hidden_labels
+      mode = ThreadViewMode.new t, @hidden_labels, self
       BufferManager.spawn t.subj, mode
       BufferManager.draw_screen
-      mode.jump_to_first_open
+      mode.jump_to_first_open true
       BufferManager.draw_screen # lame TODO: make this unnecessary
       ## the first draw_screen is needed before topline and botline
       ## are set, and the second to show the cursor having moved
 
       update_text_for_line curpos
       UpdateManager.relay self, :read, t.first
+      when_done.call if when_done
     end
   end
 
   def multi_select threads
     threads.each { |t| select t }
   end
+
+  ## this is called by thread-view-modes when the user wants to view
+  ## the next thread without going to index-mode. we update the cursor
+  ## as a convenience.
+  def launch_next_thread_after thread, &b
+    l = @lines[thread] or return
+    t = @mutex.synchronize do
+      if l < @threads.length - 1
+        set_cursor_pos l + 1 # move out of mutex?
+        @threads[l + 1]
+      end
+    end or return
+
+    select t, b
+  end
   
   def handle_single_message_labeled_update sender, m
     ## no need to do anything different here; we don't differentiate 
@@ -120,18 +140,16 @@ EOS
     end
   end
 
-  def handle_read_update sender, m
+  def handle_simple_update sender, m
     t = thread_containing(m) or return
     l = @lines[t] or return
     update_text_for_line l
   end
 
-  def handle_archived_update *a; handle_read_update(*a); end
-
-  def handle_deleted_update sender, m
-    t = thread_containing(m) or return
-    hide_thread t
-    regen_text
+  %w(read unread archived starred unstarred).each do |state|
+    define_method "handle_#{state}_update" do |*a|
+      handle_simple_update(*a)
+    end
   end
 
   ## overwrite me!
@@ -142,7 +160,7 @@ EOS
     BufferManager.draw_screen
   end
 
-  def handle_deleted_update sender, m
+  def handle_single_message_deleted_update sender, m
     @ts_mutex.synchronize do
       return unless @ts.contains? m
       @ts.remove_id m.id
@@ -150,6 +168,14 @@ EOS
     update
   end
 
+  def handle_deleted_update sender, m
+    @ts_mutex.synchronize do
+      return unless @ts.contains? m
+      @ts.remove_thread_containing_id m.id
+    end
+    update
+  end
+
   def handle_undeleted_update sender, m
     add_or_unhide m
   end
@@ -157,7 +183,7 @@ EOS
   def update
     @mutex.synchronize do
       ## let's see you do THIS in python
-      @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| t.date }.reverse
+      @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| [t.date, t.first.id] }.reverse
       @size_widgets = @threads.map { |t| size_widget_for_thread t }
       @size_widget_width = @size_widgets.max_of { |w| w.length }
     end
@@ -256,6 +282,18 @@ EOS
     regen_text
   end
 
+  def join_threads
+    ## this command has no non-tagged form. as a convenience, allow this
+    ## command to be applied to tagged threads without hitting ';'.
+    @tags.apply_to_tagged :join_threads
+  end
+
+  def multi_join_threads threads
+    @ts.join_threads threads or return
+    @tags.drop_all_tags # otherwise we have tag pointers to invalid threads!
+    update
+  end
+
   def jump_to_next_new
     n = @mutex.synchronize do
       ((curpos + 1) ... lines).find { |i| @threads[i].has_label? :unread } ||
@@ -421,16 +459,19 @@ EOS
 
   ## TODO: figure out @ts_mutex in this method
   def load_n_threads n=LOAD_MORE_THREAD_NUM, opts={}
+    @interrupt_search = false
     @mbid = BufferManager.say "Searching for threads..."
+
     orig_size = @ts.size
     last_update = Time.now
     @ts.load_n_threads(@ts.size + n, opts) do |i|
       if (Time.now - last_update) >= 0.25
-        BufferManager.say "Loaded #{i.pluralize 'thread'}...", @mbid
+        BufferManager.say "Loaded #{i.pluralize 'thread'} (use ^G to cancel)...", @mbid
         update
         BufferManager.draw_screen
         last_update = Time.now
       end
+      break if @interrupt_search
     end
     @ts.threads.each { |th| th.labels.each { |l| LabelManager << l } }
 
@@ -450,13 +491,20 @@ EOS
     end
   end
 
+  def cancel_search
+    @interrupt_search = true
+  end
+
   def load_threads opts={}
     n = opts[:num] || ThreadIndexMode::LOAD_MORE_THREAD_NUM
 
     myopts = @load_thread_opts.merge({ :when_done => (lambda do |num|
       opts[:when_done].call(num) if opts[:when_done]
+
+      cancelled = @interrupt_search?" (search cancelled by user)":""
+
       if num > 0
-        BufferManager.flash "Found #{num.pluralize 'thread'}."
+        BufferManager.flash "Found #{num.pluralize 'thread'}#{cancelled}."
       else
         BufferManager.flash "No matches."
       end
@@ -478,15 +526,12 @@ EOS
 protected
 
   def add_or_unhide m
-    if @hidden_threads[m]
-      @hidden_threads.delete m
-      ## now it will re-appear when #update is called
-    else
-      Redwood::log "#{self}: adding: #{m}"
-      @ts_mutex.synchronize do
-        return unless is_relevant?(m) || @ts.is_relevant?(m)
+    @ts_mutex.synchronize do
+      if (is_relevant?(m) || @ts.is_relevant?(m)) && !@ts.contains?(m)
         @ts.load_thread_for_message m
       end
+
+      @hidden_threads.delete @ts.thread_for(m)
     end
 
     update