1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-11-09 03:22:06 +00:00

Compare commits

...

15 Commits
3.17 ... 3.20

Author SHA1 Message Date
Vladimir Iakovlev
d267488520 Bump to 3.20 2017-08-16 11:28:59 +02:00
Vladimir Iakovlev
e31124335f #658: Ensure that history isn't empty in autoconfiguration 2017-08-16 11:26:43 +02:00
Vladimir Iakovlev
71a5182b9a Merge pull request #676 from nvbn/662-fix-autoconfig
#662: Autoconfigure when `fuck` was called < 60 seconds ago from the same shell
2017-08-08 17:36:10 +02:00
Vladimir Iakovlev
6a096155dc #662: Autoconfigure when fuck was called < 60 seconds ago from the same shell 2017-08-08 16:13:37 +02:00
Vladimir Iakovlev
5742d2d910 #N/A: Use real PATH in tests 2017-08-03 12:30:04 +02:00
Vladimir Iakovlev
754bb3e21f #N/A: Reset environment variables in tests 2017-08-03 12:18:05 +02:00
Vladimir Iakovlev
2bbba9a0c8 Bump to 3.19 2017-08-03 11:34:01 +02:00
Vladimir Iakovlev
b978c3793e Merge pull request #669 from tomoshi0809/master
#630 Catching the escaped space in filenames
2017-07-22 20:11:03 +02:00
KEI
8a83b30e73 Corrected the part for splitting a command 2017-07-19 00:09:21 +09:00
Vladimir Iakovlev
fd20a3f832 Merge pull request #657 from josephfrazier/git_not_command-wording
Update stderr wording of git_not_command
2017-06-19 23:12:46 +02:00
Joseph Frazier
b6ed499103 Make git_not_command stderr detection backward-compatible 2017-06-06 13:56:13 -04:00
Joseph Frazier
76600cf40a Update stderr wording of git_not_command
This changed in git v2.13.1, see
6c48686263 (diff-081cf476dd9ac3b05c183570de47cb23)
2017-06-05 17:29:42 -04:00
Vladimir Iakovlev
e62666181a #650: #651: #646: Recommend to install thefuck globally 2017-05-29 10:11:15 +02:00
Vladimir Iakovlev
c88b0792b8 Bump to 3.18 2017-05-10 16:51:19 +02:00
Vladimir Iakovlev
06a89427e2 #N/A: Fix bash alias on ci 2017-05-10 16:40:57 +02:00
18 changed files with 125 additions and 85 deletions

View File

@@ -106,13 +106,13 @@ On Ubuntu you can install `The Fuck` with:
```bash ```bash
sudo apt update sudo apt update
sudo apt install python3-dev python3-pip sudo apt install python3-dev python3-pip
pip3 install --user thefuck sudo pip3 install thefuck
``` ```
On other systems you can install `The Fuck` with `pip`: On other systems you can install `The Fuck` with `pip`:
```bash ```bash
pip install --user thefuck pip install thefuck
``` ```
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation) [Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
@@ -139,7 +139,7 @@ alias fuck-it='export THEFUCK_REQUIRE_CONFIRMATION=False; fuck; export THEFUCK_R
## Update ## Update
```bash ```bash
pip install --user thefuck --upgrade pip install thefuck --upgrade
``` ```
**Aliases changed in 1.34.** **Aliases changed in 1.34.**

View File

@@ -29,7 +29,7 @@ elif (3, 0) < version < (3, 3):
' ({}.{} detected).'.format(*version)) ' ({}.{} detected).'.format(*version))
sys.exit(-1) sys.exit(-1)
VERSION = '3.17' VERSION = '3.20'
install_requires = ['psutil', 'colorama', 'six', 'decorator'] install_requires = ['psutil', 'colorama', 'six', 'decorator']
extras_require = {':python_version<"3.4"': ['pathlib2'], extras_require = {':python_version<"3.4"': ['pathlib2'],

View File

@@ -1,3 +1,4 @@
import os
import pytest import pytest
from thefuck import shells from thefuck import shells
from thefuck import conf, const from thefuck import conf, const
@@ -56,7 +57,13 @@ def set_shell(monkeypatch, request):
def _set(cls): def _set(cls):
shell = cls() shell = cls()
monkeypatch.setattr('thefuck.shells.shell', shell) monkeypatch.setattr('thefuck.shells.shell', shell)
request.addfinalizer()
return shell return shell
return _set return _set
@pytest.fixture(autouse=True)
def os_environ(monkeypatch):
env = {'PATH': os.environ['PATH']}
monkeypatch.setattr('os.environ', env)
return env

View File

@@ -39,7 +39,6 @@ parametrize_extensions = pytest.mark.parametrize('ext', tar_extensions)
# (filename as typed by the user, unquoted filename, quoted filename as per shells.quote) # (filename as typed by the user, unquoted filename, quoted filename as per shells.quote)
parametrize_filename = pytest.mark.parametrize('filename, unquoted, quoted', [ parametrize_filename = pytest.mark.parametrize('filename, unquoted, quoted', [
('foo{}', 'foo{}', 'foo{}'), ('foo{}', 'foo{}', 'foo{}'),
('foo\ bar{}', 'foo bar{}', "'foo bar{}'"),
('"foo bar{}"', 'foo bar{}', "'foo bar{}'")]) ('"foo bar{}"', 'foo bar{}', "'foo bar{}'")])
parametrize_script = pytest.mark.parametrize('script, fixed', [ parametrize_script = pytest.mark.parametrize('script, fixed', [

View File

@@ -64,7 +64,6 @@ def test_side_effect(zip_error, script, filename):
@pytest.mark.parametrize('script,fixed,filename', [ @pytest.mark.parametrize('script,fixed,filename', [
(u'unzip café', u"unzip café -d 'café'", u'café.zip'), (u'unzip café', u"unzip café -d 'café'", u'café.zip'),
(u'unzip foo', u'unzip foo -d foo', u'foo.zip'), (u'unzip foo', u'unzip foo -d foo', u'foo.zip'),
(u"unzip foo\\ bar.zip", u"unzip foo\\ bar.zip -d 'foo bar'", u'foo.zip'),
(u"unzip 'foo bar.zip'", u"unzip 'foo bar.zip' -d 'foo bar'", u'foo.zip'), (u"unzip 'foo bar.zip'", u"unzip 'foo bar.zip' -d 'foo bar'", u'foo.zip'),
(u'unzip foo.zip', u'unzip foo.zip -d foo', u'foo.zip')]) (u'unzip foo.zip', u'unzip foo.zip -d foo', u'foo.zip')])
def test_get_new_command(zip_error, script, fixed, filename): def test_get_new_command(zip_error, script, fixed, filename):

View File

@@ -7,7 +7,7 @@ from tests.utils import Command
def git_not_command(): def git_not_command():
return """git: 'brnch' is not a git command. See 'git --help'. return """git: 'brnch' is not a git command. See 'git --help'.
Did you mean this? The most similar command is
branch branch
""" """
@@ -16,7 +16,7 @@ branch
def git_not_command_one_of_this(): def git_not_command_one_of_this():
return """git: 'st' is not a git command. See 'git --help'. return """git: 'st' is not a git command. See 'git --help'.
Did you mean one of these? The most similar commands are
status status
reset reset
stage stage
@@ -29,7 +29,7 @@ stats
def git_not_command_closest(): def git_not_command_closest():
return '''git: 'tags' is not a git command. See 'git --help'. return '''git: 'tags' is not a git command. See 'git --help'.
Did you mean one of these? The most similar commands are
\tstage \tstage
\ttag \ttag
''' '''

View File

@@ -50,8 +50,8 @@ def test_match(command):
assert match(command) assert match(command)
@pytest.mark.parametrize('command, new_command', [ @pytest.mark.parametrize('command, url', [
(Command('yarn help clean', stdout=stdout_clean), (Command('yarn help clean', stdout=stdout_clean),
open_command('https://yarnpkg.com/en/docs/cli/clean'))]) 'https://yarnpkg.com/en/docs/cli/clean')])
def test_get_new_command(command, new_command): def test_get_new_command(command, url):
assert get_new_command(command) == new_command assert get_new_command(command) == open_command(url)

View File

@@ -18,17 +18,14 @@ class TestFish(object):
b'man\nmath\npopd\npushd\nruby') b'man\nmath\npopd\npushd\nruby')
return mock return mock
@pytest.fixture
def os_environ(self, monkeypatch, key, value):
monkeypatch.setattr('os.environ', {key: value})
@pytest.mark.parametrize('key, value', [ @pytest.mark.parametrize('key, value', [
('TF_OVERRIDDEN_ALIASES', 'cut,git,sed'), # legacy ('TF_OVERRIDDEN_ALIASES', 'cut,git,sed'), # legacy
('THEFUCK_OVERRIDDEN_ALIASES', 'cut,git,sed'), ('THEFUCK_OVERRIDDEN_ALIASES', 'cut,git,sed'),
('THEFUCK_OVERRIDDEN_ALIASES', 'cut, git, sed'), ('THEFUCK_OVERRIDDEN_ALIASES', 'cut, git, sed'),
('THEFUCK_OVERRIDDEN_ALIASES', ' cut,\tgit,sed\n'), ('THEFUCK_OVERRIDDEN_ALIASES', ' cut,\tgit,sed\n'),
('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')]) ('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
def test_get_overridden_aliases(self, shell, os_environ): def test_get_overridden_aliases(self, shell, os_environ, key, value):
os_environ[key] = value
assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep', assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep',
'ls', 'man', 'open', 'sed'} 'ls', 'man', 'open', 'sed'}

View File

@@ -10,14 +10,6 @@ def load_source(mocker):
return mocker.patch('thefuck.conf.load_source') return mocker.patch('thefuck.conf.load_source')
@pytest.fixture
def environ(monkeypatch):
data = {}
monkeypatch.setattr('thefuck.conf.os.environ', data)
return data
@pytest.mark.usefixture('environ')
def test_settings_defaults(load_source, settings): def test_settings_defaults(load_source, settings):
load_source.return_value = object() load_source.return_value = object()
settings.init() settings.init()
@@ -25,7 +17,6 @@ def test_settings_defaults(load_source, settings):
assert getattr(settings, key) == val assert getattr(settings, key) == val
@pytest.mark.usefixture('environ')
class TestSettingsFromFile(object): class TestSettingsFromFile(object):
def test_from_file(self, load_source, settings): def test_from_file(self, load_source, settings):
load_source.return_value = Mock(rules=['test'], load_source.return_value = Mock(rules=['test'],
@@ -54,15 +45,15 @@ class TestSettingsFromFile(object):
@pytest.mark.usefixture('load_source') @pytest.mark.usefixture('load_source')
class TestSettingsFromEnv(object): class TestSettingsFromEnv(object):
def test_from_env(self, environ, settings): def test_from_env(self, os_environ, settings):
environ.update({'THEFUCK_RULES': 'bash:lisp', os_environ.update({'THEFUCK_RULES': 'bash:lisp',
'THEFUCK_EXCLUDE_RULES': 'git:vim', 'THEFUCK_EXCLUDE_RULES': 'git:vim',
'THEFUCK_WAIT_COMMAND': '55', 'THEFUCK_WAIT_COMMAND': '55',
'THEFUCK_REQUIRE_CONFIRMATION': 'true', 'THEFUCK_REQUIRE_CONFIRMATION': 'true',
'THEFUCK_NO_COLORS': 'false', 'THEFUCK_NO_COLORS': 'false',
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15', 'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
'THEFUCK_WAIT_SLOW_COMMAND': '999', 'THEFUCK_WAIT_SLOW_COMMAND': '999',
'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'}) 'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
settings.init() settings.init()
assert settings.rules == ['bash', 'lisp'] assert settings.rules == ['bash', 'lisp']
assert settings.exclude_rules == ['git', 'vim'] assert settings.exclude_rules == ['git', 'vim']
@@ -73,8 +64,8 @@ class TestSettingsFromEnv(object):
assert settings.wait_slow_command == 999 assert settings.wait_slow_command == 999
assert settings.slow_commands == ['lein', 'react-native', './gradlew'] assert settings.slow_commands == ['lein', 'react-native', './gradlew']
def test_from_env_with_DEFAULT(self, environ, settings): def test_from_env_with_DEFAULT(self, os_environ, settings):
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'}) os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
settings.init() settings.init()
assert settings.rules == const.DEFAULT_RULES + ['bash', 'lisp'] assert settings.rules == const.DEFAULT_RULES + ['bash', 'lisp']
@@ -116,15 +107,15 @@ class TestInitializeSettingsFile(object):
(False, '/user/test/config/', '/user/test/config/thefuck'), (False, '/user/test/config/', '/user/test/config/thefuck'),
(True, '~/.config', '~/.thefuck'), (True, '~/.config', '~/.thefuck'),
(True, '/user/test/config/', '~/.thefuck')]) (True, '/user/test/config/', '~/.thefuck')])
def test_get_user_dir_path(mocker, environ, settings, legacy_dir_exists, def test_get_user_dir_path(mocker, os_environ, settings, legacy_dir_exists,
xdg_config_home, result): xdg_config_home, result):
mocker.patch('thefuck.conf.Path.is_dir', mocker.patch('thefuck.conf.Path.is_dir',
return_value=legacy_dir_exists) return_value=legacy_dir_exists)
if xdg_config_home is not None: if xdg_config_home is not None:
environ['XDG_CONFIG_HOME'] = xdg_config_home os_environ['XDG_CONFIG_HOME'] = xdg_config_home
else: else:
environ.pop('XDG_CONFIG_HOME', None) os_environ.pop('XDG_CONFIG_HOME', None)
path = settings._get_user_dir_path().as_posix() path = settings._get_user_dir_path().as_posix()
assert path == os.path.expanduser(result) assert path == os.path.expanduser(result)

View File

@@ -1,4 +1,6 @@
import pytest import pytest
import json
from six import StringIO
from mock import MagicMock from mock import MagicMock
from thefuck.shells.generic import ShellConfiguration from thefuck.shells.generic import ShellConfiguration
from thefuck.not_configured import main from thefuck.not_configured import main
@@ -11,19 +13,33 @@ def usage_tracker(mocker):
new_callable=MagicMock) new_callable=MagicMock)
def _assert_tracker_updated(usage_tracker, pid): @pytest.fixture(autouse=True)
def usage_tracker_io(usage_tracker):
io = StringIO()
usage_tracker.return_value \ usage_tracker.return_value \
.open.return_value \ .open.return_value \
.__enter__.return_value \ .__enter__.return_value = io
.write.assert_called_once_with(str(pid)) return io
def _change_tracker(usage_tracker, pid): @pytest.fixture(autouse=True)
usage_tracker.return_value.exists.return_value = True def usage_tracker_exists(usage_tracker):
usage_tracker.return_value \ usage_tracker.return_value \
.open.return_value \ .exists.return_value = True
.__enter__.return_value \ return usage_tracker.return_value.exists
.read.return_value = str(pid)
def _assert_tracker_updated(usage_tracker_io, pid):
usage_tracker_io.seek(0)
info = json.load(usage_tracker_io)
assert info['pid'] == pid
def _change_tracker(usage_tracker_io, pid):
usage_tracker_io.truncate(0)
info = {'pid': pid, 'time': 0}
json.dump(info, usage_tracker_io)
usage_tracker_io.seek(0)
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@@ -67,29 +83,28 @@ def test_for_generic_shell(shell, logs):
logs.how_to_configure_alias.assert_called_once() logs.how_to_configure_alias.assert_called_once()
def test_on_first_run(usage_tracker, shell_pid, logs): def test_on_first_run(usage_tracker_io, usage_tracker_exists, shell_pid, logs):
shell_pid.return_value = 12 shell_pid.return_value = 12
usage_tracker.return_value.exists.return_value = False
main() main()
_assert_tracker_updated(usage_tracker, 12) usage_tracker_exists.return_value = False
_assert_tracker_updated(usage_tracker_io, 12)
logs.how_to_configure_alias.assert_called_once() logs.how_to_configure_alias.assert_called_once()
def test_on_run_after_other_commands(usage_tracker, shell_pid, shell, logs): def test_on_run_after_other_commands(usage_tracker_io, shell_pid, shell, logs):
shell_pid.return_value = 12 shell_pid.return_value = 12
shell.get_history.return_value = ['fuck', 'ls'] shell.get_history.return_value = ['fuck', 'ls']
_change_tracker(usage_tracker, 12) _change_tracker(usage_tracker_io, 12)
main() main()
logs.how_to_configure_alias.assert_called_once() logs.how_to_configure_alias.assert_called_once()
def test_on_first_run_from_current_shell(usage_tracker, shell_pid, def test_on_first_run_from_current_shell(usage_tracker_io, shell_pid,
shell, logs): shell, logs):
shell.get_history.return_value = ['fuck'] shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12 shell_pid.return_value = 12
_change_tracker(usage_tracker, 55)
main() main()
_assert_tracker_updated(usage_tracker, 12) _assert_tracker_updated(usage_tracker_io, 12)
logs.how_to_configure_alias.assert_called_once() logs.how_to_configure_alias.assert_called_once()
@@ -104,21 +119,21 @@ def test_when_cant_configure_automatically(shell_pid, shell, logs):
logs.how_to_configure_alias.assert_called_once() logs.how_to_configure_alias.assert_called_once()
def test_when_already_configured(usage_tracker, shell_pid, def test_when_already_configured(usage_tracker_io, shell_pid,
shell, shell_config, logs): shell, shell_config, logs):
shell.get_history.return_value = ['fuck'] shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12 shell_pid.return_value = 12
_change_tracker(usage_tracker, 12) _change_tracker(usage_tracker_io, 12)
shell_config.read.return_value = 'eval $(thefuck --alias)' shell_config.read.return_value = 'eval $(thefuck --alias)'
main() main()
logs.already_configured.assert_called_once() logs.already_configured.assert_called_once()
def test_when_successfuly_configured(usage_tracker, shell_pid, def test_when_successfully_configured(usage_tracker_io, shell_pid,
shell, shell_config, logs): shell, shell_config, logs):
shell.get_history.return_value = ['fuck'] shell.get_history.return_value = ['fuck']
shell_pid.return_value = 12 shell_pid.return_value = 12
_change_tracker(usage_tracker, 12) _change_tracker(usage_tracker_io, 12)
shell_config.read.return_value = '' shell_config.read.return_value = ''
main() main()
shell_config.write.assert_any_call('eval $(thefuck --alias)') shell_config.write.assert_any_call('eval $(thefuck --alias)')

View File

@@ -115,11 +115,10 @@ class TestCommand(object):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def prepare(self, monkeypatch): def prepare(self, monkeypatch):
monkeypatch.setattr('thefuck.types.os.environ', {})
monkeypatch.setattr('thefuck.types.Command._wait_output', monkeypatch.setattr('thefuck.types.Command._wait_output',
staticmethod(lambda *_: True)) staticmethod(lambda *_: True))
def test_from_script_calls(self, Popen, settings): def test_from_script_calls(self, Popen, settings, os_environ):
settings.env = {} settings.env = {}
assert Command.from_raw_script( assert Command.from_raw_script(
['apt-get', 'search', 'vim']) == Command( ['apt-get', 'search', 'vim']) == Command(
@@ -129,7 +128,7 @@ class TestCommand(object):
stdin=PIPE, stdin=PIPE,
stdout=PIPE, stdout=PIPE,
stderr=PIPE, stderr=PIPE,
env={}) env=os_environ)
@pytest.mark.parametrize('script, result', [ @pytest.mark.parametrize('script, result', [
([''], None), ([''], None),

View File

@@ -206,8 +206,7 @@ class TestGetValidHistoryWithoutCurrent(object):
return_value='fuck') return_value='fuck')
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def bins(self, mocker, monkeypatch): def bins(self, mocker):
monkeypatch.setattr('thefuck.conf.os.environ', {'PATH': 'path'})
callables = list() callables = list()
for name in ['diff', 'ls', 'café']: for name in ['diff', 'ls', 'café']:
bin_mock = mocker.Mock(name=name) bin_mock = mocker.Mock(name=name)

View File

@@ -63,3 +63,5 @@ SETTINGS_HEADER = u"""# The Fuck settings file
""" """
ARGUMENT_PLACEHOLDER = 'THEFUCK_ARGUMENT_PLACEHOLDER' ARGUMENT_PLACEHOLDER = 'THEFUCK_ARGUMENT_PLACEHOLDER'
CONFIGURATION_TIMEOUT = 60

View File

@@ -4,9 +4,11 @@ from .system import init_output
init_output() init_output()
import os # noqa: E402 import os # noqa: E402
from psutil import Process # noqa: E402 import json # noqa: E402
import time # noqa: E402
import six # noqa: E402 import six # noqa: E402
from . import logs # noqa: E402 from psutil import Process # noqa: E402
from . import logs, const # noqa: E402
from .shells import shell # noqa: E402 from .shells import shell # noqa: E402
from .conf import settings # noqa: E402 from .conf import settings # noqa: E402
from .system import Path # noqa: E402 from .system import Path # noqa: E402
@@ -30,19 +32,41 @@ def _get_not_configured_usage_tracker_path():
def _record_first_run(): def _record_first_run():
"""Records shell pid to tracker file.""" """Records shell pid to tracker file."""
with _get_not_configured_usage_tracker_path().open('w') as tracker: info = {'pid': _get_shell_pid(),
tracker.write(six.text_type(_get_shell_pid())) 'time': time.time()}
mode = 'wb' if six.PY2 else 'w'
with _get_not_configured_usage_tracker_path().open(mode) as tracker:
json.dump(info, tracker)
def _get_previous_command():
history = shell.get_history()
if history:
return history[-1]
else:
return None
def _is_second_run(): def _is_second_run():
"""Returns `True` when we know that `fuck` called second time.""" """Returns `True` when we know that `fuck` called second time."""
tracker_path = _get_not_configured_usage_tracker_path() tracker_path = _get_not_configured_usage_tracker_path()
if not tracker_path.exists() or not shell.get_history()[-1] == 'fuck': if not tracker_path.exists():
return False return False
current_pid = _get_shell_pid() current_pid = _get_shell_pid()
with tracker_path.open('r') as tracker: with tracker_path.open('r') as tracker:
return tracker.read() == six.text_type(current_pid) try:
info = json.load(tracker)
except ValueError:
return False
if not (isinstance(info, dict) and info.get('pid') == current_pid):
return False
return (_get_previous_command() == 'fuck' or
time.time() - info.get('time', 0) < const.CONFIGURATION_TIMEOUT)
def _is_already_configured(configuration_details): def _is_already_configured(configuration_details):

View File

@@ -6,12 +6,13 @@ from thefuck.specific.git import git_support
@git_support @git_support
def match(command): def match(command):
return (" is not a git command. See 'git --help'." in command.stderr return (" is not a git command. See 'git --help'." in command.stderr
and 'Did you mean' in command.stderr) and ('The most similar command' in command.stderr
or 'Did you mean' in command.stderr))
@git_support @git_support
def get_new_command(command): def get_new_command(command):
broken_cmd = re.findall(r"git: '([^']*)' is not a git command", broken_cmd = re.findall(r"git: '([^']*)' is not a git command",
command.stderr)[0] command.stderr)[0]
matched = get_all_matched_commands(command.stderr) matched = get_all_matched_commands(command.stderr, ['The most similar command', 'Did you mean'])
return replace_command(command, broken_cmd, matched) return replace_command(command, broken_cmd, matched)

View File

@@ -11,12 +11,14 @@ class Bash(Generic):
return ''' return '''
function {name} () {{ function {name} () {{
TF_PREVIOUS=$(fc -ln -1); TF_PREVIOUS=$(fc -ln -1);
TF_PYTHONIOENCODING=$PYTHONIOENCODING;
export TF_ALIAS={name};
export TF_SHELL_ALIASES=$(alias);
export PYTHONIOENCODING=utf-8;
TF_CMD=$( TF_CMD=$(
export TF_ALIAS={name}
export TF_SHELL_ALIASES=$(alias)
export PYTHONIOENCODING=utf-8
thefuck $TF_PREVIOUS {argument_placeholder} $@ thefuck $TF_PREVIOUS {argument_placeholder} $@
) && eval $TF_CMD; ) && eval $TF_CMD;
export PYTHONIOENCODING=$TF_PYTHONIOENCODING;
{alter_history} {alter_history}
}} }}
'''.format( '''.format(

View File

@@ -77,7 +77,7 @@ class Generic(object):
encoded = self.encode_utf8(command) encoded = self.encode_utf8(command)
try: try:
splitted = shlex.split(encoded) splitted = [s.replace("??", "\ ") for s in shlex.split(encoded.replace('\ ', '??'))]
except ValueError: except ValueError:
splitted = encoded.split(' ') splitted = encoded.split(' ')

View File

@@ -141,12 +141,17 @@ def eager(fn, *args, **kwargs):
@eager @eager
def get_all_matched_commands(stderr, separator='Did you mean'): def get_all_matched_commands(stderr, separator='Did you mean'):
if not isinstance(separator, list):
separator = [separator]
should_yield = False should_yield = False
for line in stderr.split('\n'): for line in stderr.split('\n'):
if separator in line: for sep in separator:
should_yield = True if sep in line:
elif should_yield and line: should_yield = True
yield line.strip() break
else:
if should_yield and line:
yield line.strip()
def replace_command(command, broken, matched): def replace_command(command, broken, matched):