Excerpts from Hamish's message of Sun Feb 20 22:02:54 +0000 2011: > For the moment this work is in the async_message_edit branch. If no one > shouts about this being a terrible idea then I'll merge it into next > within a week.
No one shouted, so I've merged it into next. At the end of the email is the diff of the async_message_edit branch against where I started it. Hamish Downer diff --git a/lib/sup.rb b/lib/sup.rb index 74eb950..213823c 100644 --- a/lib/sup.rb +++ b/lib/sup.rb @@ -370,6 +370,7 @@ require "sup/horizontal-selector" require "sup/modes/line-cursor-mode" require "sup/modes/help-mode" require "sup/modes/edit-message-mode" +require "sup/modes/edit-message-async-mode" require "sup/modes/compose-mode" require "sup/modes/resume-mode" require "sup/modes/forward-mode" diff --git a/lib/sup/buffer.rb b/lib/sup/buffer.rb index 25ea132..444589a 100644 --- a/lib/sup/buffer.rb +++ b/lib/sup/buffer.rb @@ -73,7 +73,7 @@ class InputSequenceAborted < StandardError; end class Buffer attr_reader :mode, :x, :y, :width, :height, :title, :atime bool_reader :dirty, :system - bool_accessor :force_to_top + bool_accessor :force_to_top, :hidden def initialize window, mode, width, height, opts={} @w = window @@ -82,6 +82,7 @@ class Buffer @focus = false @title = opts[:title] || "" @force_to_top = opts[:force_to_top] || false + @hidden = opts[:hidden] || false @x, @y, @width, @height = 0, 0, width, height @atime = Time.at 0 @system = opts[:system] || false @@ -265,7 +266,7 @@ EOS end def rollable_buffers - @buffers.select { |b| !b.system? || @buffers.last == b } + @buffers.select { |b| !(b.system? || b.hidden?) || @buffers.last == b } end def handle_input c diff --git a/lib/sup/modes/buffer-list-mode.rb b/lib/sup/modes/buffer-list-mode.rb index 40f2e76..08bb604 100644 --- a/lib/sup/modes/buffer-list-mode.rb +++ b/lib/sup/modes/buffer-list-mode.rb @@ -28,7 +28,7 @@ protected end def regen_text - @bufs = BufferManager.buffers.reject { |name, buf| buf.mode == self }.sort_by { |name, buf| buf.atime }.reverse + @bufs = BufferManager.buffers.reject { |name, buf| buf.mode == self || buf.hidden? }.sort_by { |name, buf| buf.atime }.reverse width = @bufs.max_of { |name, buf| buf.mode.name.length } @text = @bufs.map do |name, buf| base_color = buf.system? ? :system_buf_color : :regular_buf_color diff --git a/lib/sup/modes/edit-message-async-mode.rb b/lib/sup/modes/edit-message-async-mode.rb new file mode 100644 index 0000000..385ba6a --- /dev/null +++ b/lib/sup/modes/edit-message-async-mode.rb @@ -0,0 +1,89 @@ +module Redwood + +class EditMessageAsyncMode < LineCursorMode + + register_keymap do |k| + k.add :edit_finished, "Finished editing message", 'E' + k.add :path_to_clipboard, "Copy file path to the clipboard", :enter + end + + def initialize parent_edit_mode, file_path, msg_subject + @parent_edit_mode = parent_edit_mode + @file_path = file_path + @orig_mtime = File.mtime @file_path + + @text = ["ASYNC MESSAGE EDIT", + "", "Your message with subject:", msg_subject, "is saved in a file:", "", @file_path, "", + "You can edit your message in the editor of your choice and continue to", + "use sup while you edit your message.", "", + "Press <Enter> to have the file path copied to the clipboard.", "", + "When you have finished editing, select this buffer and press 'E'.",] + super() + end + + def lines; @text.length end + + def [] i + @text[i] + end + + def killable? + if file_being_edited? + if !BufferManager.ask_yes_or_no("It appears the file is still being edited. Are you sure?") + return false + end + end + + @parent_edit_mode.edit_message_async_resume true + true + end + + def unsaved? + !file_being_edited? && !file_has_been_edited? + end + +protected + + def edit_finished + if file_being_edited? + if !BufferManager.ask_yes_or_no("It appears the file is still being edited. Are you sure?") + return false + end + end + + @parent_edit_mode.edit_message_async_resume + BufferManager.kill_buffer buffer + true + end + + def path_to_clipboard + if system("which xsel > /dev/null 2>&1") + # linux/unix path + IO.popen('xsel --clipboard --input', 'r+') { |clipboard| clipboard.puts(@file_path) } + BufferManager.flash "Copied file path to clipboard." + elsif system("which pbcopy > /dev/null 2>&1") + # mac path + IO.popen('pbcopy', 'r+') { |clipboard| clipboard.puts(@file_path) } + BufferManager.flash "Copied file path to clipboard." + else + BufferManager.flash "No way to copy text to clipboard - try installing xsel." + end + end + + def file_being_edited? + # check for common editor lock files + vim_lock_file = File.join(File.dirname(@file_path), '.'+File.basename(@file_path)+'.swp') + emacs_lock_file = File.join(File.dirname(@file_path), '.#'+File.basename(@file_path)) + + return true if File.exist?(vim_lock_file) || File.exist?(emacs_lock_file) + + false + end + + def file_has_been_edited? + File.mtime(@file_path) > @orig_mtime + end + +end + +end diff --git a/lib/sup/modes/edit-message-mode.rb b/lib/sup/modes/edit-message-mode.rb index 734a879..01f3653 100644 --- a/lib/sup/modes/edit-message-mode.rb +++ b/lib/sup/modes/edit-message-mode.rb @@ -80,6 +80,7 @@ EOS k.add :edit_cc, "Edit Cc:", 'c' k.add :edit_subject, "Edit Subject", 's' k.add :edit_message, "Edit message", :enter + k.add :edit_message_async, "Edit message asynchronously", 'E' k.add :save_as_draft, "Save as draft", 'P' k.add :attach_file, "Attach a file", 'a' k.add :delete_attachment, "Delete an attachment", 'd' @@ -184,7 +185,51 @@ EOS @edited end + def edit_message_async + @file = Tempfile.new ["sup.#{self.class.name.gsub(/.*::/, '').camel_to_hyphy}", ".eml"] + @file.puts format_headers(@header - NON_EDITABLE_HEADERS).first + @file.puts + @file.puts @body.join("\n") + @file.close + + @mtime = File.mtime @file.path + + # put up buffer saying you can now edit the message in another + # terminal or app, and continue to use sup in the meantime. + subject = @header["Subject"] || "" + @async_mode = EditMessageAsyncMode.new self, @file.path, subject + BufferManager.spawn "Waiting for message \"#{subject}\" to be finished", @async_mode + + # hide ourselves, and wait for signal to resume from async mode ... + buffer.hidden = true + end + + def edit_message_async_resume being_killed=false + buffer.hidden = false + @async_mode = nil + BufferManager.raise_to_front buffer if !being_killed + + @edited = true if File.mtime(@file.path) > @mtime + + header, @body = parse_file @file.path + @header = header - NON_EDITABLE_HEADERS + handle_new_text @header, @body + update + + true + end + def killable? + if !@async_mode.nil? + return false if !@async_mode.killable? + if File.mtime(@file.path) > @mtime + @edited = true + header, @body = parse_file @file.path + @header = header - NON_EDITABLE_HEADERS + handle_new_text @header, @body + update + end + end !edited? || BufferManager.ask_yes_or_no("Discard message?") end _______________________________________________ Sup-devel mailing list Sup-devel@rubyforge.org http://rubyforge.org/mailman/listinfo/sup-devel