lib/sup/modes/thread-index-mode.rb in sup-0.9.1 vs lib/sup/modes/thread-index-mode.rb in sup-0.10
- old
+ new
@@ -35,11 +35,11 @@
k.add :edit_labels, "Edit or add labels for a thread", 'l'
k.add :edit_message, "Edit message (drafts only)", 'e'
k.add :toggle_spam, "Mark/unmark thread as spam", 'S'
k.add :toggle_deleted, "Delete/undelete thread", 'd'
k.add :kill, "Kill thread (never to be seen in inbox again)", '&'
- k.add :save, "Save changes now", '$'
+ k.add :flush_index, "Flush all changes now", '$'
k.add :jump_to_next_new, "Jump to next new thread", :tab
k.add :reply, "Reply to latest message in a thread", 'r'
k.add :reply_all, "Reply to all participants of the latest message in a thread", 'G'
k.add :forward, "Forward latest message in a thread", 'f'
k.add :toggle_tagged, "Tag/untag selected thread", 't'
@@ -64,11 +64,11 @@
@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
@@ -218,16 +218,18 @@
def undo
UndoManager.undo
end
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[t] }.sort_by { |t| [t.date, t.first.id] }.reverse
@size_widgets = @threads.map { |t| size_widget_for_thread t }
@size_widget_width = @size_widgets.max_of { |w| w.display_length }
end
+ set_cursor_pos @threads.index(old_cursor_thread)||curpos
regen_text
end
def edit_message
@@ -264,19 +266,22 @@
end
def toggle_starred
t = cursor_thread or return
undo = actually_toggle_starred t
- UndoManager.register "toggling thread starred status", undo
+ UndoManager.register "toggling thread starred status", undo, lambda { Index.save_thread t }
update_text_for_line curpos
cursor_down
+ Index.save_thread t
end
def multi_toggle_starred threads
UndoManager.register "toggling #{threads.size.pluralize 'thread'} starred status",
- threads.map { |t| actually_toggle_starred t }
+ 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
## returns an undo lambda
def actually_toggle_archived t
thread = t
@@ -348,30 +353,36 @@
end
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 }
+ 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
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 }
+ 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
def toggle_new
t = cursor_thread or return
t.toggle_label :unread
update_text_for_line curpos
cursor_down
+ Index.save_thread t
end
def multi_toggle_new threads
threads.each { |t| t.toggle_label :unread }
regen_text
+ threads.each { |t| Index.save_thread t }
end
def multi_toggle_tagged threads
@mutex.synchronize { @tags.drop_all_tags }
regen_text
@@ -383,10 +394,11 @@
@tags.apply_to_tagged :join_threads
end
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
def jump_to_next_new
@@ -397,18 +409,17 @@
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"
+ BufferManager.flash "No new messages."
end
end
def toggle_spam
t = cursor_thread or return
multi_toggle_spam [t]
- HookManager.run("mark-as-spam", :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
@@ -416,13 +427,15 @@
## 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.
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 }
+ undos, lambda { regen_text }, lambda { threads.each { |t| Index.save_thread t } }
regen_text
+ threads.each { |t| Index.save_thread t }
end
def toggle_deleted
t = cursor_thread or return
multi_toggle_deleted [t]
@@ -430,25 +443,33 @@
## see comment for multi_toggle_spam
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 }
+ undos, lambda { regen_text }, lambda { threads.each { |t| Index.save_thread t } }
regen_text
+ threads.each { |t| Index.save_thread t }
end
def kill
t = cursor_thread or return
multi_kill [t]
end
+ def flush_index
+ @flush_id = BufferManager.say "Flushing index..."
+ Index.save_index
+ BufferManager.clear @flush_id
+ end
+
## m-m-m-m-MULTI-KILL
def multi_kill threads
UndoManager.register "killing #{threads.size.pluralize 'thread'}" do
threads.each do |t|
t.remove_label :killed
add_or_unhide t.first
+ Index.save_thread t
end
regen_text
end
threads.each do |t|
@@ -456,45 +477,24 @@
hide_thread t
end
regen_text
BufferManager.flash "#{threads.size.pluralize 'thread'} killed."
+ threads.each { |t| Index.save_thread t }
end
- def save background=true
- if background
- Redwood::reporting_thread("saving thread") { actually_save }
- else
- actually_save
- end
- end
-
- def actually_save
- @save_thread_mutex.synchronize do
- BufferManager.say("Saving contacts...") { ContactManager.instance.save }
- dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } }
- next if dirty_threads.empty?
-
- BufferManager.say("Saving threads...") do |say_id|
- dirty_threads.each_with_index do |t, i|
- BufferManager.say "Saving modified thread #{i + 1} of #{dirty_threads.length}...", say_id
- t.save_state Index
- end
- end
- end
- end
-
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
- save false
+ dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } }
+ fail "dirty threads remain" unless dirty_threads.empty?
super
end
def toggle_tagged
t = cursor_thread or return
@@ -541,13 +541,15 @@
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
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
@@ -577,13 +579,16 @@
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
def reply type_arg=nil
t = cursor_thread or return
m = t.latest_message
@@ -757,34 +762,40 @@
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
-
+
def authors; map { |m, *o| m.from if m }.compact.uniq; end
+ ## preserve author order from the thread
def author_names_and_newness_for_thread t, limit=nil
new = {}
- authors = Set.new
- t.each do |m, *o|
- next unless m
- break if limit and authors.size >= limit
+ seen = {}
+ authors = t.map do |m, *o|
+ next unless m && m.from
+ new[m.from] ||= m.has_label?(:unread)
+ next if seen[m.from]
+ seen[m.from] = true
+ m.from
+ end.compact
- name =
- if AccountManager.is_account?(m.from)
- "me"
- elsif t.authors.size == 1
- m.from.mediumname
- else
- m.from.shortname
- end
+ result = []
+ authors.each do |a|
+ break if limit && result.size >= limit
+ name = if AccountManager.is_account?(a)
+ "me"
+ elsif t.authors.size == 1
+ a.mediumname
+ else
+ a.shortname
+ end
- new[name] ||= m.has_label?(:unread)
- authors << name
+ result << [name, new[a]]
end
- authors.to_a.map { |a| [a, new[a]] }
+ result
end
AUTHOR_LIMIT = 5
def text_for_thread_at line
t, size_widget = @mutex.synchronize { [@threads[line], @size_widgets[line]] }
@@ -841,10 +852,10 @@
size_widget_text = sprintf "%#{ @size_widget_width}s", size_widget
[
[:tagged_color, @tags.tagged?(t) ? ">" : " "],
- [:none, sprintf("%#{@date_width}s", date)],
+ [:date_color, sprintf("%#{@date_width}s", date)],
(starred ? [:starred_color, "*"] : [:none, " "]),
] +
from +
[
[subj_color, size_widget_text],