"""
Insert_Command_Output.py - A Jython macro for jEdit that
inserts the output of a process into the current Buffer.

Copyright 2002 (C) Ollie Rutherfurd <oliver@rutherfurd.net>

$Id: Insert_Command_Output.py 28 2003-03-25 22:40:28Z oliver $
"""

__author__ = 'Ollie Rutherfurd'
__version__ = '$Revision: 1.3 $'[11:-2]

from java.lang import Runtime, Thread
from java.io import BufferedReader, InputStreamReader, IOException
from org.gjt.sp.jedit import Macros
import Queue
import os


class StreamThread(Thread):

	"""
	Class for reading output from a Java InputStream in a separate
	thread.

	Lines read from stream are placed in a Queue, to send
	them to the `controlling` thread.

	EOF is signalled by placing None into the Queue.

	NOTE: Based on StreamThread from Console plugin, 
	written by Slava Pestov.
	"""

	def __init__(self,inputStream,queue):
		self.inputStream = inputStream
		self.queue = queue

	def run(self):
		inp = None
		try:
			inp = BufferedReader(InputStreamReader(self.inputStream))
			while 1:
				line = inp.readLine()
				if line is None:
					self.queue.put(None)
					break
				self.queue.put(line)
		finally:
			if inp:
				inp.close()


def execute(cmd, directory=None, stdout=1,stderr=1):

	"""
	execute(cmd,directory=None,stdout=1,stderr=1) -> (exit code: int, output: [])

	executes `cmd` in the specified directory, or in the current
	directory if `directory` is None. If stdout == 1, stdout ouput
	will be returned if stderr == 1, stderr output will be returned.

	NOTE: stderr and stdout may both be 1, but at least one must be 1.

	If process runs without error, exitCode (int) is returned as
	is a list of output lines.

	@throws ValueError, IOException
	"""

	exitCode = None
	output = []				# output lines
	queue = Queue.Queue()	# queue for reading stdout/stderr

	if stdout not in (0,1):
		raise ValueError('stdout parameter value must be 0 or 1 (got %s).' % (str(stdout),))

	if stderr not in (0,1):
		raise ValueError('stderr parameter value must be 0 or 1 (got %s).' % (str(stderr),))

	streams = stdout + stderr
	if streams == 0:
		raise ValueError('one of both of stdout and stderr must be set to 1.')

	process = Runtime.getRuntime().exec(cmd,[],directory)

	# wrap stdout/stderr in threaded readers
	if stdout:
		stdout = StreamThread(process.getInputStream(), queue)
		stdout.start()
	if stderr:
		stderr = StreamThread(process.getErrorStream(), queue)
		stderr.start()

	# read output lines from queue, until a None
	# is recieved for each stream
	while streams:
		line = queue.get()
		if line is None:
			streams -= 1
		else:
			output.append(line)

	exitCode = process.exitValue()

	return exitCode,output


def main():

	cmd = Macros.input(init.view,'Execute Command', init.textArea.getSelectedText())
	if cmd is None or len(cmd) == 0:
		return

	# execute command
	try:
		exit,output = execute(cmd)
	except IOException,e:
		Macros.error(init.view, 'Error running: %s\n\n%s' % (cmd, str(e),))
		return
	except ValueError, e:
		Macros.error(init.view, 'Error executing `%s`: %s' % (cmd,str(e),))
		return

	# if didn't exit with 0 as exit value
	if exit != 0:
		Macros.error(init.view, 'Error: `%s` exited with %d' % (cmd,exit,))
		return

	# insert output
	init.textArea.setSelectedText('\n'.join(output))


if __name__ in ('__main__','main'):
	main()

# :indentSize=4:lineSeparator=\n:noTabs=false:tabSize=4:

