lib/sup/modes/thread-view-mode.rb in sup-0.9.1 vs lib/sup/modes/thread-view-mode.rb in sup-0.10

- old
+ new

@@ -56,18 +56,20 @@ k.add :forward, "Forward a message or attachment", 'f' k.add :bounce, "Bounce message to other recipient(s)", '!' k.add :alias, "Edit alias/nickname for a person", 'i' k.add :edit_as_new, "Edit message as new", 'D' k.add :save_to_disk, "Save message/attachment to disk", 's' + k.add :save_all_to_disk, "Save all attachments to disk", 'A' k.add :search, "Search for messages from particular people", 'S' k.add :compose, "Compose message to person", 'm' k.add :subscribe_to_list, "Subscribe to/unsubscribe from mailing list", "(" k.add :unsubscribe_from_list, "Subscribe to/unsubscribe from mailing list", ")" k.add :pipe_message, "Pipe message or attachment to a shell command", '|' k.add :archive_and_next, "Archive this thread, kill buffer, and view next", 'a' k.add :delete_and_next, "Delete this thread, kill buffer, and view next", 'd' + k.add :toggle_wrap, "Toggle wrapping of text", 'w' k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read:", '.' do |kk| kk.add :archive_and_kill, "Archive this thread and kill buffer", 'a' kk.add :delete_and_kill, "Delete this thread and kill buffer", 'd' kk.add :spam_and_kill, "Mark this thread as spam and kill buffer", 's' @@ -125,15 +127,23 @@ latest_date = m.date latest = m end end + @wrap = true + @layout[latest].state = :open if @layout[latest].state == :closed @layout[earliest].state = :detailed if earliest.has_label?(:unread) || @thread.size == 1 @thread.remove_label :unread + Index.save_thread @thread + end + + def toggle_wrap + @wrap = !@wrap regen_text + buffer.mark_dirty if buffer end def draw_line ln, opts={} if ln == curpos super ln, :highlight => true @@ -142,21 +152,29 @@ end end def lines; @text.length; end def [] i; @text[i]; end + ## a little hacky---since regen_text can depend on buffer features like the + ## content_width, we don't call it in the constructor, and instead call it + ## here, which is set before we're responsible for drawing ourself. + def buffer= b + super + regen_text + end + def show_header m = @message_lines[curpos] or return BufferManager.spawn_unless_exists("Full header for #{m.id}") do - TextMode.new m.raw_header + TextMode.new m.raw_header.ascii end end def show_message m = @message_lines[curpos] or return BufferManager.spawn_unless_exists("Raw message for #{m.id}") do - TextMode.new m.raw_message + TextMode.new m.raw_message.ascii end end def toggle_detailed_header m = @message_lines[curpos] or return @@ -256,12 +274,14 @@ return unless new_labels @thread.labels = Set.new(reserved_labels) + new_labels new_labels.each { |l| LabelManager << l } update UpdateManager.relay self, :labeled, @thread.first + Index.save_thread @thread UndoManager.register "labeling thread" do @thread.labels = old_labels + Index.save_thread @thread UpdateManager.relay self, :labeled, @thread.first end end def toggle_starred @@ -282,10 +302,11 @@ end ## TODO: don't recalculate EVERYTHING just to add a stupid little ## star to the display update UpdateManager.relay self, :single_message_labeled, m + Index.save_thread @thread end ## called when someone presses enter when the cursor is highlighting ## a chunk. for expandable chunks (including messages) we toggle ## open/closed state; for viewable chunks (like attachments) we @@ -324,12 +345,14 @@ def save_to_disk chunk = @chunk_lines[curpos] or return case chunk when Chunk::Attachment - default_dir = File.join(($config[:default_attachment_save_dir] || "."), chunk.filename) - fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_dir + default_dir = $config[:default_attachment_save_dir] + default_dir = ENV["HOME"] if default_dir.nil? || default_dir.empty? + default_fn = File.expand_path File.join(default_dir, chunk.filename) + fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_fn save_to_file(fn) { |f| f.print chunk.raw_content } if fn else m = @message_lines[curpos] fn = BufferManager.ask_for_filename :filename, "Save message to file: " return unless fn @@ -337,10 +360,36 @@ m.each_raw_message_line { |l| f.print l } end end end + def save_all_to_disk + m = @message_lines[curpos] or return + default_dir = ($config[:default_attachment_save_dir] || ".") + folder = BufferManager.ask_for_filename :filename, "Save all attachments to folder: ", default_dir, true + return unless folder + + num = 0 + num_errors = 0 + m.chunks.each do |chunk| + next unless chunk.is_a?(Chunk::Attachment) + fn = File.join(folder, chunk.filename) + num_errors += 1 unless save_to_file(fn, false) { |f| f.print chunk.raw_content } + num += 1 + end + + if num == 0 + BufferManager.flash "Didn't find any attachments!" + else + if num_errors == 0 + BufferManager.flash "Wrote #{num.pluralize 'attachment'} to #{folder}." + else + BufferManager.flash "Wrote #{(num - num_errors).pluralize 'attachment'} to #{folder}; couldn't write #{num_errors} of them (see log)." + end + end + end + def edit_draft m = @message_lines[curpos] or return if m.is_draft? mode = ResumeMode.new m BufferManager.spawn "Edit message", mode @@ -474,43 +523,50 @@ def archive_and_then op dispatch op do @thread.remove_label :inbox UpdateManager.relay self, :archived, @thread.first + Index.save_thread @thread UndoManager.register "archiving 1 thread" do @thread.apply_label :inbox + Index.save_thread @thread UpdateManager.relay self, :unarchived, @thread.first end end end def spam_and_then op dispatch op do @thread.apply_label :spam UpdateManager.relay self, :spammed, @thread.first + Index.save_thread @thread UndoManager.register "marking 1 thread as spam" do @thread.remove_label :spam + Index.save_thread @thread UpdateManager.relay self, :unspammed, @thread.first end end end def delete_and_then op dispatch op do @thread.apply_label :deleted UpdateManager.relay self, :deleted, @thread.first + Index.save_thread @thread UndoManager.register "deleting 1 thread" do @thread.remove_label :deleted + Index.save_thread @thread UpdateManager.relay self, :undeleted, @thread.first end end end def unread_and_then op dispatch op do @thread.apply_label :unread UpdateManager.relay self, :unread, @thread.first + Index.save_thread @thread end end def do_nothing_and_then op dispatch op @@ -555,11 +611,11 @@ message.each_raw_message_line { |l| stream.print l } end end if output - BufferManager.spawn "Output of '#{command}'", TextMode.new(output) + BufferManager.spawn "Output of '#{command}'", TextMode.new(output.ascii) else BufferManager.flash "'#{command}' done!" end end @@ -732,11 +788,16 @@ (chunk.is_draft? ? [[[:draft_notification_color, prefix + " >>> This message is a draft. Hit 'e' to edit, 'y' to send. <<<"]]] : []) else raise "Bad chunk: #{chunk.inspect}" unless chunk.respond_to?(:inlineable?) ## debugging if chunk.inlineable? - chunk.lines.map { |line| [[chunk.color, "#{prefix}#{line}"]] } + lines = chunk.lines + if @wrap + width = buffer.content_width + lines = lines.map { |l| l.chomp.wrap width }.flatten + end + lines.map { |line| [[chunk.color, "#{prefix}#{line}"]] } elsif chunk.expandable? case state when :closed [[[chunk.patina_color, "#{prefix}+ #{chunk.patina_text}"]]] when :open @@ -752,10 +813,10 @@ BufferManager.flash "viewing #{chunk.content_type} attachment..." success = chunk.view! BufferManager.erase_flash BufferManager.completely_redraw_screen unless success - BufferManager.spawn "Attachment: #{chunk.filename}", TextMode.new(chunk.to_s, chunk.filename) + BufferManager.spawn "Attachment: #{chunk.filename}", TextMode.new(chunk.to_s.ascii, chunk.filename) BufferManager.flash "Couldn't execute view command, viewing as text." end end end