module Redcar
class Runnables
class CommandOutputController
include Redcar::HtmlController
attr_accessor :cmd
def initialize(path, cmd, title)
@path = path
@cmd = cmd
@title = title
@output_id = 0
end
def title
@title
end
def ask_before_closing
if @pid
"This tab contains an unfinished process. \n\nKill the process and close?"
end
end
def close
if @pid
Process.kill(9, @pid.to_i + 1)
end
end
def run
case Redcar.platform
when :osx, :linux
cmd = "sh -c \"cd #{@path}; #{@cmd}\""
when :windows
cmd = "cd \"#{@path.gsub('/', '\\')}\" & #{@cmd}"
end
run_command(cmd)
end
def copy_output(text)
Redcar.app.clipboard << text
end
def stylesheet_link_tag(*files)
files.map do |file|
path = File.join(Redcar.root, %w(plugins runnables views) + [file.to_s + ".css"])
url = "file://" + File.expand_path(path)
%Q||
end.join("\n")
end
def process(text)
@processor ||= OutputProcessor.new
@processor.process(text)
end
def output_thread(type, output)
Thread.new(output) do
instance_variable_set("@#{type}_thread_started", true)
begin
while line = output.gets
append_output %Q|
#{process(line)}
|
end
rescue => e
puts e.class
puts e.message
puts e.backtrace
end
end
end
def run_command(cmd)
Thread.new do
execute <<-JS
$('.actions').hide();
$('.output').slideUp().prev('.header').addClass('up');
JS
# TODO: Find browser's onload rather than sleeping
sleep 1
start_output_block
Redcar.log.info "Running: #{cmd}"
# JRuby-specific
@pid, input, output, error = IO.popen4(cmd)
@stdout_thread = output_thread(:stdout, output)
@stderr_thread = output_thread(:stderr, error)
Thread.new do
sleep 0.1 until finished?
@pid = nil
end_output_block
end
end
end
def finished?
@stdout_thread_started && @stderr_thread_started &&
!@stdout_thread.alive? && !@stderr_thread.alive?
end
def format_time(time)
time.strftime("%I:%M:%S %p").downcase
end
def start_output_block
@start = Time.now
@output_id += 1
append_to_container <<-HTML
Started at #{format_time(@start)}
HTML
end
def end_output_block
@end = Time.now
append_to(header_container, <<-HTML)
Completed at #{format_time(@end)}. (Took #{@end - @start} seconds)
HTML
execute <<-JS
$('Copy output to clipboard').click(function () {
Controller.copyOutput($("#{output_container}").text());
return false;
}).appendTo('#{header_container}');
$("#{output_container}").parent().removeClass("running");
$('.actions').show();
$("html, body").attr({ scrollTop: $("body").attr("scrollHeight") });
JS
end
def scroll_to_end(container)
execute <<-JS
$("html, body").attr({ scrollTop: $("body").attr("scrollHeight") });
JS
end
def append_to(container, html)
execute(<<-JS)
$(#{html.inspect}).appendTo("#{container}");
JS
end
def append_to_container(html)
append_to("#container", html)
scroll_to_end("#container")
end
def header_container
"#header#{@output_id}"
end
def output_container
"#output#{@output_id}"
end
def append_output(output)
append_to(output_container, output)
scroll_to_end(output_container)
end
def open_file(file, line)
Project::Manager.open_file(File.join(Project::Manager.focussed_project.path, file))
Redcar.app.focussed_window.focussed_notebook_tab.edit_view.document.scroll_to_line(line.to_i)
end
def index
rhtml = ERB.new(File.read(File.join(File.dirname(__FILE__), "..", "..", "views", "command_output.html.erb")))
command = @cmd
run
rhtml.result(binding)
end
end
end
end