lib/sup/modes/label_list_mode.rb (3894B) - raw
1 module Redwood
2
3 class LabelListMode < LineCursorMode
4 register_keymap do |k|
5 k.add :select_label, "Search by label", :enter
6 k.add :reload, "Discard label list and reload", '@'
7 k.add :jump_to_next_new, "Jump to next new thread", :tab
8 k.add :toggle_show_unread_only, "Toggle between showing all labels and those with unread mail", 'u'
9 end
10
11 HookManager.register "label-list-filter", <<EOS
12 Filter the label list, typically to sort.
13 Variables:
14 counted: an array of counted labels.
15 Return value:
16 An array of counted labels with sort_by output structure.
17 EOS
18
19 HookManager.register "label-list-format", <<EOS
20 Create the sprintf format string for label-list-mode.
21 Variables:
22 width: the maximum label width
23 tmax: the maximum total message count
24 umax: the maximum unread message count
25 Return value:
26 A format string for sprintf
27 EOS
28
29 def initialize
30 @labels = []
31 @text = []
32 @unread_only = false
33 super
34 UpdateManager.register self
35 regen_text
36 end
37
38 def cleanup
39 UpdateManager.unregister self
40 super
41 end
42
43 def lines; @text.length end
44 def [] i; @text[i] end
45
46 def jump_to_next_new
47 n = ((curpos + 1) ... lines).find { |i| @labels[i][1] > 0 } || (0 ... curpos).find { |i| @labels[i][1] > 0 }
48 if n
49 ## jump there if necessary
50 jump_to_line n unless n >= topline && n < botline
51 set_cursor_pos n
52 else
53 BufferManager.flash "No labels messages with unread messages."
54 end
55 end
56
57 def focus
58 reload # make sure unread message counts are up-to-date
59 end
60
61 def handle_added_update sender, m
62 reload
63 end
64
65 protected
66
67 def toggle_show_unread_only
68 @unread_only = !@unread_only
69 reload
70 end
71
72 def reload
73 regen_text
74 buffer.mark_dirty if buffer
75 end
76
77 def regen_text
78 @text = []
79 labels = LabelManager.all_labels
80
81 counted = labels.map do |label|
82 string = LabelManager.string_for label
83 total = Index.num_results_for :label => label
84 unread = (label == :unread)? total : Index.num_results_for(:labels => [label, :unread])
85 [label, string, total, unread]
86 end
87
88 if HookManager.enabled? "label-list-filter"
89 counts = HookManager.run "label-list-filter", :counted => counted
90 else
91 counts = counted.sort_by { |l, s, t, u| s.downcase }
92 end
93
94 width = counts.max_of { |l, s, t, u| s.length }
95 tmax = counts.max_of { |l, s, t, u| t }
96 umax = counts.max_of { |l, s, t, u| u }
97
98 if @unread_only
99 counts.delete_if { | l, s, t, u | u == 0 }
100 end
101
102 @labels = []
103 counts.map do |label, string, total, unread|
104 ## if we've done a search and there are no messages for this label, we can delete it from the
105 ## list. BUT if it's a brand-new label, the user may not have sync'ed it to the index yet, so
106 ## don't delete it in this case.
107 ##
108 ## this is all a hack. what should happen is:
109 ## TODO make the labelmanager responsible for label counts
110 ## and then it can listen to labeled and unlabeled events, etc.
111 if total == 0 && !LabelManager::RESERVED_LABELS.include?(label) && !LabelManager.new_label?(label)
112 debug "no hits for label #{label}, deleting"
113 LabelManager.delete label
114 next
115 end
116
117 fmt = HookManager.run "label-list-format", :width => width, :tmax => tmax, :umax => umax
118 if !fmt
119 fmt = "%#{width + 1}s %5d %s, %5d unread"
120 end
121
122 @text << [[(unread == 0 ? :labellist_old_color : :labellist_new_color),
123 sprintf(fmt, string, total, total == 1 ? " message" : "messages", unread)]]
124 @labels << [label, unread]
125 yield i if block_given?
126 end.compact
127
128 BufferManager.flash "No labels with unread messages!" if counts.empty? && @unread_only
129 end
130
131 def select_label
132 label, _num_unread = @labels[curpos]
133 return unless label
134 LabelSearchResultsMode.spawn_nicely label
135 end
136 end
137
138 end