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

[sup-talk] [PATCH] mutt-style pipe to interactive process support



Adds a new method maybe_interactive_pipe_message to ThreadViewMode which will
pipe a message to a process in the same manner as the mutt mutt_pipe_message
command, allowing interactive tools such as 'urlview' to reopen the tty for
IO.

Terminating your pipe command with the pipe character ('|') for "pipe back to
sup" will use the original behavior, capturing the output of the pipeline for
display in a sup buffer. Calling maybe_interactive_pipe_message with
maybe_interactive=false, or calling pipe_message will always use the old
behavior.

No keymap is provided in this patch. It is recommended to replace pipe_message
on '|' in keybindings.rb using a line like:

Redwood::ThreadViewMode::keymap.add! :maybe_interactive_pipe_message, "Pipe
message or attachment to an interactive shell command", '|'
---
 lib/sup/mode.rb                   |   32 ++++++++++++++++++++++++
 lib/sup/modes/thread-view-mode.rb |   48 +++++++++++++++++++++++++++++-------
 2 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/lib/sup/mode.rb b/lib/sup/mode.rb
index f5aee1c..8d6197d 100644
--- a/lib/sup/mode.rb
+++ b/lib/sup/mode.rb
@@ -101,6 +101,38 @@ EOS
     end
   end
 
+  def pipe_to_interactive_process command
+    read, write = IO.pipe
+
+    child_pid = fork
+    if child_pid
+      # main process
+      begin
+        read.close
+        yield write
+      rescue
+        warn "error writing to #{command}: #{$!}"
+        BufferManager.flash "error writing to #{command}: #{$!}"
+      ensure
+        write.close
+        Process.waitpid(child_pid)
+      end
+    else
+      # child
+      begin
+        write.close
+        $stdin.reopen(read)
+        exec(command)
+      rescue
+        # Can't access logger from child process, but can flash an error
+        BufferManager.flash "error running #{command}: #{$!}"
+      ensure
+        read.close
+        Kernel.exit!(127)
+      end
+    end
+  end
+
   def pipe_to_process command
     Open3.popen3(command) do |input, output, error|
       err, data, * = IO.select [error], [input], nil
diff --git a/lib/sup/modes/thread-view-mode.rb b/lib/sup/modes/thread-view-mode.rb
index 088529b..bd7908c 100644
--- a/lib/sup/modes/thread-view-mode.rb
+++ b/lib/sup/modes/thread-view-mode.rb
@@ -661,6 +661,10 @@ EOS
   private :dispatch
 
   def pipe_message
+    maybe_interactive_pipe_message false
+  end
+
+  def maybe_interactive_pipe_message maybe_interactive=true
     chunk = @chunk_lines[curpos]
     chunk = nil unless chunk.is_a?(Chunk::Attachment)
     message = @message_lines[curpos] unless chunk
@@ -669,20 +673,44 @@ EOS
 
     command = BufferManager.ask(:shell, "pipe command: ")
     return if command.nil? || command.empty?
+    if maybe_interactive and command[-1,1]=="|"
+      command = command.chop.strip
+      return if command.empty?
+      interactive = false
+    else
+      interactive = maybe_interactive
+    end
+
+    if interactive
+      pipe_to_interactive_process(command) do |stream|
+        if chunk
+          stream.print chunk.raw_content
+        else
+          message.each_raw_message_line { |l| 
+            begin
+              stream.print l
+            rescue
+              warn "error writing to #{command}: #{$!}"
+              BufferManager.flash "error writing to #{command}: #{$!}"
+              break
+            end }
+        end
+      end
+    else
+      output = pipe_to_process(command) do |stream|
+        if chunk
+          stream.print chunk.raw_content
+        else
+          message.each_raw_message_line { |l| stream.print l }
+        end
+      end
 
-    output = pipe_to_process(command) do |stream|
-      if chunk
-        stream.print chunk.raw_content
+      if output
+        BufferManager.spawn "Output of '#{command}'", TextMode.new(output.ascii)
       else
-        message.each_raw_message_line { |l| stream.print l }
+        BufferManager.flash "'#{command}' done!"
       end
     end
-
-    if output
-      BufferManager.spawn "Output of '#{command}'", TextMode.new(output.ascii)
-    else
-      BufferManager.flash "'#{command}' done!"
-    end
   end
 
 private
-- 
1.6.4.4

_______________________________________________
sup-talk mailing list
sup-talk@rubyforge.org
http://rubyforge.org/mailman/listinfo/sup-talk