1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-02-21 12:28:41 +00:00

#N/A Add ability to get shell history

This commit is contained in:
nvbn 2015-07-10 16:42:21 +03:00
parent c7071763a3
commit 4b4e7acc0f
2 changed files with 62 additions and 4 deletions

View File

@ -12,6 +12,16 @@ def isfile(mocker):
return mocker.patch('os.path.isfile', return_value=True) return mocker.patch('os.path.isfile', return_value=True)
@pytest.fixture
@pytest.mark.usefixtures('isfile')
def history_lines(mocker):
def aux(lines):
mock = mocker.patch('io.open')
mock.return_value.__enter__\
.return_value.__iter__.return_value = lines
return aux
class TestGeneric(object): class TestGeneric(object):
@pytest.fixture @pytest.fixture
def shell(self): def shell(self):
@ -38,6 +48,12 @@ class TestGeneric(object):
assert 'thefuck' in shell.app_alias() assert 'thefuck' in shell.app_alias()
assert 'TF_ALIAS' in shell.app_alias() assert 'TF_ALIAS' in shell.app_alias()
def test_get_history(self, history_lines, shell):
history_lines(['ls', 'rm'])
# We don't know what to do in generic shell with history lines,
# so just ignore them:
assert list(shell.get_history()) == []
@pytest.mark.usefixtures('isfile') @pytest.mark.usefixtures('isfile')
class TestBash(object): class TestBash(object):
@ -85,6 +101,10 @@ class TestBash(object):
assert 'thefuck' in shell.app_alias() assert 'thefuck' in shell.app_alias()
assert 'TF_ALIAS' in shell.app_alias() assert 'TF_ALIAS' in shell.app_alias()
def test_get_history(self, history_lines, shell):
history_lines(['ls', 'rm'])
assert list(shell.get_history()) == ['ls', 'rm']
@pytest.mark.usefixtures('isfile') @pytest.mark.usefixtures('isfile')
class TestFish(object): class TestFish(object):
@ -187,3 +207,7 @@ class TestZsh(object):
assert 'alias fuck' in shell.app_alias() assert 'alias fuck' in shell.app_alias()
assert 'thefuck' in shell.app_alias() assert 'thefuck' in shell.app_alias()
assert 'TF_ALIAS' in shell.app_alias() assert 'TF_ALIAS' in shell.app_alias()
def test_get_history(self, history_lines, shell):
history_lines([': 1432613911:0;ls', ': 1432613916:0;rm'])
assert list(shell.get_history()) == ['ls', 'rm']

View File

@ -7,7 +7,9 @@ from collections import defaultdict
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from time import time from time import time
import os import os
import io
from psutil import Process from psutil import Process
import six
from .utils import DEVNULL, memoize from .utils import DEVNULL, memoize
@ -48,6 +50,26 @@ class Generic(object):
with open(history_file_name, 'a') as history: with open(history_file_name, 'a') as history:
history.write(self._get_history_line(command_script)) history.write(self._get_history_line(command_script))
def _script_from_history(self, line):
"""Returns prepared history line.
Should return a blank line if history line is corrupted or empty.
"""
return ''
def get_history(self):
"""Returns list of history entries."""
history_file_name = self._get_history_file_name()
if os.path.isfile(history_file_name):
with io.open(history_file_name, 'r',
encoding='utf-8', errors='ignore') as history:
for line in history:
prepared = self._script_from_history(line)\
.strip()
if prepared:
yield prepared
def and_(self, *commands): def and_(self, *commands):
return u' && '.join(commands) return u' && '.join(commands)
@ -63,7 +85,6 @@ class Bash(Generic):
value = value[1:-1] value = value[1:-1]
return name, value return name, value
@memoize
def get_aliases(self): def get_aliases(self):
proc = Popen('bash -ic alias', stdout=PIPE, stderr=DEVNULL, proc = Popen('bash -ic alias', stdout=PIPE, stderr=DEVNULL,
shell=True) shell=True)
@ -79,6 +100,10 @@ class Bash(Generic):
def _get_history_line(self, command_script): def _get_history_line(self, command_script):
return u'{}\n'.format(command_script) return u'{}\n'.format(command_script)
def _script_from_history(self, line):
print(line)
return line
class Fish(Generic): class Fish(Generic):
def app_alias(self): def app_alias(self):
@ -96,7 +121,6 @@ class Fish(Generic):
" end\n" " end\n"
"end") "end")
@memoize
def get_aliases(self): def get_aliases(self):
proc = Popen('fish -ic functions', stdout=PIPE, stderr=DEVNULL, proc = Popen('fish -ic functions', stdout=PIPE, stderr=DEVNULL,
shell=True) shell=True)
@ -137,7 +161,6 @@ class Zsh(Generic):
value = value[1:-1] value = value[1:-1]
return name, value return name, value
@memoize
def get_aliases(self): def get_aliases(self):
proc = Popen('zsh -ic alias', stdout=PIPE, stderr=DEVNULL, proc = Popen('zsh -ic alias', stdout=PIPE, stderr=DEVNULL,
shell=True) shell=True)
@ -153,6 +176,12 @@ class Zsh(Generic):
def _get_history_line(self, command_script): def _get_history_line(self, command_script):
return u': {}:0;{}\n'.format(int(time()), command_script) return u': {}:0;{}\n'.format(int(time()), command_script)
def _script_from_history(self, line):
if ';' in line:
return line.split(';', 1)[1]
else:
return ''
class Tcsh(Generic): class Tcsh(Generic):
def app_alias(self): def app_alias(self):
@ -162,7 +191,6 @@ class Tcsh(Generic):
name, value = alias.split("\t", 1) name, value = alias.split("\t", 1)
return name, value return name, value
@memoize
def get_aliases(self): def get_aliases(self):
proc = Popen('tcsh -ic alias', stdout=PIPE, stderr=DEVNULL, proc = Popen('tcsh -ic alias', stdout=PIPE, stderr=DEVNULL,
shell=True) shell=True)
@ -219,5 +247,11 @@ def and_(*commands):
return _get_shell().and_(*commands) return _get_shell().and_(*commands)
@memoize
def get_aliases(): def get_aliases():
return list(_get_shell().get_aliases().keys()) return list(_get_shell().get_aliases().keys())
@memoize
def get_history():
return list(_get_shell().get_history())