class Redwood::ThreadIndexMode
subclasses should implement:
-
is_relevant?
Constants
- AUTHOR_LIMIT
- DATE_WIDTH
- LOAD_MORE_THREAD_NUM
- MIN_FROM_WIDTH
Public Class Methods
# File lib/sup/modes/thread_index_mode.rb, line 60 def initialize hidden_labels=[], load_thread_opts={} super() @mutex = Mutex.new # covers the following variables: @threads = [] @hidden_threads = {} @size_widget_width = nil @size_widgets = [] @date_widget_width = nil @date_widgets = [] @tags = Tagger.new self ## these guys, and @text and @lines, are not covered @load_thread = nil @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 UpdateManager.register self @save_thread_mutex = Mutex.new @last_load_more_size = nil to_load_more do |size| next if @last_load_more_size == 0 load_threads :num => size, :when_done => lambda { |num| @last_load_more_size = num } end end
Public Instance Methods
# File lib/sup/modes/thread_index_mode.rb, line 96 def [] i; @text[i]; end
returns an undo lambda
# File lib/sup/modes/thread_index_mode.rb, line 330 def actually_toggle_archived t thread = t pos = curpos if t.has_label? :inbox t.remove_label :inbox UpdateManager.relay self, :archived, t.first lambda do thread.apply_label :inbox update_text_for_line pos UpdateManager.relay self,:unarchived, thread.first end else t.apply_label :inbox UpdateManager.relay self, :unarchived, t.first lambda do thread.remove_label :inbox update_text_for_line pos UpdateManager.relay self, :unarchived, thread.first end end end
returns an undo lambda
# File lib/sup/modes/thread_index_mode.rb, line 377 def actually_toggle_deleted t if t.has_label? :deleted t.remove_label :deleted add_or_unhide t.first UpdateManager.relay self, :undeleted, t.first lambda do t.apply_label :deleted hide_thread t UpdateManager.relay self, :deleted, t.first end else t.apply_label :deleted hide_thread t UpdateManager.relay self, :deleted, t.first lambda do t.remove_label :deleted add_or_unhide t.first UpdateManager.relay self, :undeleted, t.first end end end
returns an undo lambda
# File lib/sup/modes/thread_index_mode.rb, line 353 def actually_toggle_spammed t thread = t if t.has_label? :spam t.remove_label :spam add_or_unhide t.first UpdateManager.relay self, :unspammed, t.first lambda do thread.apply_label :spam self.hide_thread thread UpdateManager.relay self,:spammed, thread.first end else t.apply_label :spam hide_thread t UpdateManager.relay self, :spammed, t.first lambda do thread.remove_label :spam add_or_unhide thread.first UpdateManager.relay self,:unspammed, thread.first end end end
returns an undo lambda
# File lib/sup/modes/thread_index_mode.rb, line 292 def actually_toggle_starred t if t.has_label? :starred # if ANY message has a star t.remove_label :starred # remove from all UpdateManager.relay self, :unstarred, t.first lambda do t.first.add_label :starred UpdateManager.relay self, :starred, t.first regen_text end else t.first.add_label :starred # add only to first UpdateManager.relay self, :starred, t.first lambda do t.remove_label :starred UpdateManager.relay self, :unstarred, t.first regen_text end end end
# File lib/sup/modes/thread_index_mode.rb, line 580 def apply_to_tagged; @tags.apply_to_tagged; end
# File lib/sup/modes/thread_index_mode.rb, line 714 def cancel_search @interrupt_search = true end
# File lib/sup/modes/thread_index_mode.rb, line 541 def cleanup UpdateManager.unregister self if @load_thread @load_thread.kill BufferManager.clear @mbid if @mbid sleep 0.1 # TODO: necessary? BufferManager.erase_flash end dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } } fail "dirty threads remain" unless dirty_threads.empty? super end
# File lib/sup/modes/thread_index_mode.rb, line 97 def contains_thread? t; @threads.include?(t) end
# File lib/sup/modes/thread_index_mode.rb, line 582 def edit_labels thread = cursor_thread or return speciall = (@hidden_labels + LabelManager::RESERVED_LABELS).uniq old_labels = thread.labels pos = curpos keepl, modifyl = thread.labels.partition { |t| speciall.member? t } user_labels = BufferManager.ask_for_labels :label, "Labels for thread: ", modifyl.sort_by {|x| x.to_s}, @hidden_labels return unless user_labels thread.labels = Set.new(keepl) + user_labels user_labels.each { |l| LabelManager << l } update_text_for_line curpos UndoManager.register "labeling thread" do thread.labels = old_labels update_text_for_line pos UpdateManager.relay self, :labeled, thread.first Index.save_thread thread end UpdateManager.relay self, :labeled, thread.first Index.save_thread thread end
# File lib/sup/modes/thread_index_mode.rb, line 280 def edit_message return unless(t = cursor_thread) message, *_ = t.find { |m, *o| m.has_label? :draft } if message mode = ResumeMode.new message BufferManager.spawn "Edit message", mode else BufferManager.flash "Not a draft message!" end end
# File lib/sup/modes/thread_index_mode.rb, line 502 def flush_index @flush_id = BufferManager.say "Flushing index..." Index.save_index BufferManager.clear @flush_id end
# File lib/sup/modes/thread_index_mode.rb, line 659 def forward t = cursor_thread or return m = t.latest_message return if m.nil? # probably won't happen m.load_from_source! ForwardMode.spawn_nicely :message => m end
# File lib/sup/modes/thread_index_mode.rb, line 199 def handle_added_update sender, m add_or_unhide m BufferManager.draw_screen end
# File lib/sup/modes/thread_index_mode.rb, line 232 def handle_deleted_update sender, m t = @ts_mutex.synchronize { @ts.thread_for m } return unless t hide_thread t update end
# File lib/sup/modes/thread_index_mode.rb, line 239 def handle_killed_update sender, m t = @ts_mutex.synchronize { @ts.thread_for m } return unless t hide_thread t update end
# File lib/sup/modes/thread_index_mode.rb, line 175 def handle_labeled_update sender, m if(t = thread_containing(m)) l = @lines[t] or return update_text_for_line l elsif is_relevant?(m) add_or_unhide m end end
# File lib/sup/modes/thread_index_mode.rb, line 215 def handle_location_deleted_update sender, m t = thread_containing(m) delete_thread t if t and t.first.id == m.id @ts_mutex.synchronize do @ts.delete_message m if t end update end
# File lib/sup/modes/thread_index_mode.rb, line 184 def handle_simple_update sender, m t = thread_containing(m) or return l = @lines[t] or return update_text_for_line l end
# File lib/sup/modes/thread_index_mode.rb, line 224 def handle_single_message_deleted_update sender, m @ts_mutex.synchronize do return unless @ts.contains? m @ts.remove_id m.id end update end
# File lib/sup/modes/thread_index_mode.rb, line 169 def handle_single_message_labeled_update sender, m ## no need to do anything different here; we don't differentiate ## messages from their containing threads handle_labeled_update sender, m end
# File lib/sup/modes/thread_index_mode.rb, line 246 def handle_spammed_update sender, m t = @ts_mutex.synchronize { @ts.thread_for m } return unless t hide_thread t update end
# File lib/sup/modes/thread_index_mode.rb, line 253 def handle_undeleted_update sender, m add_or_unhide m end
# File lib/sup/modes/thread_index_mode.rb, line 257 def handle_unkilled_update sender, m add_or_unhide m end
# File lib/sup/modes/thread_index_mode.rb, line 204 def handle_updated_update sender, m t = thread_containing(m) or return l = @lines[t] or return @ts_mutex.synchronize do @ts.delete_message m @ts.add_message m end Index.save_thread t, sync_back = false update_text_for_line l end
overwrite me!
# File lib/sup/modes/thread_index_mode.rb, line 197 def is_relevant? m; false; end
# File lib/sup/modes/thread_index_mode.rb, line 435 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
# File lib/sup/modes/thread_index_mode.rb, line 448 def jump_to_next_new n = @mutex.synchronize do ((curpos + 1) ... lines).find { |i| @threads[i].has_label? :unread } || (0 ... curpos).find { |i| @threads[i].has_label? :unread } end if n ## jump there if necessary jump_to_line n unless n >= topline && n < botline set_cursor_pos n else BufferManager.flash "No new messages." end end
# File lib/sup/modes/thread_index_mode.rb, line 497 def kill t = cursor_thread or return multi_kill [t] end
# File lib/sup/modes/thread_index_mode.rb, line 152 def launch_another_thread thread, direction, &b l = @lines[thread] or return target_l = l + direction t = @mutex.synchronize do if target_l >= 0 && target_l < @threads.length @threads[target_l] end end if t # there's a next thread set_cursor_pos target_l # move out of mutex? select t, b elsif b # no next thread. call the block anyways b.call end end
these two methods are called by thread-view-modes when the user wants to view the previous/next thread without going back to index-mode. we update the cursor as a convenience.
# File lib/sup/modes/thread_index_mode.rb, line 144 def launch_next_thread_after thread, &b launch_another_thread thread, 1, &b end
# File lib/sup/modes/thread_index_mode.rb, line 148 def launch_prev_thread_before thread, &b launch_another_thread thread, -1, &b end
# File lib/sup/modes/thread_index_mode.rb, line 95 def lines; @text.length; end
# File lib/sup/modes/thread_index_mode.rb, line 718 def load_all_threads load_threads :num => -1 end
TODO: figure out @ts_mutex in this method
# File lib/sup/modes/thread_index_mode.rb, line 677 def load_n_threads n=LOAD_MORE_THREAD_NUM, opts={} @interrupt_search = false @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_to_load, opts) do |i| if (Time.now - last_update) >= 0.25 BufferManager.say "Loaded #{i.pluralize 'thread'}...", @mbid update BufferManager.draw_screen last_update = Time.now end ::Thread.pass break if @interrupt_search end @ts.threads.each { |th| th.labels.each { |l| LabelManager << l } } update BufferManager.clear @mbid @mbid = nil BufferManager.draw_screen @ts.size - orig_size end
# File lib/sup/modes/thread_index_mode.rb, line 667 def load_n_threads_background n=LOAD_MORE_THREAD_NUM, opts={} return if @load_thread # todo: wrap in mutex @load_thread = Redwood::reporting_thread("load threads for thread-index-mode") do num = load_n_threads n, opts opts[:when_done].call(num) if opts[:when_done] @load_thread = nil end end
# File lib/sup/modes/thread_index_mode.rb, line 722 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] if num > 0 BufferManager.flash "Found #{num.pluralize 'thread'}." else BufferManager.flash "No matches." end end)}) if opts[:background] || opts[:background].nil? load_n_threads_background n, myopts else load_n_threads n, myopts end end
# File lib/sup/modes/thread_index_mode.rb, line 609 def multi_edit_labels threads user_labels = BufferManager.ask_for_labels :labels, "Add/remove labels (use -label to remove): ", [], @hidden_labels return unless user_labels user_labels.map! { |l| (l.to_s =~ /^-/)? [l.to_s.gsub(/^-?/, '').to_sym, true] : [l, false] } hl = user_labels.select { |(l,_)| @hidden_labels.member? l } unless hl.empty? BufferManager.flash "'#{hl}' is a reserved label!" return end old_labels = threads.map { |t| t.labels.dup } threads.each do |t| user_labels.each do |(l, to_remove)| if to_remove t.remove_label l else t.apply_label l LabelManager << l end end UpdateManager.relay self, :labeled, t.first end regen_text UndoManager.register "labeling #{threads.size.pluralize 'thread'}" do threads.zip(old_labels).map do |t, old_labels| t.labels = old_labels UpdateManager.relay self, :labeled, t.first Index.save_thread t end regen_text end threads.each { |t| Index.save_thread t } end
# File lib/sup/modes/thread_index_mode.rb, line 441 def multi_join_threads threads @ts.join_threads threads or return threads.each { |t| Index.save_thread t } @tags.drop_all_tags # otherwise we have tag pointers to invalid threads! update end
m-m-m-m-MULTI-KILL
# File lib/sup/modes/thread_index_mode.rb, line 509 def multi_kill threads UndoManager.register "killing/unkilling #{threads.size.pluralize 'threads'}" do threads.each do |t| if t.toggle_label :killed add_or_unhide t.first else hide_thread t end end.each do |t| UpdateManager.relay self, :labeled, t.first Index.save_thread t end regen_text end threads.each do |t| if t.toggle_label :killed hide_thread t else add_or_unhide t.first end end.each do |t| # send 'labeled'... this might be more specific UpdateManager.relay self, :labeled, t.first Index.save_thread t end killed, unkilled = threads.partition { |t| t.has_label? :killed }.map(&:size) BufferManager.flash "#{killed.pluralize 'thread'} killed, #{unkilled} unkilled" regen_text end
# File lib/sup/modes/thread_index_mode.rb, line 766 def multi_read_and_archive threads old_labels = threads.map { |t| t.labels.dup } threads.each do |t| t.remove_label :unread t.remove_label :inbox hide_thread t end regen_text UndoManager.register "reading and archiving #{threads.size.pluralize 'thread'}" do threads.zip(old_labels).each do |t, l| t.labels = l add_or_unhide t.first Index.save_thread t end regen_text end threads.each { |t| Index.save_thread t } end
# File lib/sup/modes/thread_index_mode.rb, line 137 def multi_select threads threads.each { |t| select t } end
# File lib/sup/modes/thread_index_mode.rb, line 408 def multi_toggle_archived threads undos = threads.map { |t| actually_toggle_archived t } UndoManager.register "deleting/undeleting #{threads.size.pluralize 'thread'}", undos, lambda { regen_text }, lambda { threads.each { |t| Index.save_thread t } } regen_text threads.each { |t| Index.save_thread t } end
see comment for #multi_toggle_spam
# File lib/sup/modes/thread_index_mode.rb, line 489 def multi_toggle_deleted threads undos = threads.map { |t| actually_toggle_deleted t } UndoManager.register "deleting/undeleting #{threads.size.pluralize 'thread'}", undos, lambda { regen_text }, lambda { threads.each { |t| Index.save_thread t } } regen_text threads.each { |t| Index.save_thread t } end
# File lib/sup/modes/thread_index_mode.rb, line 424 def multi_toggle_new threads threads.each { |t| t.toggle_label :unread } regen_text threads.each { |t| Index.save_thread t } end
both spam and deleted have the curious characteristic that you always want to hide the thread after either applying or removing that label. in all thread-index-views except for label-search-results-mode, when you mark a message as spam or deleted, you want it to disappear immediately; in LSRM, you only see deleted or spam emails, and when you undelete or unspam them you also want them to disappear immediately.
# File lib/sup/modes/thread_index_mode.rb, line 474 def multi_toggle_spam threads undos = threads.map { |t| actually_toggle_spammed t } threads.each { |t| HookManager.run("mark-as-spam", :thread => t) } UndoManager.register "marking/unmarking #{threads.size.pluralize 'thread'} as spam", undos, lambda { regen_text }, lambda { threads.each { |t| Index.save_thread t } } regen_text threads.each { |t| Index.save_thread t } end
# File lib/sup/modes/thread_index_mode.rb, line 321 def multi_toggle_starred threads UndoManager.register "toggling #{threads.size.pluralize 'thread'} starred status", threads.map { |t| actually_toggle_starred t }, lambda { threads.each { |t| Index.save_thread t } } regen_text threads.each { |t| Index.save_thread t } end
# File lib/sup/modes/thread_index_mode.rb, line 430 def multi_toggle_tagged threads @mutex.synchronize { @tags.drop_all_tags } regen_text end
# File lib/sup/modes/thread_index_mode.rb, line 747 def read_and_archive return unless cursor_thread thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread was_unread = thread.labels.member? :unread UndoManager.register "reading and archiving thread" do thread.apply_label :inbox thread.apply_label :unread if was_unread add_or_unhide thread.first Index.save_thread thread end cursor_thread.remove_label :unread cursor_thread.remove_label :inbox hide_thread cursor_thread regen_text Index.save_thread thread end
# File lib/sup/modes/thread_index_mode.rb, line 99 def reload drop_all_threads UndoManager.clear BufferManager.draw_screen load_threads :num => buffer.content_height end
# File lib/sup/modes/thread_index_mode.rb, line 648 def reply type_arg=nil t = cursor_thread or return m = t.latest_message return if m.nil? # probably won't happen m.load_from_source! mode = ReplyMode.new m, type_arg BufferManager.spawn "Reply to #{m.subj}", mode end
# File lib/sup/modes/thread_index_mode.rb, line 657 def reply_all; reply :all; end
# File lib/sup/modes/thread_index_mode.rb, line 788 def resize rows, cols regen_text super end
open up a thread view window
# File lib/sup/modes/thread_index_mode.rb, line 107 def select t=nil, when_done=nil t ||= cursor_thread or return Redwood::reporting_thread("load messages for thread-view-mode") do num = t.size message = "Loading #{num.pluralize 'message body'}..." BufferManager.say(message) do |sid| t.each_with_index do |(m, *_), i| next unless m BufferManager.say "#{message} (#{i}/#{num})", sid if t.size > 1 m.load_from_source! end end mode = ThreadViewMode.new t, @hidden_labels, self BufferManager.spawn t.subj, mode BufferManager.draw_screen mode.jump_to_first_open if $config[:jump_to_open_message] 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 t.remove_label :unread Index.save_thread t update_text_for_line curpos UpdateManager.relay self, :read, t.first when_done.call if when_done end end
# File lib/sup/modes/thread_index_mode.rb, line 706 def status if (l = lines) == 0 "line 0 of 0" else "line #{curpos + 1} of #{l}" end end
# File lib/sup/modes/thread_index_mode.rb, line 567 def tag_matching query = BufferManager.ask :search, "tag threads matching (regex): " return if query.nil? || query.empty? query = begin /#{query}/i rescue RegexpError => e BufferManager.flash "error interpreting '#{query}': #{e.message}" return end @mutex.synchronize { @threads.each { |t| @tags.tag t if thread_matches?(t, query) } } regen_text end
# File lib/sup/modes/thread_index_mode.rb, line 399 def toggle_archived t = cursor_thread or return undo = actually_toggle_archived t UndoManager.register "deleting/undeleting thread #{t.first.id}", undo, lambda { update_text_for_line curpos }, lambda { Index.save_thread t } update_text_for_line curpos Index.save_thread t end
# File lib/sup/modes/thread_index_mode.rb, line 483 def toggle_deleted t = cursor_thread or return multi_toggle_deleted [t] end
# File lib/sup/modes/thread_index_mode.rb, line 416 def toggle_new t = cursor_thread or return t.toggle_label :unread update_text_for_line curpos cursor_down Index.save_thread t end
# File lib/sup/modes/thread_index_mode.rb, line 462 def toggle_spam t = cursor_thread or return multi_toggle_spam [t] end
# File lib/sup/modes/thread_index_mode.rb, line 312 def toggle_starred t = cursor_thread or return undo = actually_toggle_starred t UndoManager.register "toggling thread starred status", undo, lambda { Index.save_thread t } update_text_for_line curpos cursor_down Index.save_thread t end
# File lib/sup/modes/thread_index_mode.rb, line 555 def toggle_tagged t = cursor_thread or return @mutex.synchronize { @tags.toggle_tag_for t } update_text_for_line curpos cursor_down end
# File lib/sup/modes/thread_index_mode.rb, line 562 def toggle_tagged_all @mutex.synchronize { @threads.each { |t| @tags.toggle_tag_for t } } regen_text end
# File lib/sup/modes/thread_index_mode.rb, line 261 def undo UndoManager.undo end
# File lib/sup/modes/thread_index_mode.rb, line 94 def unsaved?; dirty? end
# File lib/sup/modes/thread_index_mode.rb, line 265 def update old_cursor_thread = cursor_thread @mutex.synchronize do ## let's see you do THIS in python @threads = @ts.threads.select { |t| !@hidden_threads.member?(t) }.select(&:has_message?).sort_by(&:sort_key) @size_widgets = @threads.map { |t| size_widget_for_thread t } @size_widget_width = @size_widgets.max_of { |w| w.display_length } @date_widgets = @threads.map { |t| date_widget_for_thread t } @date_widget_width = @date_widgets.max_of { |w| w.display_length } end set_cursor_pos @threads.index(old_cursor_thread)||curpos regen_text end
Protected Instance Methods
# File lib/sup/modes/thread_index_mode.rb, line 795 def add_or_unhide m @ts_mutex.synchronize do if (is_relevant?(m) || @ts.is_relevant?(m)) && !@ts.contains?(m) @ts.load_thread_for_message m, @load_thread_opts end @hidden_threads.delete @ts.thread_for(m) end update end
# File lib/sup/modes/thread_index_mode.rb, line 823 def cursor_thread; @mutex.synchronize { @threads[curpos] }; end
# File lib/sup/modes/thread_index_mode.rb, line 819 def date_widget_for_thread t HookManager.run("index-mode-date-widget", :thread => t) || default_date_widget_for(t) end
# File lib/sup/modes/thread_index_mode.rb, line 831 def delete_thread t @mutex.synchronize do i = @threads.index(t) or return @threads.delete_at i @size_widgets.delete_at i @date_widgets.delete_at i @tags.drop_tag_for t end end
# File lib/sup/modes/thread_index_mode.rb, line 1011 def dirty?; @mutex.synchronize { (@hidden_threads.keys + @threads).any? { |t| t.dirty? } } end
# File lib/sup/modes/thread_index_mode.rb, line 825 def drop_all_threads @tags.drop_all_tags initialize_threads update end
# File lib/sup/modes/thread_index_mode.rb, line 841 def hide_thread t @mutex.synchronize do i = @threads.index(t) or return raise "already hidden" if @hidden_threads[t] @hidden_threads[t] = true @threads.delete_at i @size_widgets.delete_at i @date_widgets.delete_at i @tags.drop_tag_for t end end
# File lib/sup/modes/thread_index_mode.rb, line 882 def regen_text threads = @mutex.synchronize { @threads } @text = threads.map_with_index { |t, i| text_for_thread_at i } @lines = threads.map_with_index { |t, i| [t, i] }.to_h buffer.mark_dirty if buffer end
# File lib/sup/modes/thread_index_mode.rb, line 815 def size_widget_for_thread t HookManager.run("index-mode-size-widget", :thread => t) || default_size_widget_for(t) end
# File lib/sup/modes/thread_index_mode.rb, line 931 def text_for_thread_at line t, size_widget, date_widget = @mutex.synchronize do [@threads[line], @size_widgets[line], @date_widgets[line]] end starred = t.has_label? :starred ## format the from column cur_width = 0 ann = author_names_and_newness_for_thread t, AUTHOR_LIMIT from = [] ann.each_with_index do |(name, newness), i| break if cur_width >= from_width last = i == ann.length - 1 abbrev = if cur_width + name.display_length > from_width name.slice_by_display_length(from_width - cur_width - 1) + "." elsif cur_width + name.display_length == from_width name.slice_by_display_length(from_width - cur_width) else if last name.slice_by_display_length(from_width - cur_width) else name.slice_by_display_length(from_width - cur_width - 1) + "," end end cur_width += abbrev.display_length if last && from_width > cur_width abbrev += " " * (from_width - cur_width) end from << [(newness ? :index_new_color : (starred ? :index_starred_color : :index_old_color)), abbrev] end is_me = AccountManager.method(:is_account?) directly_participated = t.direct_participants.any?(&is_me) participated = directly_participated || t.participants.any?(&is_me) subj_color = if t.has_label?(:draft) :index_draft_color elsif t.has_label?(:unread) :index_new_color elsif starred :index_starred_color elsif Colormap.sym_is_defined(:index_subject_color) :index_subject_color else :index_old_color end size_padding = @size_widget_width - size_widget.display_length size_widget_text = sprintf "%#{size_padding}s%s", "", size_widget date_padding = @date_widget_width - date_widget.display_length date_widget_text = sprintf "%#{date_padding}s%s", "", date_widget [ [:tagged_color, @tags.tagged?(t) ? ">" : " "], [:date_color, date_widget_text], [:starred_color, (starred ? "*" : " ")], ] + from + [ [:size_widget_color, size_widget_text], [:with_attachment_color , t.labels.member?(:attachment) ? "@" : " "], [:to_me_color, directly_participated ? ">" : (participated ? '+' : " ")], ] + (t.labels - @hidden_labels).sort_by {|x| x.to_s}.map { |label| [Colormap.sym_is_defined("label_#{label}_color".to_sym) || :label_color, "#{label} "] } + [ [subj_color, t.subj + (t.subj.empty? ? "" : " ")], [:snippet_color, t.snippet], ] end
# File lib/sup/modes/thread_index_mode.rb, line 807 def thread_containing m; @ts_mutex.synchronize { @ts.thread_for m } end
used to tag threads by query. this can be made a lot more sophisticated, but for right now we'll do the obvious this.
# File lib/sup/modes/thread_index_mode.rb, line 811 def thread_matches? t, query t.subj =~ query || t.snippet =~ query || t.participants.any? { |x| x.longname =~ query } end
# File lib/sup/modes/thread_index_mode.rb, line 853 def update_text_for_line l return unless l # not sure why this happens, but it does, occasionally need_update = false @mutex.synchronize do # and certainly not sure why this happens.. # # probably a race condition between thread modification and updating # going on. return if @threads[l].empty? @size_widgets[l] = size_widget_for_thread @threads[l] @date_widgets[l] = date_widget_for_thread @threads[l] ## if a widget size has increased, we need to redraw everyone need_update = (@size_widgets[l].size > @size_widget_width) or (@date_widgets[l].size > @date_widget_width) end if need_update update else @text[l] = text_for_thread_at l buffer.mark_dirty if buffer end end
Private Instance Methods
# File lib/sup/modes/thread_index_mode.rb, line 1024 def default_date_widget_for t t.date.getlocal.to_nice_s end
# File lib/sup/modes/thread_index_mode.rb, line 1015 def default_size_widget_for t case t.size when 1 "" else "(#{t.size})" end end
# File lib/sup/modes/thread_index_mode.rb, line 1028 def from_width [(buffer.content_width.to_f * 0.2).to_i, MIN_FROM_WIDTH].max if buffer else MIN_FROM_WIDTH # not sure why the buffer is gone end
# File lib/sup/modes/thread_index_mode.rb, line 1032 def initialize_threads @ts = ThreadSet.new Index.instance, $config[:thread_by_subject] @ts_mutex = Mutex.new @hidden_threads = {} end