[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