X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=lib%2Fsup%2Fmodes%2Fthread-view-mode.rb;h=42c62809fa8f80cb10c4730948de7fa4a208eff6;hb=fa0b5a25587356684bd45b82b172fedc729038d5;hp=a7fa964f3125deb3290fc3cf7c44b05231fc572f;hpb=f7b27c55c1be05de3d7952f6a7cf630142e0bbcd;p=sup diff --git a/lib/sup/modes/thread-view-mode.rb b/lib/sup/modes/thread-view-mode.rb index a7fa964..42c6280 100644 --- a/lib/sup/modes/thread-view-mode.rb +++ b/lib/sup/modes/thread-view-mode.rb @@ -30,6 +30,7 @@ EOS k.add :activate_chunk, "Expand/collapse or activate item", :enter k.add :expand_all_messages, "Expand/collapse all messages", 'E' k.add :edit_draft, "Edit draft", 'e' + k.add :send_draft, "Send draft", 'y' k.add :edit_labels, "Edit or add labels for a thread", 'l' k.add :expand_all_quotes, "Expand/collapse all quotes in a message", 'o' k.add :jump_to_next_open, "Jump to next open message", 'n' @@ -49,20 +50,28 @@ EOS 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_multi "(A)rchive/(d)elete/mark as (s)pam/mark as u(N)read:", '.' do |kk| + 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' kk.add :unread_and_kill, "Mark this thread as unread and kill buffer", 'N' end - k.add_multi "(A)rchive/(d)elete/mark as (s)pam/mark as u(N)read/do (n)othing:", ',' do |kk| + k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read/do (n)othing:", ',' do |kk| kk.add :archive_and_next, "Archive this thread, kill buffer, and view next", 'a' kk.add :delete_and_next, "Delete this thread, kill buffer, and view next", 'd' kk.add :spam_and_next, "Mark this thread as spam, kill buffer, and view next", 's' kk.add :unread_and_next, "Mark this thread as unread, kill buffer, and view next", 'N' kk.add :do_nothing_and_next, "Kill buffer, and view next", 'n' end + + k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read/do (n)othing:", ']' do |kk| + kk.add :archive_and_prev, "Archive this thread, kill buffer, and view previous", 'a' + kk.add :delete_and_prev, "Delete this thread, kill buffer, and view previous", 'd' + kk.add :spam_and_prev, "Mark this thread as spam, kill buffer, and view previous", 's' + kk.add :unread_and_prev, "Mark this thread as unread, kill buffer, and view previous", 'N' + kk.add :do_nothing_and_prev, "Kill buffer, and view previous", 'n' + end end ## there are a couple important instance variables we hold to format @@ -140,7 +149,7 @@ EOS def subscribe_to_list m = @message_lines[curpos] or return if m.list_subscribe && m.list_subscribe =~ // - ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [PersonManager.person_for($1)], :subj => $3 + ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [Person.from_address($1)], :subj => $3 else BufferManager.flash "Can't find List-Subscribe header for this message." end @@ -149,7 +158,7 @@ EOS def unsubscribe_from_list m = @message_lines[curpos] or return if m.list_unsubscribe && m.list_unsubscribe =~ // - ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [PersonManager.person_for($1)], :subj => $3 + ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [Person.from_address($1)], :subj => $3 else BufferManager.flash "Can't find List-Unsubscribe header for this message." end @@ -180,7 +189,7 @@ EOS def compose p = @person_lines[curpos] if p - ComposeMode.spawn_nicely :to => [p] + ComposeMode.spawn_nicely :to_default => p else ComposeMode.spawn_nicely end @@ -242,7 +251,7 @@ EOS def edit_as_new m = @message_lines[curpos] or return - mode = ComposeMode.new(:body => m.quotable_body_lines, :to => m.to, :cc => m.cc, :subj => m.subj, :bcc => m.bcc) + mode = ComposeMode.new(:body => m.quotable_body_lines, :to => m.to, :cc => m.cc, :subj => m.subj, :bcc => m.bcc, :refs => m.refs, :replytos => m.replytos) BufferManager.spawn "edit as new", mode mode.edit_message end @@ -251,7 +260,8 @@ EOS chunk = @chunk_lines[curpos] or return case chunk when Chunk::Attachment - fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", chunk.filename + default_dir = File.join(($config[:default_attachment_save_dir] || "."), chunk.filename) + fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_dir save_to_file(fn) { |f| f.print chunk.raw_content } if fn else m = @message_lines[curpos] @@ -275,6 +285,18 @@ EOS end end + def send_draft + m = @message_lines[curpos] or return + if m.is_draft? + mode = ResumeMode.new m + BufferManager.spawn "Send message", mode + BufferManager.kill_buffer self.buffer + mode.send_message + else + BufferManager.flash "Not a draft message!" + end + end + def jump_to_first_open loose_alignment=false m = @message_lines[0] or return if @layout[m].state != :closed @@ -318,6 +340,8 @@ EOS end end + IDEAL_TOP_CONTEXT = 3 # try and give 3 rows of top context + IDEAL_LEFT_CONTEXT = 4 # try and give 4 columns of left context def jump_to_message m, loose_alignment=false l = @layout[m] left = l.depth * INDENT_SPACES @@ -325,19 +349,20 @@ EOS ## jump to the top line if loose_alignment - jump_to_line [l.top - 3, 0].max # give 3 lines of top context + jump_to_line [l.top - IDEAL_TOP_CONTEXT, 0].max # give 3 lines of top context else jump_to_line l.top end ## jump to the left column - if loose_alignment - ## try and give 4 columns of left context, but not if it means that - ## the right of the message is truncated. - jump_to_col [[left - 4, rightcol - l.width - 1].min, 0].max - else - jump_to_col left - end + ideal_left = left + + if loose_alignment + -IDEAL_LEFT_CONTEXT + (l.width - buffer.content_width + IDEAL_LEFT_CONTEXT + 1).clamp(0, IDEAL_LEFT_CONTEXT) + else + 0 + end + + jump_to_col [ideal_left, 0].max ## either way, move the cursor to the first line set_cursor_pos l.top @@ -380,6 +405,12 @@ EOS def unread_and_next; unread_and_then :next end def do_nothing_and_next; do_nothing_and_then :next end + def archive_and_prev; archive_and_then :prev end + def spam_and_prev; spam_and_then :prev end + def delete_and_prev; delete_and_then :prev end + def unread_and_prev; unread_and_then :prev end + def do_nothing_and_prev; do_nothing_and_then :prev end + def archive_and_then op dispatch op do @thread.remove_label :inbox @@ -416,15 +447,18 @@ EOS return if @dying @dying = true + l = lambda do + yield if block_given? + BufferManager.kill_buffer_safely buffer + end + case op when :next - @index_mode.launch_next_thread_after(@thread) do - @thread.save Index if block_given? && yield - BufferManager.kill_buffer_safely buffer - end + @index_mode.launch_next_thread_after @thread, &l + when :prev + @index_mode.launch_prev_thread_before @thread, &l when :kill - @thread.save Index if yield - BufferManager.kill_buffer_safely buffer + l.call else raise ArgumentError, "unknown thread dispatch operation #{op.inspect}" end @@ -506,7 +540,7 @@ private (0 ... text.length).each do |i| @chunk_lines[@text.length + i] = m @message_lines[@text.length + i] = m - lw = text[i].flatten.select { |x| x.is_a? String }.map { |x| x.length }.sum + lw = text[i].flatten.select { |x| x.is_a? String }.map { |x| x.display_length }.sum end @text += text @@ -527,7 +561,7 @@ private (0 ... text.length).each do |i| @chunk_lines[@text.length + i] = c @message_lines[@text.length + i] = m - lw = text[i].flatten.select { |x| x.is_a? String }.map { |x| x.length }.sum - (depth * INDENT_SPACES) + lw = text[i].flatten.select { |x| x.is_a? String }.map { |x| x.display_length }.sum - (depth * INDENT_SPACES) l.width = lw if lw > l.width end @text += text @@ -542,29 +576,29 @@ private open_widget = [color, (state == :closed ? "+ " : "- ")] new_widget = [color, (m.has_label?(:unread) ? "N" : " ")] - starred_widget = - if m.has_label?(:starred) - [star_color, "* "] + starred_widget = if m.has_label?(:starred) + [star_color, "*"] else - [color, " "] + [color, " "] end + attach_widget = [color, (m.has_label?(:attachment) ? "@" : " ")] case state when :open @person_lines[start] = m.from - [[prefix_widget, open_widget, new_widget, starred_widget, + [[prefix_widget, open_widget, new_widget, attach_widget, starred_widget, [color, "#{m.from ? m.from.mediumname : '?'} to #{m.recipients.map { |l| l.shortname }.join(', ')} #{m.date.to_nice_s} (#{m.date.to_nice_distance_s})"]]] when :closed @person_lines[start] = m.from - [[prefix_widget, open_widget, new_widget, starred_widget, + [[prefix_widget, open_widget, new_widget, attach_widget, starred_widget, [color, "#{m.from ? m.from.mediumname : '?'}, #{m.date.to_nice_s} (#{m.date.to_nice_distance_s}) #{m.snippet}"]]] when :detailed @person_lines[start] = m.from - from_line = [[prefix_widget, open_widget, new_widget, starred_widget, + from_line = [[prefix_widget, open_widget, new_widget, attach_widget, starred_widget, [color, "From: #{m.from ? format_person(m.from) : '?'}"]]] addressee_lines = [] @@ -601,7 +635,7 @@ private def format_person_list prefix, people ptext = people.map { |p| format_person p } - pad = " " * prefix.length + pad = " " * prefix.display_length [prefix + ptext.first + (ptext.length > 1 ? "," : "")] + ptext[1 .. -1].map_with_index do |e, i| pad + e + (i == ptext.length - 1 ? "" : ",") @@ -622,7 +656,7 @@ private [[[:missing_message_color, "#{prefix}"]]] when Message message_patina_lines(chunk, state, start, parent, prefix, color, star_color) + - (chunk.is_draft? ? [[[:draft_notification_color, prefix + " >>> This message is a draft. To edit, hit 'e'. <<<"]]] : []) + (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