From 9aee4ec9b1469cf5927355daf65ce82154d949b1 Mon Sep 17 00:00:00 2001 From: Andrew De Ponte Date: Tue, 31 Jan 2012 23:32:22 -0800 Subject: [PATCH] Added word_wrap and Guard auto termination. I figured out how to enable native Sublime Text 2 view based word wrapping in the output pane so I enabled that. It is a little strange with respect to autoscrolling because the output is not hard wrapped. I think that can be fixed by actually scrolling to the size of the view like I used to rather than the first char in each line. This will require further testing and will be resolved in another commit. I also added a guard_wrapper command which is now what is executed by the plugin. It simply wraps IO for the guard command and watches for its STDIN to be closed. It does this because when the wrappers STDIN closes that means that Sublime Text 2 has exited either cleanly or by crash and we need to stop Guard. --- guard.py | 15 ++++++++--- guard_wrapper | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100755 guard_wrapper diff --git a/guard.py b/guard.py index 4b50d47..c591632 100644 --- a/guard.py +++ b/guard.py @@ -6,7 +6,6 @@ import functools import re - sublime_guard_controller = None @@ -16,6 +15,7 @@ def __init__(self, listener): self.running = False self.listener = listener self.output_view = self.listener.window.get_output_panel('guard') + self.enable_word_wrap() def open_file_paths(self): return [view.file_name() for view in self.listener.window.views() if view.file_name()] @@ -38,14 +38,17 @@ def find_project_root_path(self): break return project_root_path + def enable_word_wrap(self): + self.output_view.settings().set("word_wrap", True) + def start_guard(self): project_root_path = self.find_project_root_path() if (project_root_path == None): sublime.error_message("Failed to find Guardfile and Gemfile in any of the open folders.") else: package_path = sublime.packages_path() - cmd = "\"" + package_path + "/Guard/run_guard.sh\" \"" + project_root_path + "\"" - self.proc = subprocess.Popen([cmd], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd_array = [package_path + "/Guard/guard_wrapper", package_path + "/Guard/run_guard.sh", project_root_path] + self.proc = subprocess.Popen(cmd_array, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.running = True self.show_guard_view() if self.proc.stdout: @@ -108,6 +111,7 @@ def hide_guard_view(self): def stop_guard(self): self.proc.stdin.write('e\n') + self.proc.stdin.flush() self.running = False def is_guard_running(self): @@ -115,18 +119,23 @@ def is_guard_running(self): def reload_guard(self): self.proc.stdin.write('r\n') + self.proc.stdin.flush() def run_all_tests(self): self.proc.stdin.write('\n') + self.proc.stdin.flush() def output_help(self): self.proc.stdin.write('h\n') + self.proc.stdin.flush() def toggle_notifications(self): self.proc.stdin.write('n\n') + self.proc.stdin.flush() def pause(self): self.proc.stdin.write('p\n') + self.proc.stdin.flush() def GuardControllerSingleton(listener): diff --git a/guard_wrapper b/guard_wrapper new file mode 100755 index 0000000..8387321 --- /dev/null +++ b/guard_wrapper @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +import sys +import os +import subprocess +import threading + + +class GuardWrapper: + def __init__(self): + self.running = False + self.proc = None + self.stdout_thread = None + self.stderr_thread = None + self.log = open('/tmp/guard_wrapper.log', 'w') + + def run_cmd(self, cmd_array): + self.proc = subprocess.Popen(cmd_array, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.running = True + if self.proc.stdout: + self.stdout_thread = threading.Thread(target=self.read_stdout, args=()) + self.stdout_thread.start() + if self.proc.stderr: + self.stderr_thread = threading.Thread(target=self.read_stderr, args=()) + self.stderr_thread.start() + while True: + self.log.write("read stdin iteration\n") + self.log.flush() + data = sys.stdin.readline() + if data != "": + self.log.write("Received: " + data + "\n") + self.log.flush() + if data == "e\n": + self.proc.stdin.write(data) + self.proc.stdin.flush() + break + else: + self.proc.stdin.write(data) + self.proc.stdin.flush() + else: + self.log.write("got empty string, :-(\n") + self.log.flush() + self.proc.stdin.write("e\n") + self.proc.stdin.flush() + self.proc.stdin.close() + break + self.stdout_thread.join() + self.stderr_thread.join() + + def read_stdout(self): + while True: + data = os.read(self.proc.stdout.fileno(), 2 ** 15) + if data != "": + sys.stdout.write(data) + sys.stdout.flush() + else: + self.proc.stdout.close() + self.running = False + break + + def read_stderr(self): + while True: + data = os.read(self.proc.stderr.fileno(), 2 ** 15) + if data != "": + sys.stderr.write(data) + sys.stderr.flush() + else: + self.proc.stderr.close() + self.running = False + break + + +wrap = GuardWrapper() +wrap.run_cmd(sys.argv[1:])