[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [sup-devel] editing messages outside of sup



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