diff --git a/thefuck/const.py b/thefuck/const.py index dc55a5a2..2009d499 100644 --- a/thefuck/const.py +++ b/thefuck/const.py @@ -81,3 +81,7 @@ LOG_SIZE_IN_BYTES = 1024 * 1024 LOG_SIZE_TO_CLEAN = 10 * 1024 DIFF_WITH_ALIAS = 0.5 + +SHELL_LOGGER_SOCKET_ENV = 'SHELL_LOGGER_SOCKET' + +SHELL_LOGGER_LIMIT = 5 diff --git a/thefuck/output_readers/__init__.py b/thefuck/output_readers/__init__.py index 1bae93c8..94434d0e 100644 --- a/thefuck/output_readers/__init__.py +++ b/thefuck/output_readers/__init__.py @@ -1,5 +1,5 @@ from ..conf import settings -from . import read_log, rerun +from . import read_log, rerun, shell_logger def get_output(script, expanded): @@ -12,6 +12,8 @@ def get_output(script, expanded): :rtype: str """ + if shell_logger.is_available(): + return shell_logger.get_output(script) if settings.instant_mode: return read_log.get_output(script) else: diff --git a/thefuck/output_readers/shell_logger.py b/thefuck/output_readers/shell_logger.py new file mode 100644 index 00000000..280053da --- /dev/null +++ b/thefuck/output_readers/shell_logger.py @@ -0,0 +1,60 @@ +import json +import os +import socket +try: + from shutil import get_terminal_size +except ImportError: + from backports.shutil_get_terminal_size import get_terminal_size +import pyte +from .. import const, logs + + +def _get_socket_path(): + return os.environ.get(const.SHELL_LOGGER_SOCKET_ENV) + + +def is_available(): + """Returns `True` if shell logger socket available. + + :rtype: book + + """ + path = _get_socket_path() + if not path: + return False + + return os.path.exists(path) + + +def _get_last_n(n): + with socket.socket(socket.AF_UNIX) as client: + client.connect(_get_socket_path()) + request = json.dumps({ + "type": "list", + "count": n, + }) + '\n' + client.sendall(request.encode('utf-8')) + response = client.makefile().readline() + return json.loads(response)['commands'] + + +def _get_output_lines(output): + lines = output.split('\n') + screen = pyte.Screen(get_terminal_size().columns, len(lines)) + stream = pyte.Stream(screen) + stream.feed('\n'.join(lines)) + return screen.display + + +def get_output(script): + """Gets command output from shell logger.""" + with logs.debug_time(u'Read output from external shell logger'): + commands = _get_last_n(const.SHELL_LOGGER_LIMIT) + for command in commands: + if command['command'] == script: + lines = _get_output_lines(command['output']) + output = '\n'.join(lines).strip() + return output + else: + logs.warn("Output isn't available in shell logger") + return None