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}",
@thread_by_subj = thread_by_subj
end
- def thread_for_id mid; (c = @messages[mid]) && c.root.thread end
+ def thread_for_id mid; @messages.member?(mid) && @messages[mid].root.thread end
def contains_id? id; @messages.member?(id) && !@messages[id].empty? end
def thread_for m; thread_for_id m.id end
def contains? m; contains_id? m.id end
remove_container c
p.children << c
c.parent = p
- update_threading_for c
+
+ ## if the child was previously a top-level container, it now ain't,
+ ## so ditch our thread and kill it if necessary
+ prune_thread_of c
end
private :link
end
private :remove_container
- def update_threading_for c
- ## if the child was previously a top-level container, but now is not,
- ## ditch our thread and kill it if necessary
- if c.thread && !c.root?
- c.thread.drop c
- @threads.delete_if { |k, v| v == c.thread } if c.thread.empty?
- c.thread = nil
- end
+ def prune_thread_of c
+ return unless c.thread
+ c.thread.drop c
+ @threads.delete_if { |k, v| v == c.thread } if c.thread.empty?
+ c.thread = nil
end
- private :update_threading_for
+ private :prune_thread_of
def remove_id mid
return unless(c = @messages[mid])
remove_container c
+ prune_thread_of c
end
def remove_thread_containing_id mid
## 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
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
## that we first added a child message with a different
## subject)
if root.thread
- unless @threads[key] == root.thread
- if @threads[key]
- root.thread.empty!
- @threads[key] << root
- root.thread = @threads[key]
- else
- @threads[key] = root.thread
- end
+ if @threads.member?(key) && @threads[key] != root.thread
+ @threads.delete key
end
else
thread = @threads[key]