Subject: [sup-talk] [PATCH] (Double/guarded) keypress to show all threads

From: [email-masked] (Marcus Williams)
Date: Fri, 11 Jan 2008 17:20:58 +0000

Hi -

This patch adds a multi key combination to expand the thread index
view to all available threads. Note that this could return _a lot_ of
threads, which is why I've used a double keypress '!!' as a guard to
accidental usage. Its useful in conjunction with the tag all and apply
to all commands though.

So you may search for some term, by default you will get a limited
number of threads back. Hitting ! twice allows you to expand the
search to all available results.

It will be slow if you've got a large number of search results.

Marcus

-------------- next part --------------
A non-text attachment was scrubbed...
Name: load-all-threads
Type: application/octet-stream
Size: 2164 bytes
Desc: not available
Url : http://rubyforge.org/pipermail/sup-talk/attachments/20080111/65f63fe8/attachment-0001.obj

---

From: [email-masked] (William Morgan)
Date: Sat, 12 Jan 2008 21:30:16 -0800

> accidental usage. Its useful in conjunction with the tag all and apply

This does make me a little nervous. Is the use case always that you want
to apply a command to all threads for a given search? If so, I wonder if
it would be better to explicitly model that, without the intermediate
process of loading all the threads.

If we're going to have a potentially long-running activity like this
available from the UI, then I'd prefer to do it in a manner that gives
the user an indication of how long until completion, the ability to
abort, etc.

How does gmail handle this type of thing? Or is everything so fast with
gmail that it doesn't matter?

-- 
William <wmorgan-sup at masanjin.net>

---

From: [email-masked] (Nicolas Pouillard)
Date: Sun, 13 Jan 2008 16:57:26 +0100

> gmail that it doesn't matter?

By  default  it  occurs  only  seen  threads  (25,50,100 messages depending on
configuration),  but  you  have  also  a  check box to apply on all the search
results.

Then  that's  indeed  so fast that there's no need for a progress bar. However
that's  fast  because  operations  are  chosen  to  apply  fast (add or remove
labels, basically).

-- 
Nicolas Pouillard aka Ertai

---

From: [email-masked] (Marcus Williams)
Date: Sun, 13 Jan 2008 18:16:12 +0000

> process of loading all the threads.

I dont use it when I know the search will generate a lot of threads :)
What I'm working on is getting it to stop searching if the user
presses a key (so you get a progress of 'Found ??? threads (press ESC
to stop)' or something, but no luck yet :(

I guess it doesnt actually have to return the threads a la gmail
(gmail lets you select all threads in search without actually
displaying them but its _fast_). I tried doing this but since the
majority of searches I do end up being with labels I think you
actually need to thread them in order to be of any use (because not
all labels are on every message in thread).

I can resubmit once I figure out the interrupt.

Marcus

---

From: [email-masked] (William Morgan)
Date: Sun, 13 Jan 2008 17:06:37 -0800

> to stop)' or something, but no luck yet :(

Excellent, that would be great. I don't think it will be too hard: in
ThreadIndexMode#load_n_threads, in the block that's passed to
@ts.load_n_threads, just check to see if a boolean instance variable is
true, and break if so (and reset it). That block is called after each
thread is loaded, so the ThreadSet will still be in a consistent state.
Then add a keypress to set that flag to true, if @load_thread is true.

> displaying them but its _fast_).

The general slowness of this type of operation in Sup is a real
problem, IMO. I think we can go a long way by caching threading
information, though of course that's at the expense of disk space.

---

From: [email-masked] (Marcus Williams)
Date: Mon, 14 Jan 2008 10:54:26 +0000

> information, though of course that's at the expense of disk space.

Disk space is cheap :) So if this gets us a speed up I think its worth
it. If people are worried about that sort of thing it could be a
configurable option. 

Marcus

---

From: [email-masked] (William Morgan)
Date: Mon, 14 Jan 2008 20:49:35 -0800

> it. If people are worried about that sort of thing it could be a

I agree. I don't think it will be terribly hard to do, either, but I
should probably do some real profiling before just diving in.

---

From: [email-masked] (Marcus Williams)
Date: Tue, 15 Jan 2008 12:29:57 +0000

This adds the ability to extend your search to display all threads
(which may take a _long_ time) instead of the standard maximum (usually
screen height). It is accessed via a multi-key action !C in thread index
modes. To cancel the search the user can press another multi-key action
!S
---
 lib/sup/modes/thread-index-mode.rb |   40 +++++++++++++++++++++++++++++++----
 lib/sup/thread.rb                  |    2 +-
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb
index 0d90be4..f86a5a4 100644
--- a/lib/sup/modes/thread-index-mode.rb
+++ b/lib/sup/modes/thread-index-mode.rb
@@ -16,6 +16,10 @@ EOS
 
   register_keymap do |k|
     k.add :load_threads, "Load #{LOAD_MORE_THREAD_NUM} more threads", 'M'
+    k.add_multi "Search all threads - (C)onfirm, or (S)top current search :", '!' do |kk|
+      kk.add :load_all_threads, "Load all threads (may list a _lot_ of threads)", 'C'
+      kk.add :break_search, "Stop current search", 'S'
+    end
     k.add :reload, "Refresh view", '@'
     k.add :toggle_archived, "Toggle archived status", 'a'
     k.add :toggle_starred, "Star or unstar all messages in thread", '*'
@@ -49,6 +53,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
@@ -444,15 +450,20 @@ EOS
   ## TODO: figure out @ts_mutex in this method
   def load_n_threads n=LOAD_MORE_THREAD_NUM, opts={}
     @mbid = BufferManager.say "Searching for threads..."
+
+    ts_to_load = n
+    ts_to_load = ts_to_load + @ts.size unless n == -1 # -1 means all threads
+
     orig_size = @ts.size
     last_update = Time.now
-    @ts.load_n_threads(@ts.size + n, opts) do |i|
+    @ts.load_n_threads(ts_to_load, opts) do |i|
       if (Time.now - last_update) >= 0.25
-        BufferManager.say "Loaded #{i.pluralize 'thread'}...", @mbid
+        BufferManager.say "Loaded #{i.pluralize 'thread'} (use !S to cancel search)...", @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 } }
 
@@ -472,13 +483,32 @@ EOS
     end
   end
 
-  def load_threads opts={}
-    n = opts[:num] || ThreadIndexMode::LOAD_MORE_THREAD_NUM
+  def break_search
+    @interrupt_search = true
+  end
 
+  def load_all_threads
+    load_threads :num => -1
+  end
+
+  def load_threads opts={}
+    if opts[:num].nil?
+      n = ThreadIndexMode::LOAD_MORE_THREAD_NUM
+    else
+      n = opts[:num]
+    end
+        
     myopts = @load_thread_opts.merge({ :when_done => (lambda do |num|
       opts[:when_done].call(num) if opts[:when_done]
+      
+      cancelled = ""
+      if @interrupt_search
+        cancelled = " (search cancelled by user)" 
+        @interrupt_search = false
+      end
+
       if num > 0
-        BufferManager.flash "Found #{num.pluralize 'thread'}."
+        BufferManager.flash "Found #{num.pluralize 'thread'}#{cancelled}."
       else
         BufferManager.flash "No matches."
       end
diff --git a/lib/sup/thread.rb b/lib/sup/thread.rb
index 83f0db7..5b0a300 100644
--- a/lib/sup/thread.rb
+++ b/lib/sup/thread.rb
@@ -324,7 +324,7 @@ class ThreadSet
   ## load in (at most) num number of threads from the index
   def load_n_threads num, opts={}
     @index.each_id_by_date opts do |mid, builder|
-      break if size >= num
+      break if size >= num unless num == -1
       next if contains_id? mid
 
       m = builder.call
-- 
1.5.3.7

---

From: [email-masked] (William Morgan)
Date: Tue, 15 Jan 2008 20:30:07 -0800

Reformatted excerpts from Marcus Williams's message of 2008-01-15:
> (which may take a _long_ time) instead of the standard maximum
> (usually screen height). It is accessed via a multi-key action !C in
> thread index modes. To cancel the search the user can press another
> multi-key action !S.

I think you should split this into two patches, the first of which adds
the ability to stop any current thread-loading operation, and the second
of which gives you the "load everything now" button. I'd like to
evaluate each one independently.

I think I'd like the stop loading button to be ^G, which is the general
cancel command everywhere in Sup. The load everything now button can be
a scary multi-key sequence like "!!".

Comments welcome.

---

From: [email-masked] (Marcus Williams)
Date: Wed, 16 Jan 2008 10:47:39 +0000

> evaluate each one independently.

At the moment isnt the only thread-loading operation the
load_n_threads method in thread-index-view? All the possibly long
running operations that run threads that I can think of end up going
through this as far as I can see.

So do you want a patch for interrupting the load threads method, and
then a patch to add the potentially long running load_all_threads?

> a scary multi-key sequence like "!!".

Ok, easily done - I didnt use ^G originally because I thought you
couldnt overload a key action in a mode and I though ^G was added
elsewhere.

Marcus

---

From: [email-masked] (William Morgan)
Date: Wed, 16 Jan 2008 13:09:36 -0800

> through this as far as I can see.

Yes.

> then a patch to add the potentially long running load_all_threads?

Precisely.

> couldnt overload a key action in a mode and I though ^G was added

In general that is more or less true, but ^G is only caught by the
top-level event handler (which we override every time we define a
mode-specific keyboard command), and by the text entry stuff, which does
its own keyboard handling routine. So I think you should be fine.