From: William Morgan Date: Thu, 17 Jan 2008 01:19:00 +0000 (-0800) Subject: Merge branch 'quote-detection' into next X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=f24e54e0da3fb96f8a2e6543521a774189deadc8;hp=58d450d507300e6fe76370009298bad4ebde409c;p=sup Merge branch 'quote-detection' into next --- diff --git a/lib/sup/message.rb b/lib/sup/message.rb index ef5e3d1..853f2fc 100644 --- a/lib/sup/message.rb +++ b/lib/sup/message.rb @@ -55,6 +55,10 @@ class Message @encrypted = false @chunks = nil + ## we need to initialize this. see comments in parse_header as to + ## why. + @refs = [] + parse_header(opts[:header] || @source.load_header(@source_info)) end @@ -102,7 +106,13 @@ class Message @to = PersonManager.people_for header["to"] @cc = PersonManager.people_for header["cc"] @bcc = PersonManager.people_for header["bcc"] - @refs = (header["references"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first } + + ## before loading our full header from the source, we can actually + ## have some extra refs set by the UI. (this happens when the user + ## joins threads manually). so we will merge the current refs values + ## in here. + refs = (header["references"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first } + @refs = (@refs + refs).uniq @replytos = (header["in-reply-to"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first } @replyto = PersonManager.person_for header["reply-to"] @@ -120,6 +130,11 @@ class Message end private :parse_header + def add_ref ref + @refs << ref + @dirty = true + end + def snippet; @snippet || (chunks && @snippet); end def is_list_message?; !@list_address.nil?; end def is_draft?; @source.is_a? DraftLoader; end diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 0d90be4..dec3c1d 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -33,6 +33,7 @@ EOS k.add :toggle_tagged_all, "Tag/untag all threads", 'T' 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={} @@ -278,6 +279,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 } || diff --git a/lib/sup/tagger.rb b/lib/sup/tagger.rb index 6e4bab3..3e72463 100644 --- a/lib/sup/tagger.rb +++ b/lib/sup/tagger.rb @@ -13,7 +13,7 @@ class Tagger def drop_all_tags; @tagged.clear; end def drop_tag_for o; @tagged.delete o; end - def apply_to_tagged + def apply_to_tagged action=nil targets = @tagged.select_by_value num_tagged = targets.size if num_tagged == 0 @@ -22,10 +22,14 @@ class Tagger end noun = num_tagged == 1 ? "thread" : "threads" - c = BufferManager.ask_getch "apply to #{num_tagged} tagged #{noun}:" - return if c.nil? # user cancelled - if(action = @mode.resolve_input(c)) + unless action + c = BufferManager.ask_getch "apply to #{num_tagged} tagged #{noun}:" + return if c.nil? # user cancelled + action = @mode.resolve_input c + end + + if action tagged_sym = "multi_#{action}".intern if @mode.respond_to? tagged_sym @mode.send tagged_sym, targets diff --git a/lib/sup/thread.rb b/lib/sup/thread.rb index 83f0db7..32002c4 100644 --- a/lib/sup/thread.rb +++ b/lib/sup/thread.rb @@ -207,7 +207,7 @@ class Container def subj; find_attr :subj; end def date; find_attr :date; end - def is_reply?; subj && Message.subject_is_reply?(subj); end + def is_reply?; subj && Message.subj_is_reply?(subj); end def to_s [ "<#{id}", @@ -349,6 +349,32 @@ class ThreadSet t.each { |m, *o| add_message m } end + ## merges two threads together. both must be members of this threadset. + ## does its best, heuristically, to determine which is the parent. + def join_threads threads + return if threads.size < 2 + + containers = threads.map do |t| + c = @messages[t.first.id] + raise "not in threadset: #{t.first.id}" unless c && c.message + c + end + + ## use subject headers heuristically + parent = containers.find { |c| !c.is_reply? } + + ## no thread was rooted by a non-reply, so make a fake parent + parent ||= @messages["joining-ref-" + containers.map { |c| c.id }.join("-")] + + containers.each do |c| + next if c == parent + c.message.add_ref parent.id + link parent, c + end + + true + end + def is_relevant? m m.refs.any? { |ref_id| @messages.member? ref_id } end