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'
k.add :jump_to_prev_open, "Jump to previous open message", 'p'
+ k.add :align_current_message, "Align current message in buffer", 'z'
k.add :toggle_starred, "Star or unstar message", '*'
- k.add :toggle_new, "Toggle new/read status of message", 'N'
+ k.add :toggle_new, "Toggle unread/read status of message", 'N'
# k.add :collapse_non_new_messages, "Collapse all but unread messages", 'N'
k.add :reply, "Reply to a message", 'r'
k.add :forward, "Forward a message or attachment", 'f'
k.add :unsubscribe_from_list, "Subscribe to/unsubscribe from mailing list", ")"
k.add :pipe_message, "Pipe message or attachment to a shell command", '|'
- ## dispatch-and-kill commands
- k.add_multi "(A)rchive/(d)elete/mark as (s)pam/do (n)othing:", ',' do |kk|
- kk.add :archive_and_kill, "Archive this thread and view next", 'a'
- kk.add :delete_and_kill, "Delete this thread and view next", 'd'
- kk.add :spam_and_kill, "Mark this thread as spam and view next", 's'
- kk.add :skip_and_kill, "Skip this thread and view next", 'n'
+ 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|
+ 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
end
@thread = thread
@hidden_labels = hidden_labels
- ## used for dispatch-and-kill
+ ## used for dispatch-and-next
@index_mode = index_mode
@dying = false
end
end
- def jump_to_first_open
+ def jump_to_first_open loose_alignment=false
m = @message_lines[0] or return
if @layout[m].state != :closed
- jump_to_message m
+ jump_to_message m, loose_alignment
else
- jump_to_next_open
+ jump_to_next_open loose_alignment
end
end
- def jump_to_next_open
+ def jump_to_next_open loose_alignment=false
return continue_search_in_buffer if in_search? # hack: allow 'n' to apply to both operations
- m = @message_lines[curpos] or return
+ m = (curpos ... @message_lines.length).argfind { |i| @message_lines[i] }
+ return unless m
while nextm = @layout[m].next
break if @layout[nextm].state != :closed
m = nextm
end
- jump_to_message nextm if nextm
+ jump_to_message nextm, loose_alignment if nextm
end
- def jump_to_prev_open
+ def align_current_message
m = @message_lines[curpos] or return
+ jump_to_message m
+ end
+
+ def jump_to_prev_open loose_alignment=false
+ m = (0 .. curpos).to_a.reverse.argfind { |i| @message_lines[i] } # bah, .to_a
+ return unless m
## jump to the top of the current message if we're in the body;
## otherwise, to the previous message
break if @layout[prevm].state != :closed
m = prevm
end
- jump_to_message prevm if prevm
+ jump_to_message prevm, loose_alignment if prevm
else
- jump_to_message m
+ jump_to_message m, loose_alignment
end
end
- def jump_to_message m
+ def jump_to_message m, loose_alignment=false
l = @layout[m]
left = l.depth * INDENT_SPACES
right = left + l.width
- ## jump to the top line unless both top and bottom fit in the current view
- jump_to_line l.top unless l.top >= topline && l.top <= botline && l.bot >= topline && l.bot <= botline
+ ## jump to the top line
+ if loose_alignment
+ jump_to_line [l.top - 3, 0].max # give 3 lines of top context
+ else
+ jump_to_line l.top
+ end
- ## jump to the left columns unless both left and right fit in the current view
- jump_to_col left unless left >= leftcol && left <= rightcol && right >= leftcol && right <= rightcol
+ ## 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
## either way, move the cursor to the first line
set_cursor_pos l.top
@layout = @chunk_layout = @text = nil # for good luck
end
- def archive_and_kill
- dispatch_and_kill do
+ def archive_and_kill; archive_and_then :kill end
+ def spam_and_kill; spam_and_then :kill end
+ def delete_and_kill; delete_and_then :kill end
+ def unread_and_kill; unread_and_then :kill end
+
+ def archive_and_next; archive_and_then :next end
+ def spam_and_next; spam_and_then :next end
+ def delete_and_next; delete_and_then :next end
+ def unread_and_next; unread_and_then :next end
+ def do_nothing_and_next; do_nothing_and_then :next end
+
+ def archive_and_then op
+ dispatch op do
@thread.remove_label :inbox
UpdateManager.relay self, :archived, @thread.first
end
end
- def spam_and_kill
- dispatch_and_kill do
+ def spam_and_then op
+ dispatch op do
@thread.apply_label :spam
UpdateManager.relay self, :spammed, @thread.first
end
end
- def delete_and_kill
- dispatch_and_kill do
+ def delete_and_then op
+ dispatch op do
@thread.apply_label :deleted
UpdateManager.relay self, :deleted, @thread.first
end
end
- def skip_and_kill
- dispatch_and_kill { }
+ def unread_and_then op
+ dispatch op do
+ @thread.apply_label :unread
+ UpdateManager.relay self, :unread, @thread.first
+ end
+ end
+
+ def do_nothing_and_then op
+ dispatch op
end
- def dispatch_and_kill
+ def dispatch op
return if @dying
@dying = true
- if @index_mode
+ case op
+ when :next
@index_mode.launch_next_thread_after(@thread) do
- @thread.save Index if yield
+ @thread.save Index if block_given? && yield
BufferManager.kill_buffer_safely buffer
end
- else
+ when :kill
@thread.save Index if yield
BufferManager.kill_buffer_safely buffer
+ else
+ raise ArgumentError, "unknown thread dispatch operation #{op.inspect}"
end
end
- private :dispatch_and_kill
+ private :dispatch
def pipe_message
chunk = @chunk_lines[curpos]
BufferManager.erase_flash
BufferManager.completely_redraw_screen
unless success
- BufferManager.spawn "Attachment: #{chunk.filename}", TextMode.new(chunk.to_s)
+ BufferManager.spawn "Attachment: #{chunk.filename}", TextMode.new(chunk.to_s, chunk.filename)
BufferManager.flash "Couldn't execute view command, viewing as text."
end
end