k.add :quit, "Quit Redwood", 'q'
k.add :help, "Show help", 'H', '?'
k.add :roll_buffers, "Switch to next buffer", 'b'
- k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
+# k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
k.add :kill_buffer, "Kill the current buffer", 'x'
- k.add :list_buffers, "List all buffers", 'A'
+ k.add :list_buffers, "List all buffers", 'B'
k.add :list_contacts, "List contacts", 'C'
k.add :redraw, "Redraw screen", :ctrl_l
k.add :search, "Search messages", '/'
-for next release
+for 0.0.7
----------------
-make 'a' archive in thread-view-mode
+de-archived messages should be auto-added to inbox
+
+for 0.0.8
+---------
message attachments
warnings: top-posting, attachments
maildir
+
+for 0.0.9
+---------
undo
+use Net::SMTP
+gmail
future
------
-maybe: de-archived messages should be auto-added to inbox
swappable keymappings
bugfix: when returning from a shelling out, ncurses is crazy
bugfix: miscellaneous weirdnesses in buffer line editing
wide character support
batch deletion
support for message-content modules such as ruby-talk:XXXXX detection
-use Net::SMTP
forward attachments
CREATE attachments
tab completion on labels, contacts
maybe: rangefilter on the initial inbox to only consider the most recent 1000 messages
select all, starred, to me, etc
annotations on messages
-gmail
pop
be able to mark individual messages as spam in thread-view-mode
toggle wrapping
done
----
+x make 'A' archive in thread-view-mode
x remove stupid percent_done source methods (still useful; made it optional)
x don't quit while writing thread index state to disk or with unsaved drafts/messages
x bugfix: deleted threads are showing up (i don't see this any more)
@source.each do |thisoffset, theselabels|
m = Message.new :source => @source, :source_info => thisoffset, :labels => theselabels
Index.add_message m
- UpdateManager.relay :add, m
+ UpdateManager.relay self, :add, m
my_message = m if thisoffset == offset
end
raise ArgumentError, "not a draft: source id #{entry[:source_id].inspect}, should be #{DraftManager.source_id.inspect} for #{mid.inspect} / docno #{docid}" unless entry[:source_id].to_i == DraftManager.source_id
Index.drop_entry docid
File.delete @source.fn_for_offset(entry[:source_info])
- UpdateManager.relay :delete, mid
+ UpdateManager.relay self, :delete, mid
end
end
def killable?; false; end
def archive
- remove_label_and_hide_thread cursor_thread, :inbox
+ cursor_thread.remove_label :inbox
+ hide_thread cursor_thread
regen_text
end
regen_text
end
+ def handle_archived_update sender, t
+ hide_thread t if contains_thread? t
+ end
+
+ def handle_unarchived_update sender, t
+ ## XXX todo: fill me in
+ end
+
def status
super + " #{Index.size} messages in index"
end
def lines; @text.length; end
def [] i; @text[i]; end
+ def contains_thread? t; !@lines[t].nil?; end
def reload
drop_all_threads
t ||= @threads[curpos]
## this isn't working entirely. TODO:figure out why
- t = t.clone # required so that messages added later on don't completely
+ # t = t.clone # required so that messages added later on don't completely
# screw everything up
## TODO: don't regen text completely
threads.each { |t| select t }
end
- def handle_starred_update m
+ def handle_starred_update sender, m
return unless(t = @ts.thread_for m)
update_text_for_line @lines[t]
BufferManager.draw_screen
end
- def handle_read_update m
- return unless(t = @ts.thread_for m)
+ def handle_read_update sender, t
+ return unless @lines[t]
update_text_for_line @lines[t]
BufferManager.draw_screen
end
+ def handle_archived_update *a; handle_read_update *a; end
+
## overwrite me!
def is_relevant? m; false; end
- def handle_add_update m
+ def handle_add_update sender, m
if is_relevant?(m) || @ts.is_relevant?(m)
@ts.load_thread_for_message m
update
end
end
- def handle_delete_update mid
+ def handle_delete_update sender, mid
if @ts.contains_id? mid
@ts.remove mid
update
end
end
- ## i always hate people who name things like this...
- def actually_toggle_starred t=@threads[curpos]
+ def actually_toggle_starred t
if t.has_label? :starred # if ANY message has a star
t.remove_label :starred # remove from all
else
end
def toggle_starred
- actually_toggle_starred
+ t = @threads[curpos] or return
+ actually_toggle_starred t
update_text_for_line curpos
cursor_down
end
regen_text
end
+ def actually_toggle_archived t
+ if t.has_label? :inbox
+ t.remove_label :inbox
+ UpdateManager.relay self, :unarchived, t
+ else
+ t.add_label :inbox
+ UpdateManager.relay self, :archived, t
+ end
+ end
+
def toggle_archived
t = @threads[curpos] or return
- t.toggle_label :inbox
+ actually_toggle_archived t
update_text_for_line curpos
- cursor_down
end
def multi_toggle_archived threads
- threads.each { |t| t.toggle_label :inbox }
+ threads.each { |t| actually_toggle_archived t }
regen_text
end
update
end
- def remove_label_and_hide_thread t, label
- t.remove_label label
- hide_thread t
- end
-
def hide_thread t
raise "already hidden" if @hidden_threads[t]
@hidden_threads[t] = true
k.add :edit_as_new, "Edit message as new", 'D'
k.add :save_to_disk, "Save message/attachment to disk", 's'
k.add :search, "Search for messages from particular people", 'S'
+ k.add :archive_and_kill, "Archive thread and kill buffer", 'A'
end
## there are a couple important instance variables we hold to lay
## TODO: don't recalculate EVERYTHING just to add a stupid little
## star to the display
update
- UpdateManager.relay :starred, m
+ UpdateManager.relay self, :starred, m
end
def toggle_expanded
end
end
- ## kinda slow for large threads. TODO: fasterify
def cleanup
- BufferManager.say "Marking messages as read..." do
- @thread.each do |m, d, p|
- if m && m.has_label?(:unread)
- m.remove_label :unread
- UpdateManager.relay :read, m
- end
- end
- end
+ @thread.remove_label :unread
+ UpdateManager.relay self, :read, @thread
@layout = @text = nil
end
+ def archive_and_kill
+ @thread.remove_label :inbox
+ UpdateManager.relay self, :archived, @thread
+ BufferManager.kill_buffer_safely buffer
+ end
+
private
def initial_state_for m
Index.update_message m, docid, entry
else
Index.add_message m
- UpdateManager.relay :add, m
+ UpdateManager.relay self, :add, m
end
rescue MessageFormatError, SourceError => e
Redwood::log "ignoring erroneous message at #{source}##{offset}: #{e.message}"
@source.each do |offset, labels|
m = Message.new :source => @source, :source_info => offset, :labels => labels
Index.add_message m
- UpdateManager.relay :add, m
+ UpdateManager.relay self, :add, m
end
end
end
def authors; map { |m, *o| m.from if m }.compact.uniq; end
def apply_label t; each { |m, *o| m && m.add_label(t) }; end
- def remove_label t
- each { |m, *o| m && m.remove_label(t) }
- end
+ def remove_label t; each { |m, *o| m && m.remove_label(t) }; end
def toggle_label label
if has_label? label
def register o; @targets[o] = true; end
def unregister o; @targets.delete o; end
- def relay type, *args
+ def relay sender, type, *args
meth = "handle_#{type}_update".intern
- @targets.keys.each { |o| o.send meth, *args if o.respond_to? meth }
+ @targets.keys.each { |o| o.send meth, sender, *args unless o == sender if o.respond_to? meth }
end
end