mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 15:12:20 +00:00 
			
		
		
		
	#N/A: Split shells module
				
					
				
			This commit is contained in:
		
							
								
								
									
										0
									
								
								tests/shells/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/shells/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								tests/shells/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/shells/conftest.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| import pytest | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def builtins_open(mocker): | ||||
|     return mocker.patch('six.moves.builtins.open') | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def isfile(mocker): | ||||
|     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.readlines.return_value = lines | ||||
|     return aux | ||||
							
								
								
									
										60
									
								
								tests/shells/test_bash.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								tests/shells/test_bash.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pytest | ||||
| from thefuck.shells import Bash | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestBash(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return Bash() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.bash.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'alias fuck=\'eval $(thefuck $(fc -ln -1))\'\n' | ||||
|             b'alias l=\'ls -CF\'\n' | ||||
|             b'alias la=\'ls -A\'\n' | ||||
|             b'alias ll=\'ls -alF\'') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('pwd', 'pwd'), | ||||
|         ('fuck', 'eval $(thefuck $(fc -ln -1))'), | ||||
|         ('awk', 'awk'), | ||||
|         ('ll', 'ls -alF')]) | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', 'ls\n'), | ||||
|         (u'echo café', 'echo café\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, shell): | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))', | ||||
|                                        'l': 'ls -CF', | ||||
|                                        'la': 'ls -A', | ||||
|                                        'll': 'ls -alF'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines(['ls', 'rm']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
							
								
								
									
										86
									
								
								tests/shells/test_fish.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								tests/shells/test_fish.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pytest | ||||
| from thefuck.shells import Fish | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestFish(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return Fish() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.fish.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n' | ||||
|             b'man\nmath\npopd\npushd\nruby') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def environ(self, monkeypatch): | ||||
|         data = {'TF_OVERRIDDEN_ALIASES': 'cd, ls, man, open'} | ||||
|         monkeypatch.setattr('thefuck.shells.fish.os.environ', data) | ||||
|         return data | ||||
|  | ||||
|     @pytest.mark.usefixture('environ') | ||||
|     def test_get_overridden_aliases(self, shell, environ): | ||||
|         assert shell._get_overridden_aliases() == ['cd', 'ls', 'man', 'open'] | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('cd', 'cd'), | ||||
|         ('pwd', 'pwd'), | ||||
|         ('fuck', 'fish -ic "fuck"'), | ||||
|         ('find', 'find'), | ||||
|         ('funced', 'fish -ic "funced"'), | ||||
|         ('grep', 'grep'), | ||||
|         ('awk', 'awk'), | ||||
|         ('math "2 + 2"', r'fish -ic "math \"2 + 2\""'), | ||||
|         ('man', 'man'), | ||||
|         ('open', 'open'), | ||||
|         ('vim', 'vim'), | ||||
|         ('ll', 'fish -ic "ll"'), | ||||
|         ('ls', 'ls')])  # Fish has no aliases but functions | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', '- cmd: ls\n   when: 1430707243\n'), | ||||
|         (u'echo café', '- cmd: echo café\n   when: 1430707243\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell): | ||||
|         mocker.patch('thefuck.shells.fish.time', | ||||
|                      return_value=1430707243.3517463) | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('foo', 'bar') == 'foo; and bar' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {'fish_config': 'fish_config', | ||||
|                                        'fuck': 'fuck', | ||||
|                                        'funced': 'funced', | ||||
|                                        'funcsave': 'funcsave', | ||||
|                                        'history': 'history', | ||||
|                                        'll': 'll', | ||||
|                                        'math': 'math', | ||||
|                                        'popd': 'popd', | ||||
|                                        'pushd': 'pushd', | ||||
|                                        'ruby': 'ruby'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'function fuck' in shell.app_alias('fuck') | ||||
|         assert 'function FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines(['- cmd: ls', '  when: 1432613911', | ||||
|                        '- cmd: rm', '  when: 1432613916']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
							
								
								
									
										44
									
								
								tests/shells/test_generic.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/shells/test_generic.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pytest | ||||
| from thefuck.shells import Generic | ||||
|  | ||||
|  | ||||
| class TestGeneric(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return Generic() | ||||
|  | ||||
|     def test_from_shell(self, shell): | ||||
|         assert shell.from_shell('pwd') == 'pwd' | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     def test_put_to_history(self, builtins_open, shell): | ||||
|         assert shell.put_to_history('ls') is None | ||||
|         assert shell.put_to_history(u'echo café') is None | ||||
|         assert builtins_open.call_count == 0 | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     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()) == [] | ||||
|  | ||||
|     def test_split_command(self, shell): | ||||
|         assert shell.split_command('ls') == ['ls'] | ||||
|         assert shell.split_command(u'echo café') == [u'echo', u'café'] | ||||
							
								
								
									
										62
									
								
								tests/shells/test_zsh.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								tests/shells/test_zsh.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pytest | ||||
| from thefuck.shells.zsh import Zsh | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestZsh(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return Zsh() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.zsh.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'fuck=\'eval $(thefuck $(fc -ln -1 | tail -n 1))\'\n' | ||||
|             b'l=\'ls -CF\'\n' | ||||
|             b'la=\'ls -A\'\n' | ||||
|             b'll=\'ls -alF\'') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('fuck', 'eval $(thefuck $(fc -ln -1 | tail -n 1))'), | ||||
|         ('pwd', 'pwd'), | ||||
|         ('ll', 'ls -alF')]) | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', ': 1430707243:0;ls\n'), | ||||
|         (u'echo café', ': 1430707243:0;echo café\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell): | ||||
|         mocker.patch('thefuck.shells.zsh.time', | ||||
|                      return_value=1430707243.3517463) | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == { | ||||
|             'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))', | ||||
|             'l': 'ls -CF', | ||||
|             'la': 'ls -A', | ||||
|             'll': 'ls -alF'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines([': 1432613911:0;ls', ': 1432613916:0;rm']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
| @@ -1,260 +0,0 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pytest | ||||
| from thefuck import shells | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def builtins_open(mocker): | ||||
|     return mocker.patch('six.moves.builtins.open') | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def isfile(mocker): | ||||
|     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.readlines.return_value = lines | ||||
|     return aux | ||||
|  | ||||
|  | ||||
| class TestGeneric(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return shells.Generic() | ||||
|  | ||||
|     def test_from_shell(self, shell): | ||||
|         assert shell.from_shell('pwd') == 'pwd' | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     def test_put_to_history(self, builtins_open, shell): | ||||
|         assert shell.put_to_history('ls') is None | ||||
|         assert shell.put_to_history(u'echo café') is None | ||||
|         assert builtins_open.call_count == 0 | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     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()) == [] | ||||
|  | ||||
|     def test_split_command(self, shell): | ||||
|         assert shell.split_command('ls') == ['ls'] | ||||
|         assert shell.split_command(u'echo café') == [u'echo', u'café'] | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestBash(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return shells.Bash() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'alias fuck=\'eval $(thefuck $(fc -ln -1))\'\n' | ||||
|             b'alias l=\'ls -CF\'\n' | ||||
|             b'alias la=\'ls -A\'\n' | ||||
|             b'alias ll=\'ls -alF\'') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('pwd', 'pwd'), | ||||
|         ('fuck', 'eval $(thefuck $(fc -ln -1))'), | ||||
|         ('awk', 'awk'), | ||||
|         ('ll', 'ls -alF')]) | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', 'ls\n'), | ||||
|         (u'echo café', 'echo café\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, shell): | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))', | ||||
|                                        'l': 'ls -CF', | ||||
|                                        'la': 'ls -A', | ||||
|                                        'll': 'ls -alF'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines(['ls', 'rm']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestFish(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return shells.Fish() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n' | ||||
|             b'man\nmath\npopd\npushd\nruby') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def environ(self, monkeypatch): | ||||
|         data = {'TF_OVERRIDDEN_ALIASES': 'cd, ls, man, open'} | ||||
|         monkeypatch.setattr('thefuck.shells.os.environ', data) | ||||
|         return data | ||||
|  | ||||
|     @pytest.mark.usefixture('environ') | ||||
|     def test_get_overridden_aliases(self, shell, environ): | ||||
|         assert shell._get_overridden_aliases() == ['cd', 'ls', 'man', 'open'] | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('cd', 'cd'), | ||||
|         ('pwd', 'pwd'), | ||||
|         ('fuck', 'fish -ic "fuck"'), | ||||
|         ('find', 'find'), | ||||
|         ('funced', 'fish -ic "funced"'), | ||||
|         ('grep', 'grep'), | ||||
|         ('awk', 'awk'), | ||||
|         ('math "2 + 2"', r'fish -ic "math \"2 + 2\""'), | ||||
|         ('man', 'man'), | ||||
|         ('open', 'open'), | ||||
|         ('vim', 'vim'), | ||||
|         ('ll', 'fish -ic "ll"'), | ||||
|         ('ls', 'ls')])  # Fish has no aliases but functions | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', '- cmd: ls\n   when: 1430707243\n'), | ||||
|         (u'echo café', '- cmd: echo café\n   when: 1430707243\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell): | ||||
|         mocker.patch('thefuck.shells.time', | ||||
|                      return_value=1430707243.3517463) | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('foo', 'bar') == 'foo; and bar' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == {'fish_config': 'fish_config', | ||||
|                                        'fuck': 'fuck', | ||||
|                                        'funced': 'funced', | ||||
|                                        'funcsave': 'funcsave', | ||||
|                                        'history': 'history', | ||||
|                                        'll': 'll', | ||||
|                                        'math': 'math', | ||||
|                                        'popd': 'popd', | ||||
|                                        'pushd': 'pushd', | ||||
|                                        'ruby': 'ruby'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'function fuck' in shell.app_alias('fuck') | ||||
|         assert 'function FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines(['- cmd: ls', '  when: 1432613911', | ||||
|                        '- cmd: rm', '  when: 1432613916']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('isfile') | ||||
| class TestZsh(object): | ||||
|     @pytest.fixture | ||||
|     def shell(self): | ||||
|         return shells.Zsh() | ||||
|  | ||||
|     @pytest.fixture(autouse=True) | ||||
|     def Popen(self, mocker): | ||||
|         mock = mocker.patch('thefuck.shells.Popen') | ||||
|         mock.return_value.stdout.read.return_value = ( | ||||
|             b'fuck=\'eval $(thefuck $(fc -ln -1 | tail -n 1))\'\n' | ||||
|             b'l=\'ls -CF\'\n' | ||||
|             b'la=\'ls -A\'\n' | ||||
|             b'll=\'ls -alF\'') | ||||
|         return mock | ||||
|  | ||||
|     @pytest.mark.parametrize('before, after', [ | ||||
|         ('fuck', 'eval $(thefuck $(fc -ln -1 | tail -n 1))'), | ||||
|         ('pwd', 'pwd'), | ||||
|         ('ll', 'ls -alF')]) | ||||
|     def test_from_shell(self, before, after, shell): | ||||
|         assert shell.from_shell(before) == after | ||||
|  | ||||
|     def test_to_shell(self, shell): | ||||
|         assert shell.to_shell('pwd') == 'pwd' | ||||
|  | ||||
|     @pytest.mark.parametrize('entry, entry_utf8', [ | ||||
|         ('ls', ': 1430707243:0;ls\n'), | ||||
|         (u'echo café', ': 1430707243:0;echo café\n')]) | ||||
|     def test_put_to_history(self, entry, entry_utf8, builtins_open, mocker, shell): | ||||
|         mocker.patch('thefuck.shells.time', | ||||
|                      return_value=1430707243.3517463) | ||||
|         shell.put_to_history(entry) | ||||
|         builtins_open.return_value.__enter__.return_value. \ | ||||
|             write.assert_called_once_with(entry_utf8) | ||||
|  | ||||
|     def test_and_(self, shell): | ||||
|         assert shell.and_('ls', 'cd') == 'ls && cd' | ||||
|  | ||||
|     def test_get_aliases(self, shell): | ||||
|         assert shell.get_aliases() == { | ||||
|             'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))', | ||||
|             'l': 'ls -CF', | ||||
|             'la': 'ls -A', | ||||
|             'll': 'ls -alF'} | ||||
|  | ||||
|     def test_app_alias(self, shell): | ||||
|         assert 'alias fuck' in shell.app_alias('fuck') | ||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||
|         assert 'thefuck' in shell.app_alias('fuck') | ||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||
|  | ||||
|     def test_get_history(self, history_lines, shell): | ||||
|         history_lines([': 1432613911:0;ls', ': 1432613916:0;rm']) | ||||
|         assert list(shell.get_history()) == ['ls', 'rm'] | ||||
| @@ -1,334 +0,0 @@ | ||||
| """Module with shell specific actions, each shell class should | ||||
| implement `from_shell`, `to_shell`, `app_alias`, `put_to_history` and | ||||
| `get_aliases` methods. | ||||
|  | ||||
| """ | ||||
| from collections import defaultdict | ||||
| from psutil import Process | ||||
| from subprocess import Popen, PIPE | ||||
| from time import time | ||||
| import io | ||||
| import os | ||||
| import shlex | ||||
| import sys | ||||
| import six | ||||
| from .utils import DEVNULL, memoize, cache | ||||
| from .conf import settings | ||||
| from . import logs | ||||
|  | ||||
|  | ||||
| class Generic(object): | ||||
|     def get_aliases(self): | ||||
|         return {} | ||||
|  | ||||
|     def _expand_aliases(self, command_script): | ||||
|         aliases = self.get_aliases() | ||||
|         binary = command_script.split(' ')[0] | ||||
|         if binary in aliases: | ||||
|             return command_script.replace(binary, aliases[binary], 1) | ||||
|         else: | ||||
|             return command_script | ||||
|  | ||||
|     def from_shell(self, command_script): | ||||
|         """Prepares command before running in app.""" | ||||
|         return self._expand_aliases(command_script) | ||||
|  | ||||
|     def to_shell(self, command_script): | ||||
|         """Prepares command for running in shell.""" | ||||
|         return command_script | ||||
|  | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval $(TF_ALIAS={0} PYTHONIOENCODING=utf-8 " \ | ||||
|                "thefuck $(fc -ln -1))'".format(fuck) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return '' | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return '' | ||||
|  | ||||
|     def put_to_history(self, command_script): | ||||
|         """Puts command script to shell history.""" | ||||
|         history_file_name = self._get_history_file_name() | ||||
|         if os.path.isfile(history_file_name): | ||||
|             with open(history_file_name, 'a') as history: | ||||
|                 entry = self._get_history_line(command_script) | ||||
|                 if six.PY2: | ||||
|                     history.write(entry.encode('utf-8')) | ||||
|                 else: | ||||
|                     history.write(entry) | ||||
|  | ||||
|     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_file: | ||||
|  | ||||
|                 lines = history_file.readlines() | ||||
|                 if settings.history_limit: | ||||
|                     lines = lines[-settings.history_limit:] | ||||
|  | ||||
|                 for line in lines: | ||||
|                     prepared = self._script_from_history(line) \ | ||||
|                         .strip() | ||||
|                     if prepared: | ||||
|                         yield prepared | ||||
|  | ||||
|     def and_(self, *commands): | ||||
|         return u' && '.join(commands) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return | ||||
|  | ||||
|     def split_command(self, command): | ||||
|         """Split the command using shell-like syntax.""" | ||||
|         if six.PY2: | ||||
|             return [s.decode('utf8') for s in shlex.split(command.encode('utf8'))] | ||||
|         return shlex.split(command) | ||||
|  | ||||
|     def quote(self, s): | ||||
|         """Return a shell-escaped version of the string s.""" | ||||
|  | ||||
|         if six.PY2: | ||||
|             from pipes import quote | ||||
|         else: | ||||
|             from shlex import quote | ||||
|  | ||||
|         return quote(s) | ||||
|  | ||||
|     def _script_from_history(self, line): | ||||
|         return line | ||||
|  | ||||
|  | ||||
| class Bash(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval " \ | ||||
|                "$(TF_ALIAS={0} PYTHONIOENCODING=utf-8 thefuck $(fc -ln -1));" \ | ||||
|                " history -r'".format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.replace('alias ', '', 1).split('=', 1) | ||||
|         if value[0] == value[-1] == '"' or value[0] == value[-1] == "'": | ||||
|             value = value[1:-1] | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.bashrc', '.bash_profile') | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['bash', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '=' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.bash_history')) | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'{}\n'.format(command_script) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         if os.path.join(os.path.expanduser('~'), '.bashrc'): | ||||
|             config = '~/.bashrc' | ||||
|         elif os.path.join(os.path.expanduser('~'), '.bash_profile'): | ||||
|             config = '~/.bashrc' | ||||
|         else: | ||||
|             config = 'bash config' | ||||
|         return 'eval $(thefuck --alias)', config | ||||
|  | ||||
|  | ||||
| class Fish(Generic): | ||||
|     def _get_overridden_aliases(self): | ||||
|         overridden_aliases = os.environ.get('TF_OVERRIDDEN_ALIASES', '').strip() | ||||
|         if overridden_aliases: | ||||
|             return [alias.strip() for alias in overridden_aliases.split(',')] | ||||
|         else: | ||||
|             return ['cd', 'grep', 'ls', 'man', 'open'] | ||||
|  | ||||
|     def app_alias(self, fuck): | ||||
|         return ('function {0} -d "Correct your previous console command"\n' | ||||
|                 '  set -l exit_code $status\n' | ||||
|                 '  set -l fucked_up_command $history[1]\n' | ||||
|                 '  env TF_ALIAS={0} PYTHONIOENCODING=utf-8' | ||||
|                 ' thefuck $fucked_up_command | read -l unfucked_command\n' | ||||
|                 '  if [ "$unfucked_command" != "" ]\n' | ||||
|                 '    eval $unfucked_command\n' | ||||
|                 '    if test $exit_code -ne 0\n' | ||||
|                 '      history --delete $fucked_up_command\n' | ||||
|                 '      history --merge ^ /dev/null\n' | ||||
|                 '      return 0\n' | ||||
|                 '    end\n' | ||||
|                 '  end\n' | ||||
|                 'end').format(fuck) | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.config/fish/config.fish', '.config/fish/functions') | ||||
|     def get_aliases(self): | ||||
|         overridden = self._get_overridden_aliases() | ||||
|         proc = Popen(['fish', '-ic', 'functions'], stdout=PIPE, stderr=DEVNULL) | ||||
|         functions = proc.stdout.read().decode('utf-8').strip().split('\n') | ||||
|         return {func: func for func in functions if func not in overridden} | ||||
|  | ||||
|     def _expand_aliases(self, command_script): | ||||
|         aliases = self.get_aliases() | ||||
|         binary = command_script.split(' ')[0] | ||||
|         if binary in aliases: | ||||
|             return u'fish -ic "{}"'.format(command_script.replace('"', r'\"')) | ||||
|         else: | ||||
|             return command_script | ||||
|  | ||||
|     def from_shell(self, command_script): | ||||
|         """Prepares command before running in app.""" | ||||
|         return self._expand_aliases(command_script) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.path.expanduser('~/.config/fish/fish_history') | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'- cmd: {}\n   when: {}\n'.format(command_script, int(time())) | ||||
|  | ||||
|     def _script_from_history(self, line): | ||||
|         if '- cmd: ' in line: | ||||
|             return line.split('- cmd: ', 1)[1] | ||||
|         else: | ||||
|             return '' | ||||
|  | ||||
|     def and_(self, *commands): | ||||
|         return u'; and '.join(commands) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval thefuck --alias', '~/.config/fish/config.fish' | ||||
|  | ||||
|  | ||||
| class Zsh(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval $(TF_ALIAS={0} PYTHONIOENCODING=utf-8" \ | ||||
|                " thefuck $(fc -ln -1 | tail -n 1));" \ | ||||
|                " fc -R'".format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.split('=', 1) | ||||
|         if value[0] == value[-1] == '"' or value[0] == value[-1] == "'": | ||||
|             value = value[1:-1] | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.zshrc') | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['zsh', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '=' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.zsh_history')) | ||||
|  | ||||
|     def _get_history_line(self, 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 '' | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval $(thefuck --alias)', '~/.zshrc' | ||||
|  | ||||
|  | ||||
| class Tcsh(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return ("alias {0} 'setenv TF_ALIAS {0} && " | ||||
|                 "set fucked_cmd=`history -h 2 | head -n 1` && " | ||||
|                 "eval `thefuck ${{fucked_cmd}}`'").format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.split("\t", 1) | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['tcsh', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '\t' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.history')) | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'#+{}\n{}\n'.format(int(time()), command_script) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval `thefuck --alias`', '~/.tcshrc' | ||||
|  | ||||
|  | ||||
| shells = defaultdict(Generic, { | ||||
|     'bash': Bash(), | ||||
|     'fish': Fish(), | ||||
|     'zsh': Zsh(), | ||||
|     'csh': Tcsh(), | ||||
|     'tcsh': Tcsh()}) | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def _get_shell(): | ||||
|     try: | ||||
|         shell = Process(os.getpid()).parent().name() | ||||
|     except TypeError: | ||||
|         shell = Process(os.getpid()).parent.name | ||||
|     return shells[shell] | ||||
|  | ||||
|  | ||||
| def from_shell(command): | ||||
|     return _get_shell().from_shell(command) | ||||
|  | ||||
|  | ||||
| def to_shell(command): | ||||
|     return _get_shell().to_shell(command) | ||||
|  | ||||
|  | ||||
| def app_alias(alias): | ||||
|     return _get_shell().app_alias(alias) | ||||
|  | ||||
|  | ||||
| def thefuck_alias(): | ||||
|     return os.environ.get('TF_ALIAS', 'fuck') | ||||
|  | ||||
|  | ||||
| def put_to_history(command): | ||||
|     try: | ||||
|         return _get_shell().put_to_history(command) | ||||
|     except IOError: | ||||
|         logs.exception("Can't update history", sys.exc_info()) | ||||
|  | ||||
|  | ||||
| def and_(*commands): | ||||
|     return _get_shell().and_(*commands) | ||||
|  | ||||
|  | ||||
| def get_aliases(): | ||||
|     return list(_get_shell().get_aliases().keys()) | ||||
|  | ||||
|  | ||||
| def split_command(command): | ||||
|     return _get_shell().split_command(command) | ||||
|  | ||||
|  | ||||
| def quote(s): | ||||
|     return _get_shell().quote(s) | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def get_history(): | ||||
|     return list(_get_shell().get_history()) | ||||
|  | ||||
|  | ||||
| def how_to_configure(): | ||||
|     return _get_shell().how_to_configure() | ||||
							
								
								
									
										75
									
								
								thefuck/shells/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								thefuck/shells/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| from collections import defaultdict | ||||
| from psutil import Process | ||||
| import os | ||||
| import sys | ||||
| from ..utils import memoize | ||||
| from .. import logs | ||||
| from .bash import Bash | ||||
| from .fish import Fish | ||||
| from .generic import Generic | ||||
| from .tcsh import Tcsh | ||||
| from .zsh import Zsh | ||||
|  | ||||
| shells = defaultdict(Generic, | ||||
|                      bash=Bash(), | ||||
|                      fish=Fish(), | ||||
|                      zsh=Zsh(), | ||||
|                      csh=Tcsh(), | ||||
|                      tcsh=Tcsh()) | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def _get_shell(): | ||||
|     try: | ||||
|         shell = Process(os.getpid()).parent().name() | ||||
|     except TypeError: | ||||
|         shell = Process(os.getpid()).parent.name | ||||
|     return shells[shell] | ||||
|  | ||||
|  | ||||
| def from_shell(command): | ||||
|     return _get_shell().from_shell(command) | ||||
|  | ||||
|  | ||||
| def to_shell(command): | ||||
|     return _get_shell().to_shell(command) | ||||
|  | ||||
|  | ||||
| def app_alias(alias): | ||||
|     return _get_shell().app_alias(alias) | ||||
|  | ||||
|  | ||||
| def thefuck_alias(): | ||||
|     return os.environ.get('TF_ALIAS', 'fuck') | ||||
|  | ||||
|  | ||||
| def put_to_history(command): | ||||
|     try: | ||||
|         return _get_shell().put_to_history(command) | ||||
|     except IOError: | ||||
|         logs.exception("Can't update history", sys.exc_info()) | ||||
|  | ||||
|  | ||||
| def and_(*commands): | ||||
|     return _get_shell().and_(*commands) | ||||
|  | ||||
|  | ||||
| def get_aliases(): | ||||
|     return list(_get_shell().get_aliases().keys()) | ||||
|  | ||||
|  | ||||
| def split_command(command): | ||||
|     return _get_shell().split_command(command) | ||||
|  | ||||
|  | ||||
| def quote(s): | ||||
|     return _get_shell().quote(s) | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def get_history(): | ||||
|     return list(_get_shell().get_history()) | ||||
|  | ||||
|  | ||||
| def how_to_configure(): | ||||
|     return _get_shell().how_to_configure() | ||||
							
								
								
									
										42
									
								
								thefuck/shells/bash.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								thefuck/shells/bash.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| from subprocess import Popen, PIPE | ||||
| import os | ||||
| from ..utils import DEVNULL, memoize, cache | ||||
| from .generic import Generic | ||||
|  | ||||
|  | ||||
| class Bash(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval " \ | ||||
|                "$(TF_ALIAS={0} PYTHONIOENCODING=utf-8 thefuck $(fc -ln -1));" \ | ||||
|                " history -r'".format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.replace('alias ', '', 1).split('=', 1) | ||||
|         if value[0] == value[-1] == '"' or value[0] == value[-1] == "'": | ||||
|             value = value[1:-1] | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.bashrc', '.bash_profile') | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['bash', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '=' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.bash_history')) | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'{}\n'.format(command_script) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         if os.path.join(os.path.expanduser('~'), '.bashrc'): | ||||
|             config = '~/.bashrc' | ||||
|         elif os.path.join(os.path.expanduser('~'), '.bash_profile'): | ||||
|             config = '~/.bashrc' | ||||
|         else: | ||||
|             config = 'bash config' | ||||
|         return 'eval $(thefuck --alias)', config | ||||
							
								
								
									
										68
									
								
								thefuck/shells/fish.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								thefuck/shells/fish.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| from subprocess import Popen, PIPE | ||||
| from time import time | ||||
| import os | ||||
| from ..utils import DEVNULL, memoize, cache | ||||
| from .generic import Generic | ||||
|  | ||||
|  | ||||
| class Fish(Generic): | ||||
|     def _get_overridden_aliases(self): | ||||
|         overridden_aliases = os.environ.get('TF_OVERRIDDEN_ALIASES', '').strip() | ||||
|         if overridden_aliases: | ||||
|             return [alias.strip() for alias in overridden_aliases.split(',')] | ||||
|         else: | ||||
|             return ['cd', 'grep', 'ls', 'man', 'open'] | ||||
|  | ||||
|     def app_alias(self, fuck): | ||||
|         return ('function {0} -d "Correct your previous console command"\n' | ||||
|                 '  set -l exit_code $status\n' | ||||
|                 '  set -l fucked_up_command $history[1]\n' | ||||
|                 '  env TF_ALIAS={0} PYTHONIOENCODING=utf-8' | ||||
|                 ' thefuck $fucked_up_command | read -l unfucked_command\n' | ||||
|                 '  if [ "$unfucked_command" != "" ]\n' | ||||
|                 '    eval $unfucked_command\n' | ||||
|                 '    if test $exit_code -ne 0\n' | ||||
|                 '      history --delete $fucked_up_command\n' | ||||
|                 '      history --merge ^ /dev/null\n' | ||||
|                 '      return 0\n' | ||||
|                 '    end\n' | ||||
|                 '  end\n' | ||||
|                 'end').format(fuck) | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.config/fish/config.fish', '.config/fish/functions') | ||||
|     def get_aliases(self): | ||||
|         overridden = self._get_overridden_aliases() | ||||
|         proc = Popen(['fish', '-ic', 'functions'], stdout=PIPE, stderr=DEVNULL) | ||||
|         functions = proc.stdout.read().decode('utf-8').strip().split('\n') | ||||
|         return {func: func for func in functions if func not in overridden} | ||||
|  | ||||
|     def _expand_aliases(self, command_script): | ||||
|         aliases = self.get_aliases() | ||||
|         binary = command_script.split(' ')[0] | ||||
|         if binary in aliases: | ||||
|             return u'fish -ic "{}"'.format(command_script.replace('"', r'\"')) | ||||
|         else: | ||||
|             return command_script | ||||
|  | ||||
|     def from_shell(self, command_script): | ||||
|         """Prepares command before running in app.""" | ||||
|         return self._expand_aliases(command_script) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.path.expanduser('~/.config/fish/fish_history') | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'- cmd: {}\n   when: {}\n'.format(command_script, int(time())) | ||||
|  | ||||
|     def _script_from_history(self, line): | ||||
|         if '- cmd: ' in line: | ||||
|             return line.split('- cmd: ', 1)[1] | ||||
|         else: | ||||
|             return '' | ||||
|  | ||||
|     def and_(self, *commands): | ||||
|         return u'; and '.join(commands) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval thefuck --alias', '~/.config/fish/config.fish' | ||||
							
								
								
									
										89
									
								
								thefuck/shells/generic.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								thefuck/shells/generic.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| import io | ||||
| import os | ||||
| import shlex | ||||
| import six | ||||
| from ..conf import settings | ||||
|  | ||||
|  | ||||
| class Generic(object): | ||||
|     def get_aliases(self): | ||||
|         return {} | ||||
|  | ||||
|     def _expand_aliases(self, command_script): | ||||
|         aliases = self.get_aliases() | ||||
|         binary = command_script.split(' ')[0] | ||||
|         if binary in aliases: | ||||
|             return command_script.replace(binary, aliases[binary], 1) | ||||
|         else: | ||||
|             return command_script | ||||
|  | ||||
|     def from_shell(self, command_script): | ||||
|         """Prepares command before running in app.""" | ||||
|         return self._expand_aliases(command_script) | ||||
|  | ||||
|     def to_shell(self, command_script): | ||||
|         """Prepares command for running in shell.""" | ||||
|         return command_script | ||||
|  | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval $(TF_ALIAS={0} PYTHONIOENCODING=utf-8 " \ | ||||
|                "thefuck $(fc -ln -1))'".format(fuck) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return '' | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return '' | ||||
|  | ||||
|     def put_to_history(self, command_script): | ||||
|         """Puts command script to shell history.""" | ||||
|         history_file_name = self._get_history_file_name() | ||||
|         if os.path.isfile(history_file_name): | ||||
|             with open(history_file_name, 'a') as history: | ||||
|                 entry = self._get_history_line(command_script) | ||||
|                 if six.PY2: | ||||
|                     history.write(entry.encode('utf-8')) | ||||
|                 else: | ||||
|                     history.write(entry) | ||||
|  | ||||
|     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_file: | ||||
|  | ||||
|                 lines = history_file.readlines() | ||||
|                 if settings.history_limit: | ||||
|                     lines = lines[-settings.history_limit:] | ||||
|  | ||||
|                 for line in lines: | ||||
|                     prepared = self._script_from_history(line) \ | ||||
|                         .strip() | ||||
|                     if prepared: | ||||
|                         yield prepared | ||||
|  | ||||
|     def and_(self, *commands): | ||||
|         return u' && '.join(commands) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return | ||||
|  | ||||
|     def split_command(self, command): | ||||
|         """Split the command using shell-like syntax.""" | ||||
|         if six.PY2: | ||||
|             return [s.decode('utf8') for s in shlex.split(command.encode('utf8'))] | ||||
|         return shlex.split(command) | ||||
|  | ||||
|     def quote(self, s): | ||||
|         """Return a shell-escaped version of the string s.""" | ||||
|  | ||||
|         if six.PY2: | ||||
|             from pipes import quote | ||||
|         else: | ||||
|             from shlex import quote | ||||
|  | ||||
|         return quote(s) | ||||
|  | ||||
|     def _script_from_history(self, line): | ||||
|         return line | ||||
							
								
								
									
										34
									
								
								thefuck/shells/tcsh.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								thefuck/shells/tcsh.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| from subprocess import Popen, PIPE | ||||
| from time import time | ||||
| import os | ||||
| from ..utils import DEVNULL, memoize | ||||
| from .generic import Generic | ||||
|  | ||||
|  | ||||
| class Tcsh(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return ("alias {0} 'setenv TF_ALIAS {0} && " | ||||
|                 "set fucked_cmd=`history -h 2 | head -n 1` && " | ||||
|                 "eval `thefuck ${{fucked_cmd}}`'").format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.split("\t", 1) | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['tcsh', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '\t' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.history')) | ||||
|  | ||||
|     def _get_history_line(self, command_script): | ||||
|         return u'#+{}\n{}\n'.format(int(time()), command_script) | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval `thefuck --alias`', '~/.tcshrc' | ||||
							
								
								
									
										43
									
								
								thefuck/shells/zsh.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								thefuck/shells/zsh.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| from subprocess import Popen, PIPE | ||||
| from time import time | ||||
| import os | ||||
| from ..utils import DEVNULL, memoize, cache | ||||
| from .generic import Generic | ||||
|  | ||||
|  | ||||
| class Zsh(Generic): | ||||
|     def app_alias(self, fuck): | ||||
|         return "alias {0}='eval $(TF_ALIAS={0} PYTHONIOENCODING=utf-8" \ | ||||
|                " thefuck $(fc -ln -1 | tail -n 1));" \ | ||||
|                " fc -R'".format(fuck) | ||||
|  | ||||
|     def _parse_alias(self, alias): | ||||
|         name, value = alias.split('=', 1) | ||||
|         if value[0] == value[-1] == '"' or value[0] == value[-1] == "'": | ||||
|             value = value[1:-1] | ||||
|         return name, value | ||||
|  | ||||
|     @memoize | ||||
|     @cache('.zshrc') | ||||
|     def get_aliases(self): | ||||
|         proc = Popen(['zsh', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||
|         return dict( | ||||
|                 self._parse_alias(alias) | ||||
|                 for alias in proc.stdout.read().decode('utf-8').split('\n') | ||||
|                 if alias and '=' in alias) | ||||
|  | ||||
|     def _get_history_file_name(self): | ||||
|         return os.environ.get("HISTFILE", | ||||
|                               os.path.expanduser('~/.zsh_history')) | ||||
|  | ||||
|     def _get_history_line(self, 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 '' | ||||
|  | ||||
|     def how_to_configure(self): | ||||
|         return 'eval $(thefuck --alias)', '~/.zshrc' | ||||
		Reference in New Issue
	
	Block a user