Merge ae13a1501b into 62e0767c50
This commit is contained in:
commit
f9ccade8d5
|
|
@ -23,6 +23,7 @@
|
|||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
Monkey patch setuptools to write faster console_scripts with this format:
|
||||
|
||||
|
|
@ -35,8 +36,11 @@ This is better.
|
|||
(c) 2016, Aaron Christianson
|
||||
http://github.com/ninjaaron/fast-entry_points
|
||||
'''
|
||||
|
||||
from setuptools.command import easy_install
|
||||
import re
|
||||
|
||||
|
||||
TEMPLATE = r'''\
|
||||
# -*- coding: utf-8 -*-
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}'
|
||||
|
|
@ -60,15 +64,20 @@ def get_args(cls, dist, header=None):
|
|||
if header is None:
|
||||
header = cls.get_header()
|
||||
spec = str(dist.as_requirement())
|
||||
for type_ in 'console', 'gui':
|
||||
for type_ in ['console', 'gui']:
|
||||
group = type_ + '_scripts'
|
||||
for name, ep in dist.get_entry_map(group).items():
|
||||
# ensure_safe_name
|
||||
if re.search(r'[\\/]', name):
|
||||
raise ValueError("Path separators not allowed in script names")
|
||||
script_text = TEMPLATE.format(
|
||||
ep.module_name, ep.attrs[0], '.'.join(ep.attrs),
|
||||
spec, group, name)
|
||||
ep.module_name,
|
||||
ep.attrs[0],
|
||||
'.'.join(ep.attrs),
|
||||
spec,
|
||||
group,
|
||||
name
|
||||
)
|
||||
args = cls._get_script_args(type_, name, header, script_text)
|
||||
for res in args:
|
||||
yield res
|
||||
|
|
|
|||
85
setup.py
85
setup.py
|
|
@ -33,38 +33,67 @@ elif (3, 0) < version < (3, 5):
|
|||
|
||||
VERSION = '3.32'
|
||||
|
||||
install_requires = ['psutil', 'colorama', 'six']
|
||||
extras_require = {':python_version<"3.4"': ['pathlib2'],
|
||||
':python_version<"3.3"': ['backports.shutil_get_terminal_size'],
|
||||
':python_version<="2.7"': ['decorator<5', 'pyte<0.8.1'],
|
||||
':python_version>"2.7"': ['decorator', 'pyte'],
|
||||
":sys_platform=='win32'": ['win_unicode_console']}
|
||||
install_requires = [
|
||||
'psutil',
|
||||
'colorama',
|
||||
'six'
|
||||
]
|
||||
|
||||
extras_require = {
|
||||
':python_version<"3.4"': ['pathlib2'],
|
||||
':python_version<"3.3"': ['backports.shutil_get_terminal_size'],
|
||||
':python_version<="2.7"': [
|
||||
'decorator<5',
|
||||
'pyte<0.8.1'
|
||||
],
|
||||
':python_version>"2.7"': [
|
||||
'decorator',
|
||||
'pyte'
|
||||
],
|
||||
":sys_platform=='win32'": [
|
||||
'win_unicode_console'
|
||||
]
|
||||
}
|
||||
|
||||
if sys.platform == "win32":
|
||||
scripts = ['scripts\\fuck.bat', 'scripts\\fuck.ps1']
|
||||
scripts = [
|
||||
'scripts\\fuck.bat',
|
||||
'scripts\\fuck.ps1'
|
||||
]
|
||||
entry_points = {'console_scripts': [
|
||||
'thefuck = thefuck.entrypoints.main:main',
|
||||
'thefuck_firstuse = thefuck.entrypoints.not_configured:main']}
|
||||
'thefuck = thefuck.entrypoints.main:main',
|
||||
'thefuck_firstuse = thefuck.entrypoints.not_configured:main'
|
||||
]}
|
||||
else:
|
||||
scripts = []
|
||||
entry_points = {'console_scripts': [
|
||||
'thefuck = thefuck.entrypoints.main:main',
|
||||
'fuck = thefuck.entrypoints.not_configured:main']}
|
||||
'thefuck = thefuck.entrypoints.main:main',
|
||||
'fuck = thefuck.entrypoints.not_configured:main'
|
||||
]}
|
||||
|
||||
setup(name='thefuck',
|
||||
version=VERSION,
|
||||
description="Magnificent app which corrects your previous console command",
|
||||
long_description=long_description,
|
||||
author='Vladimir Iakovlev',
|
||||
author_email='nvbn.rm@gmail.com',
|
||||
url='https://github.com/nvbn/thefuck',
|
||||
license='MIT',
|
||||
packages=find_packages(exclude=['ez_setup', 'examples',
|
||||
'tests', 'tests.*', 'release']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
|
||||
install_requires=install_requires,
|
||||
extras_require=extras_require,
|
||||
scripts=scripts,
|
||||
entry_points=entry_points)
|
||||
package_exclude = [
|
||||
'ez_setup',
|
||||
'examples',
|
||||
'tests',
|
||||
'tests.*',
|
||||
'release'
|
||||
]
|
||||
|
||||
setup(
|
||||
name = 'thefuck',
|
||||
version = VERSION,
|
||||
description = "Magnificent app which corrects your previous console command",
|
||||
long_description = long_description,
|
||||
author = 'Vladimir Iakovlev',
|
||||
author_email = 'nvbn.rm@gmail.com',
|
||||
url = 'https://github.com/nvbn/thefuck',
|
||||
license = 'MIT',
|
||||
packages = find_packages(exclude = package_exclude),
|
||||
include_package_data = True,
|
||||
zip_safe = False,
|
||||
python_requires = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
|
||||
install_requires = install_requires,
|
||||
extras_require = extras_require,
|
||||
scripts = scripts,
|
||||
entry_points = entry_points
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,23 +4,29 @@ from thefuck.entrypoints.alias import _get_alias, print_alias
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'py2, enable_experimental_instant_mode, which, is_instant', [
|
||||
'py2, enable_experimental_instant_mode, which, is_instant',
|
||||
[
|
||||
(False, True, True, True),
|
||||
(False, False, True, False),
|
||||
(False, True, False, False),
|
||||
(True, True, True, False),
|
||||
(True, True, False, False),
|
||||
(True, False, True, False)])
|
||||
(True, False, True, False)
|
||||
]
|
||||
)
|
||||
def test_get_alias(monkeypatch, mocker, py2,
|
||||
enable_experimental_instant_mode,
|
||||
which, is_instant):
|
||||
monkeypatch.setattr('six.PY2', py2)
|
||||
args = Mock(
|
||||
enable_experimental_instant_mode=enable_experimental_instant_mode,
|
||||
alias='fuck', )
|
||||
alias='fuck',
|
||||
)
|
||||
mocker.patch('thefuck.entrypoints.alias.which', return_value=which)
|
||||
shell = Mock(app_alias=lambda _: 'app_alias',
|
||||
instant_mode_alias=lambda _: 'instant_mode_alias')
|
||||
shell = Mock(
|
||||
app_alias=lambda _: 'app_alias',
|
||||
instant_mode_alias=lambda _: 'instant_mode_alias'
|
||||
)
|
||||
monkeypatch.setattr('thefuck.entrypoints.alias.shell', shell)
|
||||
|
||||
alias = _get_alias(args)
|
||||
|
|
|
|||
|
|
@ -10,15 +10,21 @@ class TestGetRawCommand(object):
|
|||
|
||||
def test_from_command_argument(self, os_environ):
|
||||
os_environ['TF_HISTORY'] = None
|
||||
known_args = Mock(force_command=None,
|
||||
command=['sl'])
|
||||
known_args = Mock(
|
||||
force_command=None,
|
||||
command=['sl']
|
||||
)
|
||||
assert _get_raw_command(known_args) == ['sl']
|
||||
|
||||
@pytest.mark.parametrize('history, result', [
|
||||
('git br', 'git br'),
|
||||
('git br\nfcuk', 'git br'),
|
||||
('git br\nfcuk\nls', 'ls'),
|
||||
('git br\nfcuk\nls\nfuk', 'ls')])
|
||||
@pytest.mark.parametrize(
|
||||
'history, result',
|
||||
[
|
||||
('git br', 'git br'),
|
||||
('git br\nfcuk', 'git br'),
|
||||
('git br\nfcuk\nls', 'ls'),
|
||||
('git br\nfcuk\nls\nfuk', 'ls')
|
||||
]
|
||||
)
|
||||
def test_from_history(self, os_environ, history, result):
|
||||
os_environ['TF_HISTORY'] = history
|
||||
known_args = Mock(force_command=None,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ from thefuck.entrypoints.not_configured import main
|
|||
def usage_tracker(mocker):
|
||||
return mocker.patch(
|
||||
'thefuck.entrypoints.not_configured._get_not_configured_usage_tracker_path',
|
||||
new_callable=MagicMock)
|
||||
new_callable=MagicMock
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
@ -44,27 +45,34 @@ def _change_tracker(usage_tracker_io, pid):
|
|||
|
||||
@pytest.fixture(autouse=True)
|
||||
def shell_pid(mocker):
|
||||
return mocker.patch('thefuck.entrypoints.not_configured._get_shell_pid',
|
||||
new_callable=MagicMock)
|
||||
return mocker.patch(
|
||||
'thefuck.entrypoints.not_configured._get_shell_pid',
|
||||
new_callable=MagicMock
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def shell(mocker):
|
||||
shell = mocker.patch('thefuck.entrypoints.not_configured.shell',
|
||||
new_callable=MagicMock)
|
||||
shell = mocker.patch(
|
||||
'thefuck.entrypoints.not_configured.shell',
|
||||
new_callable=MagicMock
|
||||
)
|
||||
shell.get_history.return_value = []
|
||||
shell.how_to_configure.return_value = ShellConfiguration(
|
||||
content='eval $(thefuck --alias)',
|
||||
path='/tmp/.bashrc',
|
||||
reload='bash',
|
||||
can_configure_automatically=True)
|
||||
can_configure_automatically=True
|
||||
)
|
||||
return shell
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def shell_config(mocker):
|
||||
path_mock = mocker.patch('thefuck.entrypoints.not_configured.Path',
|
||||
new_callable=MagicMock)
|
||||
path_mock = mocker.patch(
|
||||
'thefuck.entrypoints.not_configured.Path',
|
||||
new_callable=MagicMock
|
||||
)
|
||||
return path_mock.return_value \
|
||||
.expanduser.return_value \
|
||||
.open.return_value \
|
||||
|
|
@ -73,8 +81,10 @@ def shell_config(mocker):
|
|||
|
||||
@pytest.fixture(autouse=True)
|
||||
def logs(mocker):
|
||||
return mocker.patch('thefuck.entrypoints.not_configured.logs',
|
||||
new_callable=MagicMock)
|
||||
return mocker.patch(
|
||||
'thefuck.entrypoints.not_configured.logs',
|
||||
new_callable=MagicMock
|
||||
)
|
||||
|
||||
|
||||
def test_for_generic_shell(shell, logs):
|
||||
|
|
@ -114,7 +124,8 @@ def test_when_cant_configure_automatically(shell_pid, shell, logs):
|
|||
content='eval $(thefuck --alias)',
|
||||
path='/tmp/.bashrc',
|
||||
reload='bash',
|
||||
can_configure_automatically=False)
|
||||
can_configure_automatically=False
|
||||
)
|
||||
main()
|
||||
logs.how_to_configure_alias.assert_called_once()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ def _set_confirmation(proc, require):
|
|||
proc.sendline(u'mkdir -p ~/.thefuck')
|
||||
proc.sendline(
|
||||
u'echo "require_confirmation = {}" > ~/.thefuck/settings.py'.format(
|
||||
require))
|
||||
require
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def with_confirmation(proc, TIMEOUT):
|
||||
|
|
|
|||
|
|
@ -4,13 +4,17 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
|
|||
select_command_with_arrows, how_to_configure
|
||||
|
||||
|
||||
python_3 = (u'thefuck/python3',
|
||||
u'',
|
||||
u'sh')
|
||||
python_3 = (
|
||||
u'thefuck/python3',
|
||||
u'',
|
||||
u'sh'
|
||||
)
|
||||
|
||||
python_2 = (u'thefuck/python2',
|
||||
u'',
|
||||
u'sh')
|
||||
python_2 = (
|
||||
u'thefuck/python2',
|
||||
u'',
|
||||
u'sh'
|
||||
)
|
||||
|
||||
|
||||
init_bashrc = u'''echo '
|
||||
|
|
@ -29,7 +33,9 @@ def proc(request, spawnu, TIMEOUT):
|
|||
container, instant_mode = request.param
|
||||
proc = spawnu(*container)
|
||||
proc.sendline(init_bashrc.format(
|
||||
u'--enable-experimental-instant-mode' if instant_mode else ''))
|
||||
u'--enable-experimental-instant-mode' if instant_mode else ''
|
||||
)
|
||||
)
|
||||
proc.sendline(u"bash")
|
||||
if instant_mode:
|
||||
assert proc.expect([TIMEOUT, u'instant mode ready: True'])
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ def proc(request, spawnu, TIMEOUT):
|
|||
container, instant_mode = request.param
|
||||
proc = spawnu(*container)
|
||||
proc.sendline(init_zshrc.format(
|
||||
u'--enable-experimental-instant-mode' if instant_mode else ''))
|
||||
u'--enable-experimental-instant-mode' if instant_mode else '')
|
||||
)
|
||||
proc.sendline(u"zsh")
|
||||
if instant_mode:
|
||||
assert proc.expect([TIMEOUT, u'instant mode ready: True'])
|
||||
|
|
|
|||
|
|
@ -10,10 +10,18 @@ from thefuck.utils import default_settings, \
|
|||
from thefuck.types import Command
|
||||
|
||||
|
||||
@pytest.mark.parametrize('override, old, new', [
|
||||
({'key': 'val'}, {}, {'key': 'val'}),
|
||||
({'key': 'new-val'}, {'key': 'val'}, {'key': 'val'}),
|
||||
({'key': 'new-val', 'unset': 'unset'}, {'key': 'val'}, {'key': 'val', 'unset': 'unset'})])
|
||||
@pytest.mark.parametrize(
|
||||
'override, old, new',
|
||||
[
|
||||
({'key': 'val'}, {}, {'key': 'val'}),
|
||||
({'key': 'new-val'}, {'key': 'val'}, {'key': 'val'}),
|
||||
(
|
||||
{'key': 'new-val', 'unset': 'unset'},
|
||||
{'key': 'val'},
|
||||
{'key': 'val', 'unset': 'unset'}
|
||||
)
|
||||
]
|
||||
)
|
||||
def test_default_settings(settings, override, old, new):
|
||||
settings.clear()
|
||||
settings.update(old)
|
||||
|
|
@ -46,7 +54,8 @@ class TestGetClosest(object):
|
|||
assert 'status' == get_closest('st', ['status', 'reset'])
|
||||
|
||||
def test_without_fallback(self):
|
||||
assert get_closest('st', ['status', 'reset'],
|
||||
assert get_closest('st',
|
||||
['status', 'reset'],
|
||||
fallback_to_first=False) is None
|
||||
|
||||
|
||||
|
|
@ -115,31 +124,55 @@ def test_replace_argument(args, result):
|
|||
assert replace_argument(*args) == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stderr, result', [
|
||||
(("git: 'cone' is not a git command. See 'git --help'.\n"
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\tclone'), ['clone']),
|
||||
(("git: 're' is not a git command. See 'git --help'.\n"
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\trebase\n'
|
||||
'\treset\n'
|
||||
'\tgrep\n'
|
||||
'\trm'), ['rebase', 'reset', 'grep', 'rm']),
|
||||
(('tsuru: "target" is not a tsuru command. See "tsuru help".\n'
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\tservice-add\n'
|
||||
'\tservice-bind\n'
|
||||
'\tservice-doc\n'
|
||||
'\tservice-info\n'
|
||||
'\tservice-list\n'
|
||||
'\tservice-remove\n'
|
||||
'\tservice-status\n'
|
||||
'\tservice-unbind'), ['service-add', 'service-bind', 'service-doc',
|
||||
'service-info', 'service-list', 'service-remove',
|
||||
'service-status', 'service-unbind'])])
|
||||
@pytest.mark.parametrize(
|
||||
'stderr, result',
|
||||
[
|
||||
(
|
||||
(
|
||||
"git: 'cone' is not a git command. See 'git --help'.\n"
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\tclone'
|
||||
),
|
||||
['clone']
|
||||
),
|
||||
(
|
||||
(
|
||||
"git: 're' is not a git command. See 'git --help'.\n"
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\trebase\n'
|
||||
'\treset\n'
|
||||
'\tgrep\n'
|
||||
'\trm'
|
||||
),
|
||||
[
|
||||
'rebase', 'reset',
|
||||
'grep', 'rm'
|
||||
]
|
||||
),
|
||||
(
|
||||
(
|
||||
'tsuru: "target" is not a tsuru command. See "tsuru help".\n'
|
||||
'\n'
|
||||
'Did you mean one of these?\n'
|
||||
'\tservice-add\n'
|
||||
'\tservice-bind\n'
|
||||
'\tservice-doc\n'
|
||||
'\tservice-info\n'
|
||||
'\tservice-list\n'
|
||||
'\tservice-remove\n'
|
||||
'\tservice-status\n'
|
||||
'\tservice-unbind'
|
||||
),
|
||||
[
|
||||
'service-add', 'service-bind', 'service-doc',
|
||||
'service-info', 'service-list', 'service-remove',
|
||||
'service-status', 'service-unbind'
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
def test_get_all_matched_commands(stderr, result):
|
||||
assert list(get_all_matched_commands(stderr)) == result
|
||||
|
||||
|
|
@ -265,12 +298,14 @@ class TestGetValidHistoryWithoutCurrent(object):
|
|||
path_mock = mocker.Mock(iterdir=mocker.Mock(return_value=callables))
|
||||
return mocker.patch('thefuck.utils.Path', return_value=path_mock)
|
||||
|
||||
@pytest.mark.parametrize('script, result', [
|
||||
('le cat', ['ls cat', 'diff x', u'café ô']),
|
||||
('diff x', ['ls cat', u'café ô']),
|
||||
('fuck', ['ls cat', 'diff x', u'café ô']),
|
||||
(u'cafe ô', ['ls cat', 'diff x', u'café ô']),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'script, result', [
|
||||
('le cat', ['ls cat', 'diff x', u'café ô']),
|
||||
('diff x', ['ls cat', u'café ô']),
|
||||
('fuck', ['ls cat', 'diff x', u'café ô']),
|
||||
(u'cafe ô', ['ls cat', 'diff x', u'café ô']),
|
||||
]
|
||||
)
|
||||
def test_get_valid_history_without_current(self, script, result):
|
||||
command = Command(script, '')
|
||||
assert get_valid_history_without_current(command) == result
|
||||
|
|
|
|||
|
|
@ -19,37 +19,45 @@ class Parser(object):
|
|||
self._parser.add_argument(
|
||||
'-v', '--version',
|
||||
action='store_true',
|
||||
help="show program's version number and exit")
|
||||
help="show program's version number and exit"
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'-a', '--alias',
|
||||
nargs='?',
|
||||
const=get_alias(),
|
||||
help='[custom-alias-name] prints alias for current shell')
|
||||
help='[custom-alias-name] prints alias for current shell'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'-l', '--shell-logger',
|
||||
action='store',
|
||||
help='log shell output to the file')
|
||||
help='log shell output to the file'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--enable-experimental-instant-mode',
|
||||
action='store_true',
|
||||
help='enable experimental instant mode, use on your own risk')
|
||||
help='enable experimental instant mode, use on your own risk'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'-h', '--help',
|
||||
action='store_true',
|
||||
help='show this help message and exit')
|
||||
help='show this help message and exit'
|
||||
)
|
||||
self._add_conflicting_arguments()
|
||||
self._parser.add_argument(
|
||||
'-d', '--debug',
|
||||
action='store_true',
|
||||
help='enable debug output')
|
||||
help='enable debug output'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--force-command',
|
||||
action='store',
|
||||
help=SUPPRESS)
|
||||
help=SUPPRESS
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'command',
|
||||
nargs='*',
|
||||
help='command that should be fixed')
|
||||
help='command that should be fixed'
|
||||
)
|
||||
|
||||
def _add_conflicting_arguments(self):
|
||||
"""It's too dangerous to use `-y` and `-r` together."""
|
||||
|
|
@ -57,11 +65,13 @@ class Parser(object):
|
|||
group.add_argument(
|
||||
'-y', '--yes', '--yeah', '--hard',
|
||||
action='store_true',
|
||||
help='execute fixed command without confirmation')
|
||||
help='execute fixed command without confirmation'
|
||||
)
|
||||
group.add_argument(
|
||||
'-r', '--repeat',
|
||||
action='store_true',
|
||||
help='repeat on failure')
|
||||
help='repeat on failure'
|
||||
)
|
||||
|
||||
def _prepare_arguments(self, argv):
|
||||
"""Prepares arguments by:
|
||||
|
|
|
|||
|
|
@ -59,8 +59,11 @@ class Settings(dict):
|
|||
|
||||
# For backward compatibility use legacy '~/.thefuck' if it exists:
|
||||
if legacy_user_dir.is_dir():
|
||||
warn(u'Config path {} is deprecated. Please move to {}'.format(
|
||||
legacy_user_dir, user_dir))
|
||||
warn(
|
||||
u'Config path {} is deprecated. Please move to {}'.format(
|
||||
legacy_user_dir, user_dir
|
||||
)
|
||||
)
|
||||
return legacy_user_dir
|
||||
else:
|
||||
return user_dir
|
||||
|
|
@ -78,9 +81,11 @@ class Settings(dict):
|
|||
"""Loads settings from file."""
|
||||
settings = load_source(
|
||||
'settings', text_type(self.user_dir.joinpath('settings.py')))
|
||||
return {key: getattr(settings, key)
|
||||
for key in const.DEFAULT_SETTINGS.keys()
|
||||
if hasattr(settings, key)}
|
||||
return {
|
||||
key: getattr(settings, key)
|
||||
for key in const.DEFAULT_SETTINGS.keys()
|
||||
if hasattr(settings, key)
|
||||
}
|
||||
|
||||
def _rules_from_env(self, val):
|
||||
"""Transforms rules list from env-string to python."""
|
||||
|
|
@ -118,9 +123,11 @@ class Settings(dict):
|
|||
|
||||
def _settings_from_env(self):
|
||||
"""Loads settings from env."""
|
||||
return {attr: self._val_from_env(env, attr)
|
||||
for env, attr in const.ENV_TO_ATTR.items()
|
||||
if env in os.environ}
|
||||
return {
|
||||
attr: self._val_from_env(env, attr)
|
||||
for env, attr in const.ENV_TO_ATTR.items()
|
||||
if env in os.environ
|
||||
}
|
||||
|
||||
def _settings_from_args(self, args):
|
||||
"""Loads settings from args."""
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ KEY_CTRL_C = _GenConst('Ctrl+C')
|
|||
KEY_CTRL_N = _GenConst('Ctrl+N')
|
||||
KEY_CTRL_P = _GenConst('Ctrl+P')
|
||||
|
||||
KEY_MAPPING = {'\x0e': KEY_CTRL_N,
|
||||
'\x03': KEY_CTRL_C,
|
||||
'\x10': KEY_CTRL_P}
|
||||
KEY_MAPPING = {
|
||||
'\x0e': KEY_CTRL_N,
|
||||
'\x03': KEY_CTRL_C,
|
||||
'\x10': KEY_CTRL_P
|
||||
}
|
||||
|
||||
ACTION_SELECT = _GenConst('select')
|
||||
ACTION_ABORT = _GenConst('abort')
|
||||
|
|
@ -28,39 +30,49 @@ ALL_ENABLED = _GenConst('All rules enabled')
|
|||
DEFAULT_RULES = [ALL_ENABLED]
|
||||
DEFAULT_PRIORITY = 1000
|
||||
|
||||
DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
|
||||
'exclude_rules': [],
|
||||
'wait_command': 3,
|
||||
'require_confirmation': True,
|
||||
'no_colors': False,
|
||||
'debug': False,
|
||||
'priority': {},
|
||||
'history_limit': None,
|
||||
'alter_history': True,
|
||||
'wait_slow_command': 15,
|
||||
'slow_commands': ['lein', 'react-native', 'gradle',
|
||||
'./gradlew', 'vagrant'],
|
||||
'repeat': False,
|
||||
'instant_mode': False,
|
||||
'num_close_matches': 3,
|
||||
'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'},
|
||||
'excluded_search_path_prefixes': []}
|
||||
DEFAULT_SETTINGS = {
|
||||
'rules': DEFAULT_RULES,
|
||||
'exclude_rules': [],
|
||||
'wait_command': 3,
|
||||
'require_confirmation': True,
|
||||
'no_colors': False,
|
||||
'debug': False,
|
||||
'priority': {},
|
||||
'history_limit': None,
|
||||
'alter_history': True,
|
||||
'wait_slow_command': 15,
|
||||
'slow_commands': [
|
||||
'lein', 'react-native', 'gradle',
|
||||
'./gradlew', 'vagrant'
|
||||
],
|
||||
'repeat': False,
|
||||
'instant_mode': False,
|
||||
'num_close_matches': 3,
|
||||
'env': {
|
||||
'LC_ALL': 'C',
|
||||
'LANG': 'C',
|
||||
'GIT_TRACE': '1'
|
||||
},
|
||||
'excluded_search_path_prefixes': []
|
||||
}
|
||||
|
||||
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
|
||||
'THEFUCK_EXCLUDE_RULES': 'exclude_rules',
|
||||
'THEFUCK_WAIT_COMMAND': 'wait_command',
|
||||
'THEFUCK_REQUIRE_CONFIRMATION': 'require_confirmation',
|
||||
'THEFUCK_NO_COLORS': 'no_colors',
|
||||
'THEFUCK_DEBUG': 'debug',
|
||||
'THEFUCK_PRIORITY': 'priority',
|
||||
'THEFUCK_HISTORY_LIMIT': 'history_limit',
|
||||
'THEFUCK_ALTER_HISTORY': 'alter_history',
|
||||
'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
|
||||
'THEFUCK_SLOW_COMMANDS': 'slow_commands',
|
||||
'THEFUCK_REPEAT': 'repeat',
|
||||
'THEFUCK_INSTANT_MODE': 'instant_mode',
|
||||
'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches',
|
||||
'THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES': 'excluded_search_path_prefixes'}
|
||||
ENV_TO_ATTR = {
|
||||
'THEFUCK_RULES': 'rules',
|
||||
'THEFUCK_EXCLUDE_RULES': 'exclude_rules',
|
||||
'THEFUCK_WAIT_COMMAND': 'wait_command',
|
||||
'THEFUCK_REQUIRE_CONFIRMATION': 'require_confirmation',
|
||||
'THEFUCK_NO_COLORS': 'no_colors',
|
||||
'THEFUCK_DEBUG': 'debug',
|
||||
'THEFUCK_PRIORITY': 'priority',
|
||||
'THEFUCK_HISTORY_LIMIT': 'history_limit',
|
||||
'THEFUCK_ALTER_HISTORY': 'alter_history',
|
||||
'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
|
||||
'THEFUCK_SLOW_COMMANDS': 'slow_commands',
|
||||
'THEFUCK_REPEAT': 'repeat',
|
||||
'THEFUCK_INSTANT_MODE': 'instant_mode',
|
||||
'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches',
|
||||
'THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES': 'excluded_search_path_prefixes'
|
||||
}
|
||||
|
||||
SETTINGS_HEADER = u"""# The Fuck settings file
|
||||
#
|
||||
|
|
|
|||
|
|
@ -43,10 +43,16 @@ def get_rules():
|
|||
:rtype: [Rule]
|
||||
|
||||
"""
|
||||
paths = [rule_path for path in get_rules_import_paths()
|
||||
for rule_path in sorted(path.glob('*.py'))]
|
||||
return sorted(get_loaded_rules(paths),
|
||||
key=lambda rule: rule.priority)
|
||||
paths = [
|
||||
rule_path for path in get_rules_import_paths()
|
||||
for rule_path in sorted(path.glob('*.py'))
|
||||
]
|
||||
return (
|
||||
sorted(
|
||||
get_loaded_rules(paths),
|
||||
key=lambda rule: rule.priority
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def organize_commands(corrected_commands):
|
||||
|
|
@ -88,5 +94,6 @@ def get_corrected_commands(command):
|
|||
corrected_commands = (
|
||||
corrected for rule in get_rules()
|
||||
if rule.is_match(command)
|
||||
for corrected in rule.get_corrected_commands(command))
|
||||
for corrected in rule.get_corrected_commands(command)
|
||||
)
|
||||
return organize_commands(corrected_commands)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ from ..utils import which
|
|||
|
||||
def _get_alias(known_args):
|
||||
if six.PY2:
|
||||
warn("The Fuck will drop Python 2 support soon, more details "
|
||||
"https://github.com/nvbn/thefuck/issues/685")
|
||||
warn(
|
||||
"The Fuck will drop Python 2 support soon, more details "
|
||||
"https://github.com/nvbn/thefuck/issues/685"
|
||||
)
|
||||
|
||||
alias = shell.app_alias(known_args.alias)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@ def main():
|
|||
if known_args.help:
|
||||
parser.print_help()
|
||||
elif known_args.version:
|
||||
logs.version(get_installation_version(),
|
||||
sys.version.split()[0], shell.info())
|
||||
logs.version(
|
||||
get_installation_version(),
|
||||
sys.version.split()[0], shell.info()
|
||||
)
|
||||
# It's important to check if an alias is being requested before checking if
|
||||
# `TF_HISTORY` is in `os.environ`, otherwise it might mess with subshells.
|
||||
# Check https://github.com/nvbn/thefuck/issues/921 for reference
|
||||
|
|
|
|||
|
|
@ -28,9 +28,13 @@ def _get_shell_pid():
|
|||
|
||||
def _get_not_configured_usage_tracker_path():
|
||||
"""Returns path of special file where we store latest shell pid."""
|
||||
return Path(gettempdir()).joinpath(u'thefuck.last_not_configured_run_{}'.format(
|
||||
getpass.getuser(),
|
||||
))
|
||||
return (
|
||||
Path(gettempdir()).joinpath(
|
||||
u'thefuck.last_not_configured_run_{}'.format(
|
||||
getpass.getuser(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _record_first_run():
|
||||
|
|
@ -68,8 +72,10 @@ def _is_second_run():
|
|||
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)
|
||||
return (
|
||||
_get_previous_command() == 'fuck' or
|
||||
time.time() - info.get('time', 0) < const.CONFIGURATION_TIMEOUT
|
||||
)
|
||||
|
||||
|
||||
def _is_already_configured(configuration_details):
|
||||
|
|
|
|||
119
thefuck/logs.py
119
thefuck/logs.py
|
|
@ -18,22 +18,29 @@ def color(color_):
|
|||
|
||||
|
||||
def warn(title):
|
||||
sys.stderr.write(u'{warn}[WARN] {title}{reset}\n'.format(
|
||||
warn=color(colorama.Back.RED + colorama.Fore.WHITE
|
||||
+ colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
title=title))
|
||||
sys.stderr.write(
|
||||
u'{warn}[WARN] {title}{reset}\n'.format(
|
||||
warn = color(colorama.Back.RED + colorama.Fore.WHITE
|
||||
+ colorama.Style.BRIGHT),
|
||||
reset = color(colorama.Style.RESET_ALL),
|
||||
title = title
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def exception(title, exc_info):
|
||||
sys.stderr.write(
|
||||
u'{warn}[WARN] {title}:{reset}\n{trace}'
|
||||
u'{warn}----------------------------{reset}\n\n'.format(
|
||||
warn=color(colorama.Back.RED + colorama.Fore.WHITE
|
||||
+ colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
title=title,
|
||||
trace=''.join(format_exception(*exc_info))))
|
||||
warn = color(
|
||||
colorama.Back.RED + colorama.Fore.WHITE
|
||||
+ colorama.Style.BRIGHT
|
||||
),
|
||||
reset = color(colorama.Style.RESET_ALL),
|
||||
title = title,
|
||||
trace = ''.join(format_exception(*exc_info))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def rule_failed(rule, exc_info):
|
||||
|
|
@ -41,44 +48,57 @@ def rule_failed(rule, exc_info):
|
|||
|
||||
|
||||
def failed(msg):
|
||||
sys.stderr.write(u'{red}{msg}{reset}\n'.format(
|
||||
msg=msg,
|
||||
red=color(colorama.Fore.RED),
|
||||
reset=color(colorama.Style.RESET_ALL)))
|
||||
sys.stderr.write(
|
||||
u'{red}{msg}{reset}\n'.format(
|
||||
msg = msg,
|
||||
red = color(colorama.Fore.RED),
|
||||
reset = color(colorama.Style.RESET_ALL)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def show_corrected_command(corrected_command):
|
||||
sys.stderr.write(u'{prefix}{bold}{script}{reset}{side_effect}\n'.format(
|
||||
prefix=const.USER_COMMAND_MARK,
|
||||
script=corrected_command.script,
|
||||
side_effect=u' (+side effect)' if corrected_command.side_effect else u'',
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL)))
|
||||
sys.stderr.write(
|
||||
u'{prefix}{bold}{script}{reset}{side_effect}\n'.format(
|
||||
prefix = const.USER_COMMAND_MARK,
|
||||
script = corrected_command.script,
|
||||
side_effect = u' (+side effect)' if corrected_command.side_effect else u'',
|
||||
bold = color(colorama.Style.BRIGHT),
|
||||
reset = color(colorama.Style.RESET_ALL)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def confirm_text(corrected_command):
|
||||
sys.stderr.write(
|
||||
(u'{prefix}{clear}{bold}{script}{reset}{side_effect} '
|
||||
u'[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}'
|
||||
u'/{red}ctrl+c{reset}]').format(
|
||||
prefix=const.USER_COMMAND_MARK,
|
||||
script=corrected_command.script,
|
||||
side_effect=' (+side effect)' if corrected_command.side_effect else '',
|
||||
clear='\033[1K\r',
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
green=color(colorama.Fore.GREEN),
|
||||
red=color(colorama.Fore.RED),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
blue=color(colorama.Fore.BLUE)))
|
||||
(
|
||||
u'{prefix}{clear}{bold}{script}{reset}{side_effect} '
|
||||
u'[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}'
|
||||
u'/{red}ctrl+c{reset}]'
|
||||
).format(
|
||||
prefix = const.USER_COMMAND_MARK,
|
||||
script = corrected_command.script,
|
||||
side_effect = ' (+side effect)' if corrected_command.side_effect else '',
|
||||
clear = '\033[1K\r',
|
||||
bold = color(colorama.Style.BRIGHT),
|
||||
green = color(colorama.Fore.GREEN),
|
||||
red = color(colorama.Fore.RED),
|
||||
reset = color(colorama.Style.RESET_ALL),
|
||||
blue = color(colorama.Fore.BLUE)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def debug(msg):
|
||||
if settings.debug:
|
||||
sys.stderr.write(u'{blue}{bold}DEBUG:{reset} {msg}\n'.format(
|
||||
msg=msg,
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
blue=color(colorama.Fore.BLUE),
|
||||
bold=color(colorama.Style.BRIGHT)))
|
||||
sys.stderr.write(
|
||||
u'{blue}{bold}DEBUG:{reset} {msg}\n'.format(
|
||||
msg = msg,
|
||||
reset = color(colorama.Style.RESET_ALL),
|
||||
blue = color(colorama.Fore.BLUE),
|
||||
bold = color(colorama.Style.BRIGHT)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@contextmanager
|
||||
|
|
@ -91,9 +111,12 @@ def debug_time(msg):
|
|||
|
||||
|
||||
def how_to_configure_alias(configuration_details):
|
||||
print(u"Seems like {bold}fuck{reset} alias isn't configured!".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL)))
|
||||
print(
|
||||
u"Seems like {bold}fuck{reset} alias isn't configured!".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL)
|
||||
)
|
||||
)
|
||||
|
||||
if configuration_details:
|
||||
print(
|
||||
|
|
@ -102,14 +125,18 @@ def how_to_configure_alias(configuration_details):
|
|||
u"changes with {bold}{reload}{reset} or restart your shell.".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
**configuration_details._asdict()))
|
||||
**configuration_details._asdict()
|
||||
)
|
||||
)
|
||||
|
||||
if configuration_details.can_configure_automatically:
|
||||
print(
|
||||
u"Or run {bold}fuck{reset} a second time to configure"
|
||||
u" it automatically.".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL)))
|
||||
reset=color(colorama.Style.RESET_ALL)
|
||||
)
|
||||
)
|
||||
|
||||
print(u'More details - https://github.com/nvbn/thefuck#manual-installation')
|
||||
|
||||
|
|
@ -121,7 +148,9 @@ def already_configured(configuration_details):
|
|||
u" or restart your shell.".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
reload=configuration_details.reload))
|
||||
reload=configuration_details.reload
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def configured_successfully(configuration_details):
|
||||
|
|
@ -131,7 +160,9 @@ def configured_successfully(configuration_details):
|
|||
u" or restart your shell.".format(
|
||||
bold=color(colorama.Style.BRIGHT),
|
||||
reset=color(colorama.Style.RESET_ALL),
|
||||
reload=configuration_details.reload))
|
||||
reload=configuration_details.reload
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def version(thefuck_version, python_version, shell_info):
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@ def _kill_process(proc):
|
|||
try:
|
||||
proc.kill()
|
||||
except AccessDenied:
|
||||
logs.debug(u'Rerun: process PID {} ({}) could not be terminated'.format(
|
||||
proc.pid, proc.exe()))
|
||||
logs.debug(
|
||||
u'Rerun: process PID {} ({}) could not be terminated'.format(
|
||||
proc.pid, proc.exe()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _wait_output(popen, is_slow):
|
||||
|
|
@ -33,8 +36,10 @@ def _wait_output(popen, is_slow):
|
|||
"""
|
||||
proc = Process(popen.pid)
|
||||
try:
|
||||
proc.wait(settings.wait_slow_command if is_slow
|
||||
else settings.wait_command)
|
||||
proc.wait(
|
||||
settings.wait_slow_command if is_slow
|
||||
else settings.wait_command
|
||||
)
|
||||
return True
|
||||
except TimeoutExpired:
|
||||
for child in proc.children(recursive=True):
|
||||
|
|
@ -59,8 +64,11 @@ def get_output(script, expanded):
|
|||
|
||||
split_expand = shlex.split(expanded)
|
||||
is_slow = split_expand[0] in settings.slow_commands if split_expand else False
|
||||
with logs.debug_time(u'Call: {}; with env: {}; is slow: {}'.format(
|
||||
script, env, is_slow)):
|
||||
with logs.debug_time(
|
||||
u'Call: {}; with env: {}; is slow: {}'.format(
|
||||
script, env, is_slow
|
||||
)
|
||||
):
|
||||
result = Popen(expanded, shell=True, stdin=PIPE,
|
||||
stdout=PIPE, stderr=STDOUT, env=env)
|
||||
if _wait_output(result, is_slow):
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@ def _parse_apt_get_and_cache_operations(help_text_lines):
|
|||
|
||||
|
||||
def _get_operations(app):
|
||||
proc = subprocess.Popen([app, '--help'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
proc = subprocess.Popen(
|
||||
[app, '--help'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
lines = proc.stdout.readlines()
|
||||
|
||||
if app == 'apt':
|
||||
|
|
|
|||
|
|
@ -12,9 +12,11 @@ def _get_suggestions(str):
|
|||
|
||||
@for_app('brew', at_least=2)
|
||||
def match(command):
|
||||
is_proper_command = ('install' in command.script and
|
||||
'No available formula' in command.output and
|
||||
'Did you mean' in command.output)
|
||||
is_proper_command = (
|
||||
'install' in command.script and
|
||||
'No available formula' in command.output and
|
||||
'Did you mean' in command.output
|
||||
)
|
||||
return is_proper_command
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.utils import for_app
|
|||
|
||||
@for_app('brew', at_least=2)
|
||||
def match(command):
|
||||
return (command.script_parts[1] in ['ln', 'link']
|
||||
and "brew link --overwrite --dry-run" in command.output)
|
||||
return (
|
||||
command.script_parts[1] in ['ln', 'link']
|
||||
and "brew link --overwrite --dry-run" in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@ import re
|
|||
from thefuck.utils import for_app
|
||||
|
||||
|
||||
warning_regex = re.compile(r'Warning: (?:.(?!is ))+ is already installed and '
|
||||
r'up-to-date')
|
||||
message_regex = re.compile(r'To reinstall (?:(?!, ).)+, run `brew reinstall '
|
||||
r'[^`]+`')
|
||||
warning_regex = re.compile(
|
||||
r'Warning: (?:.(?!is ))+ is already installed and '
|
||||
r'up-to-date'
|
||||
)
|
||||
message_regex = re.compile(
|
||||
r'To reinstall (?:(?!, ).)+, run `brew reinstall '
|
||||
r'[^`]+`'
|
||||
)
|
||||
|
||||
|
||||
@for_app('brew', at_least=2)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.utils import for_app
|
|||
|
||||
@for_app('brew', at_least=2)
|
||||
def match(command):
|
||||
return (command.script_parts[1] in ['uninstall', 'rm', 'remove']
|
||||
and "brew uninstall --force" in command.output)
|
||||
return (
|
||||
command.script_parts[1] in ['uninstall', 'rm', 'remove']
|
||||
and "brew uninstall --force" in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ def _get_brew_commands(brew_path_prefix):
|
|||
"""To get brew default commands on local environment"""
|
||||
brew_cmd_path = brew_path_prefix + BREW_CMD_PATH
|
||||
|
||||
return [name[:-3] for name in os.listdir(brew_cmd_path)
|
||||
if name.endswith(('.rb', '.sh'))]
|
||||
return [
|
||||
name[:-3] for name in os.listdir(brew_cmd_path)
|
||||
if name.endswith(('.rb', '.sh'))
|
||||
]
|
||||
|
||||
|
||||
def _get_brew_tap_specific_commands(brew_path_prefix):
|
||||
|
|
@ -34,9 +36,11 @@ def _get_brew_tap_specific_commands(brew_path_prefix):
|
|||
tap_cmd_path = brew_taps_path + TAP_CMD_PATH % (user, tap)
|
||||
|
||||
if os.path.isdir(tap_cmd_path):
|
||||
commands += (name.replace('brew-', '').replace('.rb', '')
|
||||
for name in os.listdir(tap_cmd_path)
|
||||
if _is_brew_tap_cmd_naming(name))
|
||||
commands += (
|
||||
name.replace('brew-', '').replace('.rb', '')
|
||||
for name in os.listdir(tap_cmd_path)
|
||||
if _is_brew_tap_cmd_naming(name)
|
||||
)
|
||||
|
||||
return commands
|
||||
|
||||
|
|
@ -46,23 +50,29 @@ def _is_brew_tap_cmd_naming(name):
|
|||
|
||||
|
||||
def _get_directory_names_only(path):
|
||||
return [d for d in os.listdir(path)
|
||||
if os.path.isdir(os.path.join(path, d))]
|
||||
return [
|
||||
d for d in os.listdir(path)
|
||||
if os.path.isdir(os.path.join(path, d))
|
||||
]
|
||||
|
||||
|
||||
def _brew_commands():
|
||||
brew_path_prefix = get_brew_path_prefix()
|
||||
if brew_path_prefix:
|
||||
try:
|
||||
return (_get_brew_commands(brew_path_prefix)
|
||||
+ _get_brew_tap_specific_commands(brew_path_prefix))
|
||||
return (
|
||||
_get_brew_commands(brew_path_prefix)
|
||||
+ _get_brew_tap_specific_commands(brew_path_prefix)
|
||||
)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Failback commands for testing (Based on Homebrew 0.9.5)
|
||||
return ['info', 'home', 'options', 'install', 'uninstall',
|
||||
'search', 'list', 'update', 'upgrade', 'pin', 'unpin',
|
||||
'doctor', 'create', 'edit', 'cask']
|
||||
return [
|
||||
'info', 'home', 'options', 'install', 'uninstall',
|
||||
'search', 'list', 'update', 'upgrade', 'pin', 'unpin',
|
||||
'doctor', 'create', 'edit', 'cask'
|
||||
]
|
||||
|
||||
|
||||
def match(command):
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from thefuck.utils import for_app
|
|||
|
||||
@for_app('brew', at_least=2)
|
||||
def match(command):
|
||||
return ('update' in command.script
|
||||
and "Error: This command updates brew itself" in command.output
|
||||
and "Use `brew upgrade" in command.output)
|
||||
return (
|
||||
'update' in command.script
|
||||
and "Error: This command updates brew itself" in command.output
|
||||
and "Use `brew upgrade" in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.utils import replace_argument, for_app
|
|||
|
||||
@for_app('cargo', at_least=1)
|
||||
def match(command):
|
||||
return ('no such subcommand' in command.output.lower()
|
||||
and 'Did you mean' in command.output)
|
||||
return (
|
||||
'no such subcommand' in command.output.lower()
|
||||
and 'Did you mean' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -21,11 +21,14 @@ def _get_sub_dirs(parent):
|
|||
def match(command):
|
||||
"""Match function copied from cd_mkdir.py"""
|
||||
return (
|
||||
command.script.startswith('cd ') and any((
|
||||
'no such file or directory' in command.output.lower(),
|
||||
'cd: can\'t cd to' in command.output.lower(),
|
||||
'does not exist' in command.output.lower()
|
||||
)))
|
||||
command.script.startswith('cd ') and any(
|
||||
(
|
||||
'no such file or directory' in command.output.lower(),
|
||||
'cd: can\'t cd to' in command.output.lower(),
|
||||
'does not exist' in command.output.lower()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -8,11 +8,14 @@ from thefuck.shells import shell
|
|||
@for_app('cd')
|
||||
def match(command):
|
||||
return (
|
||||
command.script.startswith('cd ') and any((
|
||||
'no such file or directory' in command.output.lower(),
|
||||
'cd: can\'t cd to' in command.output.lower(),
|
||||
'does not exist' in command.output.lower()
|
||||
)))
|
||||
command.script.startswith('cd ') and any(
|
||||
(
|
||||
'no such file or directory' in command.output.lower(),
|
||||
'cd: can\'t cd to' in command.output.lower(),
|
||||
'does not exist' in command.output.lower()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ from thefuck.shells import shell
|
|||
|
||||
|
||||
def match(command):
|
||||
return (command.script.startswith('./')
|
||||
return (
|
||||
command.script.startswith('./')
|
||||
and 'permission denied' in command.output.lower()
|
||||
and os.path.exists(command.script_parts[0])
|
||||
and not os.access(command.script_parts[0], os.X_OK))
|
||||
and not os.access(command.script_parts[0], os.X_OK)
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.utils import for_app, which
|
|||
|
||||
@for_app("choco", "cinst")
|
||||
def match(command):
|
||||
return ((command.script.startswith('choco install') or 'cinst' in command.script_parts)
|
||||
and 'Installing the following packages' in command.output)
|
||||
return (
|
||||
(command.script.startswith('choco install') or 'cinst' in command.script_parts)
|
||||
and 'Installing the following packages' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@ from thefuck.utils import replace_argument, for_app
|
|||
|
||||
@for_app('composer')
|
||||
def match(command):
|
||||
return (('did you mean this?' in command.output.lower()
|
||||
or 'did you mean one of these?' in command.output.lower())) or (
|
||||
"install" in command.script_parts and "composer require" in command.output.lower()
|
||||
return (
|
||||
(
|
||||
(
|
||||
'did you mean this?' in command.output.lower()
|
||||
or 'did you mean one of these?' in command.output.lower()
|
||||
)
|
||||
) or (
|
||||
"install" in command.script_parts and "composer require" in command.output.lower()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from thefuck.utils import for_app
|
|||
|
||||
@for_app('g++', 'clang++')
|
||||
def match(command):
|
||||
return ('This file requires compiler and library support for the '
|
||||
'ISO C++ 2011 standard.' in command.output or
|
||||
'-Wc++11-extensions' in command.output)
|
||||
return (
|
||||
'This file requires compiler and library support for the '
|
||||
'ISO C++ 2011 standard.' in command.output or
|
||||
'-Wc++11-extensions' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ from thefuck.utils import for_app
|
|||
from thefuck.shells import shell
|
||||
|
||||
|
||||
tar_extensions = ('.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
|
||||
'.tar.lzma', '.tar.xz', '.taz', '.tb2', '.tbz', '.tbz2',
|
||||
'.tgz', '.tlz', '.txz', '.tz')
|
||||
tar_extensions = (
|
||||
'.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
|
||||
'.tar.lzma', '.tar.xz', '.taz', '.tb2', '.tbz', '.tbz2',
|
||||
'.tgz', '.tlz', '.txz', '.tz'
|
||||
)
|
||||
|
||||
|
||||
def _is_tar_extract(cmd):
|
||||
|
|
@ -27,9 +29,11 @@ def _tar_file(cmd):
|
|||
|
||||
@for_app('tar')
|
||||
def match(command):
|
||||
return ('-C' not in command.script
|
||||
and _is_tar_extract(command.script)
|
||||
and _tar_file(command.script_parts) is not None)
|
||||
return (
|
||||
'-C' not in command.script
|
||||
and _is_tar_extract(command.script)
|
||||
and _tar_file(command.script_parts) is not None
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ def _parse_operations(help_text_lines):
|
|||
|
||||
|
||||
def _get_operations():
|
||||
proc = subprocess.Popen(["dnf", '--help'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
proc = subprocess.Popen(
|
||||
["dnf", '--help'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
lines = proc.stdout.read().decode("utf-8")
|
||||
|
||||
return _parse_operations(lines)
|
||||
|
|
|
|||
|
|
@ -25,14 +25,18 @@ def _get_between(content, start, end=None):
|
|||
def get_new_command(command):
|
||||
not_found_commands = _get_between(
|
||||
command.output, 'Warning: Command(s) not found:',
|
||||
'Available commands:')
|
||||
'Available commands:'
|
||||
)
|
||||
possible_commands = _get_between(
|
||||
command.output, 'Available commands:')
|
||||
command.output, 'Available commands:'
|
||||
)
|
||||
|
||||
script = command.script
|
||||
for not_found in not_found_commands:
|
||||
fix = get_closest(not_found, possible_commands)
|
||||
script = script.replace(' {}'.format(not_found),
|
||||
' {}'.format(fix))
|
||||
script = script.replace(
|
||||
' {}'.format(not_found),
|
||||
' {}'.format(fix)
|
||||
)
|
||||
|
||||
return script
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return ('command not found' in command.output.lower()
|
||||
and u' ' in command.script)
|
||||
return (
|
||||
'command not found' in command.output.lower()
|
||||
and u' ' in command.script
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -60,21 +60,29 @@ def match(command):
|
|||
return _search(command.output)
|
||||
|
||||
|
||||
@default_settings({'fixlinecmd': u'{editor} {file} +{line}',
|
||||
'fixcolcmd': None})
|
||||
@default_settings(
|
||||
{
|
||||
'fixlinecmd': u'{editor} {file} +{line}',
|
||||
'fixcolcmd': None
|
||||
}
|
||||
)
|
||||
def get_new_command(command):
|
||||
m = _search(command.output)
|
||||
|
||||
# Note: there does not seem to be a standard for columns, so they are just
|
||||
# ignored by default
|
||||
if settings.fixcolcmd and 'col' in m.groupdict():
|
||||
editor_call = settings.fixcolcmd.format(editor=os.environ['EDITOR'],
|
||||
file=m.group('file'),
|
||||
line=m.group('line'),
|
||||
col=m.group('col'))
|
||||
editor_call = settings.fixcolcmd.format(
|
||||
editor=os.environ['EDITOR'],
|
||||
file=m.group('file'),
|
||||
line=m.group('line'),
|
||||
col=m.group('col')
|
||||
)
|
||||
else:
|
||||
editor_call = settings.fixlinecmd.format(editor=os.environ['EDITOR'],
|
||||
file=m.group('file'),
|
||||
line=m.group('line'))
|
||||
editor_call = settings.fixlinecmd.format(
|
||||
editor=os.environ['EDITOR'],
|
||||
file=m.group('file'),
|
||||
line=m.group('line')
|
||||
)
|
||||
|
||||
return shell.and_(editor_call, command.script)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ from thefuck.utils import for_app, eager, replace_command, cache, which
|
|||
|
||||
@for_app('gem')
|
||||
def match(command):
|
||||
return ('ERROR: While executing gem ... (Gem::CommandLineError)'
|
||||
return (
|
||||
'ERROR: While executing gem ... (Gem::CommandLineError)'
|
||||
in command.output
|
||||
and 'Unknown command' in command.output)
|
||||
and 'Unknown command' in command.output
|
||||
)
|
||||
|
||||
|
||||
def _get_unknown_command(command):
|
||||
|
|
@ -16,8 +18,10 @@ def _get_unknown_command(command):
|
|||
|
||||
@eager
|
||||
def _get_all_commands():
|
||||
proc = subprocess.Popen(['gem', 'help', 'commands'],
|
||||
stdout=subprocess.PIPE)
|
||||
proc = subprocess.Popen(
|
||||
['gem', 'help', 'commands'],
|
||||
stdout=subprocess.PIPE
|
||||
)
|
||||
|
||||
for line in proc.stdout.readlines():
|
||||
line = line.decode()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ from thefuck.utils import memoize
|
|||
def _get_missing_file(command):
|
||||
pathspec = re.findall(
|
||||
r"error: pathspec '([^']*)' "
|
||||
r'did not match any file\(s\) known to git.', command.output)[0]
|
||||
r'did not match any file\(s\) known to git.', command.output
|
||||
)[0]
|
||||
if Path(pathspec).exists():
|
||||
return pathspec
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('add' in command.script_parts
|
||||
and 'Use -f if you really want to add them.' in command.output)
|
||||
return (
|
||||
'add' in command.script_parts
|
||||
and 'Use -f if you really want to add them.' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('bisect' in command.script_parts and
|
||||
'usage: git bisect' in command.output)
|
||||
return (
|
||||
'bisect' in command.script_parts and
|
||||
'usage: git bisect' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('branch -d' in command.script
|
||||
and 'If you are sure you want to delete it' in command.output)
|
||||
return (
|
||||
'branch -d' in command.script
|
||||
and 'If you are sure you want to delete it' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ from thefuck.utils import eager
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ("fatal: A branch named '" in command.output
|
||||
and "' already exists." in command.output)
|
||||
return (
|
||||
"fatal: A branch named '" in command.output
|
||||
and "' already exists." in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
@ -16,10 +18,12 @@ def get_new_command(command):
|
|||
branch_name = re.findall(
|
||||
r"fatal: A branch named '(.+)' already exists.", command.output)[0]
|
||||
branch_name = branch_name.replace("'", r"\'")
|
||||
new_command_templates = [['git branch -d {0}', 'git branch {0}'],
|
||||
['git branch -d {0}', 'git checkout -b {0}'],
|
||||
['git branch -D {0}', 'git branch {0}'],
|
||||
['git branch -D {0}', 'git checkout -b {0}'],
|
||||
['git checkout {0}']]
|
||||
new_command_templates = [
|
||||
['git branch -d {0}', 'git branch {0}'],
|
||||
['git branch -d {0}', 'git checkout -b {0}'],
|
||||
['git branch -D {0}', 'git branch {0}'],
|
||||
['git branch -D {0}', 'git checkout -b {0}'],
|
||||
['git checkout {0}']
|
||||
]
|
||||
for new_command_template in new_command_templates:
|
||||
yield shell.and_(*new_command_template).format(branch_name)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ from thefuck.shells import shell
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('did not match any file(s) known to git' in command.output
|
||||
and "Did you forget to 'git add'?" not in command.output)
|
||||
return (
|
||||
'did not match any file(s) known to git' in command.output
|
||||
and "Did you forget to 'git add'?" not in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_branches():
|
||||
|
|
@ -32,8 +34,10 @@ def get_new_command(command):
|
|||
missing_file = re.findall(
|
||||
r"error: pathspec '([^']*)' "
|
||||
r"did not match any file\(s\) known to git", command.output)[0]
|
||||
closest_branch = utils.get_closest(missing_file, get_branches(),
|
||||
fallback_to_first=False)
|
||||
closest_branch = utils.get_closest(
|
||||
missing_file, get_branches(),
|
||||
fallback_to_first=False
|
||||
)
|
||||
|
||||
new_commands = []
|
||||
|
||||
|
|
@ -43,7 +47,10 @@ def get_new_command(command):
|
|||
new_commands.append(replace_argument(command.script, 'checkout', 'checkout -b'))
|
||||
|
||||
if not new_commands:
|
||||
new_commands.append(shell.and_('git branch {}', '{}').format(
|
||||
missing_file, command.script))
|
||||
new_commands.append(
|
||||
shell.and_('git branch {}', '{}').format(
|
||||
missing_file, command.script
|
||||
)
|
||||
)
|
||||
|
||||
return new_commands
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (' git clone ' in command.script
|
||||
and 'fatal: Too many arguments.' in command.output)
|
||||
return (
|
||||
' git clone ' in command.script
|
||||
and 'fatal: Too many arguments.' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
files = [arg for arg in command.script_parts[2:]
|
||||
if not arg.startswith('-')]
|
||||
return ('diff' in command.script
|
||||
and '--no-index' not in command.script
|
||||
and len(files) == 2)
|
||||
files = [
|
||||
arg for arg in command.script_parts[2:]
|
||||
if not arg.startswith('-')
|
||||
]
|
||||
return (
|
||||
'diff' in command.script
|
||||
and '--no-index' not in command.script
|
||||
and len(files) == 2
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('diff' in command.script and
|
||||
'--staged' not in command.script)
|
||||
return (
|
||||
'diff' in command.script and
|
||||
'--staged' not in command.script
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ from thefuck.specific.git import git_support
|
|||
@git_support
|
||||
def match(command):
|
||||
if command.script_parts and len(command.script_parts) > 1:
|
||||
return (command.script_parts[1] == 'stash'
|
||||
and 'usage:' in command.output)
|
||||
return (
|
||||
command.script_parts[1] == 'stash'
|
||||
and 'usage:' in command.output
|
||||
)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
@ -21,7 +23,8 @@ stash_commands = (
|
|||
'list',
|
||||
'pop',
|
||||
'save',
|
||||
'show')
|
||||
'show'
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('merge' in command.script
|
||||
and ' - not something we can merge' in command.output
|
||||
and 'Did you mean this?' in command.output)
|
||||
return (
|
||||
'merge' in command.script
|
||||
and ' - not something we can merge' in command.output
|
||||
and 'Did you mean this?' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('merge' in command.script
|
||||
and 'fatal: refusing to merge unrelated histories' in command.output)
|
||||
return (
|
||||
'merge' in command.script
|
||||
and 'fatal: refusing to merge unrelated histories' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -5,14 +5,20 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (" is not a git command. See 'git --help'." in command.output
|
||||
and ('The most similar command' in command.output
|
||||
or 'Did you mean' in command.output))
|
||||
return (
|
||||
" is not a git command. See 'git --help'." in command.output
|
||||
and (
|
||||
'The most similar command' in command.output
|
||||
or 'Did you mean' in command.output
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
def get_new_command(command):
|
||||
broken_cmd = re.findall(r"git: '([^']*)' is not a git command",
|
||||
command.output)[0]
|
||||
broken_cmd = re.findall(
|
||||
r"git: '([^']*)' is not a git command",
|
||||
command.output
|
||||
)[0]
|
||||
matched = get_all_matched_commands(command.output, ['The most similar command', 'Did you mean'])
|
||||
return replace_command(command, broken_cmd, matched)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('fatal: Not a git repository' in command.output
|
||||
and "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)." in command.output)
|
||||
return (
|
||||
'fatal: Not a git repository' in command.output
|
||||
and "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)." in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,9 +4,13 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('pull' in command.script
|
||||
and ('You have unstaged changes' in command.output
|
||||
or 'contains uncommitted changes' in command.output))
|
||||
return (
|
||||
'pull' in command.script
|
||||
and (
|
||||
'You have unstaged changes' in command.output
|
||||
or 'contains uncommitted changes' in command.output
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('push' in command.script_parts
|
||||
and 'git push --set-upstream' in command.output)
|
||||
return (
|
||||
'push' in command.script_parts
|
||||
and 'git push --set-upstream' in command.output
|
||||
)
|
||||
|
||||
|
||||
def _get_upstream_option_index(command_parts):
|
||||
|
|
@ -40,5 +42,7 @@ def get_new_command(command):
|
|||
command_parts.pop(len(command_parts) - 1)
|
||||
|
||||
arguments = re.findall(r'git push (.*)', command.output)[-1].replace("'", r"\'").strip()
|
||||
return replace_argument(" ".join(command_parts), 'push',
|
||||
'push {}'.format(arguments))
|
||||
return replace_argument(
|
||||
" ".join(command_parts), 'push',
|
||||
'push {}'.format(arguments)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('push' in command.script
|
||||
return (
|
||||
'push' in command.script
|
||||
and '! [rejected]' in command.output
|
||||
and 'failed to push some refs to' in command.output
|
||||
and 'Updates were rejected because the tip of your current branch is behind' in command.output)
|
||||
and 'Updates were rejected because the tip of your current branch is behind' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -5,16 +5,24 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('push' in command.script and
|
||||
'! [rejected]' in command.output and
|
||||
'failed to push some refs to' in command.output and
|
||||
('Updates were rejected because the tip of your'
|
||||
' current branch is behind' in command.output or
|
||||
'Updates were rejected because the remote '
|
||||
'contains work that you do' in command.output))
|
||||
return (
|
||||
'push' in command.script and
|
||||
'! [rejected]' in command.output and
|
||||
'failed to push some refs to' in command.output and (
|
||||
(
|
||||
'Updates were rejected because the tip of your'
|
||||
' current branch is behind' in command.output
|
||||
) or (
|
||||
'Updates were rejected because the remote '
|
||||
'contains work that you do' in command.output
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
def get_new_command(command):
|
||||
return shell.and_(replace_argument(command.script, 'push', 'pull'),
|
||||
command.script)
|
||||
return shell.and_(
|
||||
replace_argument(command.script, 'push', 'pull'),
|
||||
command.script
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (' rebase' in command.script and
|
||||
'It seems that there is already a rebase-merge directory' in command.output and
|
||||
'I wonder if you are in the middle of another rebase' in command.output)
|
||||
return (
|
||||
' rebase' in command.script and
|
||||
'It seems that there is already a rebase-merge directory' in command.output and
|
||||
'I wonder if you are in the middle of another rebase' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('set-url' in command.script
|
||||
and 'fatal: No such remote' in command.output)
|
||||
return (
|
||||
'set-url' in command.script
|
||||
and 'fatal: No such remote' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (' rm ' in command.script and
|
||||
'error: the following file has local modifications' in command.output and
|
||||
'use --cached to keep the file, or -f to force removal' in command.output)
|
||||
return (
|
||||
' rm ' in command.script and
|
||||
'error: the following file has local modifications' in command.output and
|
||||
'use --cached to keep the file, or -f to force removal' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (' rm ' in command.script
|
||||
and "fatal: not removing '" in command.output
|
||||
and "' recursively without -r" in command.output)
|
||||
return (
|
||||
' rm ' in command.script
|
||||
and "fatal: not removing '" in command.output
|
||||
and "' recursively without -r" in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return (' rm ' in command.script and
|
||||
'error: the following file has changes staged in the index' in command.output and
|
||||
'use --cached to keep the file, or -f to force removal' in command.output)
|
||||
return (
|
||||
' rm ' in command.script and
|
||||
'error: the following file has changes staged in the index' in command.output and
|
||||
'use --cached to keep the file, or -f to force removal' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('stash' in command.script
|
||||
and 'pop' in command.script
|
||||
and 'Your local changes to the following files would be overwritten by merge' in command.output)
|
||||
return (
|
||||
'stash' in command.script
|
||||
and 'pop' in command.script
|
||||
and 'Your local changes to the following files would be overwritten by merge' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('tag' in command.script_parts
|
||||
and 'already exists' in command.output)
|
||||
return (
|
||||
'tag' in command.script_parts
|
||||
and 'already exists' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.git import git_support
|
|||
|
||||
@git_support
|
||||
def match(command):
|
||||
return ('error: did you mean `' in command.output
|
||||
and '` (with two dashes ?)' in command.output)
|
||||
return (
|
||||
'error: did you mean `' in command.output
|
||||
and '` (with two dashes ?)' in command.output
|
||||
)
|
||||
|
||||
|
||||
@git_support
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ from thefuck.utils import for_app
|
|||
|
||||
@for_app('go')
|
||||
def match(command):
|
||||
return (command.script.startswith('go run ')
|
||||
and not command.script.endswith('.go'))
|
||||
return (
|
||||
command.script.startswith('go run ')
|
||||
and not command.script.endswith('.go')
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -24,5 +24,7 @@ def match(command):
|
|||
|
||||
def get_new_command(command):
|
||||
closest_subcommand = get_closest(command.script_parts[1], get_golang_commands())
|
||||
return replace_argument(command.script, command.script_parts[1],
|
||||
closest_subcommand)
|
||||
return replace_argument(
|
||||
command.script, command.script_parts[1],
|
||||
closest_subcommand
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ from thefuck.utils import for_app, which
|
|||
|
||||
@for_app('gradle')
|
||||
def match(command):
|
||||
return (not which(command.script_parts[0])
|
||||
and 'not found' in command.output
|
||||
and os.path.isfile('gradlew'))
|
||||
return (
|
||||
not which(command.script_parts[0])
|
||||
and 'not found' in command.output
|
||||
and os.path.isfile('gradlew')
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -33,5 +33,7 @@ def get_new_command(command):
|
|||
misspelled_task = regex.findall(command.output)[0].split(':')[0]
|
||||
tasks = _get_all_tasks()
|
||||
fixed = get_closest(misspelled_task, tasks)
|
||||
return command.script.replace(' {}'.format(misspelled_task),
|
||||
' {}'.format(fixed))
|
||||
return command.script.replace(
|
||||
' {}'.format(misspelled_task),
|
||||
' {}'.format(fixed)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,13 +10,19 @@ def match(command):
|
|||
|
||||
@cache('gulpfile.js')
|
||||
def get_gulp_tasks():
|
||||
proc = subprocess.Popen(['gulp', '--tasks-simple'],
|
||||
stdout=subprocess.PIPE)
|
||||
return [line.decode('utf-8')[:-1]
|
||||
for line in proc.stdout.readlines()]
|
||||
proc = subprocess.Popen(
|
||||
['gulp', '--tasks-simple'],
|
||||
stdout=subprocess.PIPE
|
||||
)
|
||||
return [
|
||||
line.decode('utf-8')[:-1]
|
||||
for line in proc.stdout.readlines()
|
||||
]
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
wrong_task = re.findall(r"Task '(\w+)' is not in your gulpfile",
|
||||
command.output)[0]
|
||||
wrong_task = re.findall(
|
||||
r"Task '(\w+)' is not in your gulpfile",
|
||||
command.output
|
||||
)[0]
|
||||
return replace_command(command, wrong_task, get_gulp_tasks())
|
||||
|
|
|
|||
|
|
@ -3,13 +3,19 @@ from thefuck.utils import get_close_matches, get_closest, \
|
|||
|
||||
|
||||
def match(command):
|
||||
return len(get_close_matches(command.script,
|
||||
get_valid_history_without_current(command)))
|
||||
return len(
|
||||
get_close_matches(
|
||||
command.script,
|
||||
get_valid_history_without_current(command)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
return get_closest(command.script,
|
||||
get_valid_history_without_current(command))
|
||||
return get_closest(
|
||||
command.script,
|
||||
get_valid_history_without_current(command)
|
||||
)
|
||||
|
||||
|
||||
priority = 9999
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ def get_new_command(command):
|
|||
return ['hostscli websites']
|
||||
|
||||
misspelled_command = re.findall(
|
||||
r'Error: No such command ".*"', command.output)[0]
|
||||
r'Error: No such command ".*"', command.output
|
||||
)[0]
|
||||
commands = ['block', 'unblock', 'websites', 'block_all', 'unblock_all']
|
||||
return replace_command(command, misspelled_command, commands)
|
||||
|
|
|
|||
|
|
@ -6,14 +6,18 @@ from thefuck.specific.sudo import sudo_support
|
|||
@sudo_support
|
||||
@for_app('lein')
|
||||
def match(command):
|
||||
return (command.script.startswith('lein')
|
||||
return (
|
||||
command.script.startswith('lein')
|
||||
and "is not a task. See 'lein help'" in command.output
|
||||
and 'Did you mean this?' in command.output)
|
||||
and 'Did you mean this?' in command.output
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
def get_new_command(command):
|
||||
broken_cmd = re.findall(r"'([^']*)' is not a task",
|
||||
command.output)[0]
|
||||
broken_cmd = re.findall(
|
||||
r"'([^']*)' is not a task",
|
||||
command.output
|
||||
)[0]
|
||||
new_cmds = get_all_matched_commands(command.output, 'Did you mean this?')
|
||||
return replace_command(command, broken_cmd, new_cmds)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return (command.output.endswith("hard link not allowed for directory") and
|
||||
command.script_parts[0] == 'ln')
|
||||
return (
|
||||
command.output.endswith("hard link not allowed for directory")
|
||||
and command.script_parts[0] == 'ln'
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@ def _get_destination(script_parts):
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return (command.script_parts[0] == 'ln'
|
||||
return (
|
||||
command.script_parts[0] == 'ln'
|
||||
and {'-s', '--symbolic'}.intersection(command.script_parts)
|
||||
and 'File exists' in command.output
|
||||
and _get_destination(command.script_parts))
|
||||
and _get_destination(command.script_parts)
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
def match(command):
|
||||
return (command.script.startswith(u'man')
|
||||
and u'command not found' in command.output.lower())
|
||||
return (
|
||||
command.script.startswith(u'man')
|
||||
and u'command not found' in command.output.lower()
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ def extract_possibilities(command):
|
|||
|
||||
@for_app('hg')
|
||||
def match(command):
|
||||
return ('hg: unknown command' in command.output
|
||||
return (
|
||||
'hg: unknown command' in command.output
|
||||
and '(did you mean one of ' in command.output
|
||||
or "hg: command '" in command.output
|
||||
and "' is ambiguous:" in command.output)
|
||||
and "' is ambiguous:" in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ def _get_executable(script_part):
|
|||
|
||||
|
||||
def match(command):
|
||||
return (not command.script_parts[0] in get_all_executables()
|
||||
and _get_executable(command.script_parts[0]))
|
||||
return (
|
||||
not command.script_parts[0] in get_all_executables()
|
||||
and _get_executable(command.script_parts[0])
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return ('mkdir' in command.script
|
||||
and 'No such file or directory' in command.output)
|
||||
return (
|
||||
'mkdir' in command.script
|
||||
and 'No such file or directory' in command.output
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ def match(command):
|
|||
|
||||
|
||||
def get_new_command(command):
|
||||
return [command.script + ' clean package',
|
||||
command.script + ' clean install']
|
||||
return [
|
||||
command.script + ' clean package',
|
||||
command.script + ' clean install'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ import re
|
|||
|
||||
|
||||
def _get_failed_lifecycle(command):
|
||||
return re.search(r'\[ERROR\] Unknown lifecycle phase "(.+)"',
|
||||
command.output)
|
||||
return re.search(
|
||||
r'\[ERROR\] Unknown lifecycle phase "(.+)"',
|
||||
command.output
|
||||
)
|
||||
|
||||
|
||||
def _getavailable_lifecycles(command):
|
||||
return re.search(
|
||||
r'Available lifecycle phases are: (.+) -> \[Help 1\]', command.output)
|
||||
r'Available lifecycle phases are: (.+) -> \[Help 1\]', command.output
|
||||
)
|
||||
|
||||
|
||||
@for_app('mvn')
|
||||
|
|
|
|||
|
|
@ -5,11 +5,17 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return (not which(command.script_parts[0])
|
||||
and ('not found' in command.output
|
||||
or 'is not recognized as' in command.output)
|
||||
and bool(get_close_matches(command.script_parts[0],
|
||||
get_all_executables())))
|
||||
return (
|
||||
not which(command.script_parts[0])
|
||||
and ('not found' in command.output
|
||||
or 'is not recognized as' in command.output)
|
||||
and bool(
|
||||
get_close_matches(
|
||||
command.script_parts[0],
|
||||
get_all_executables()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _get_used_executables(command):
|
||||
|
|
@ -24,16 +30,21 @@ def get_new_command(command):
|
|||
# One from history:
|
||||
already_used = get_closest(
|
||||
old_command, _get_used_executables(command),
|
||||
fallback_to_first=False)
|
||||
fallback_to_first=False
|
||||
)
|
||||
if already_used:
|
||||
new_cmds = [already_used]
|
||||
else:
|
||||
new_cmds = []
|
||||
|
||||
# Other from all executables:
|
||||
new_cmds += [cmd for cmd in get_close_matches(old_command,
|
||||
get_all_executables())
|
||||
if cmd not in new_cmds]
|
||||
new_cmds += [
|
||||
cmd for cmd in get_close_matches(
|
||||
old_command,
|
||||
get_all_executables()
|
||||
)
|
||||
if cmd not in new_cmds
|
||||
]
|
||||
|
||||
return [command.script.replace(old_command, cmd, 1) for cmd in new_cmds]
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ enabled_by_default = npm_available
|
|||
|
||||
@for_app('npm')
|
||||
def match(command):
|
||||
return (any(part.startswith('ru') for part in command.script_parts)
|
||||
and 'npm ERR! missing script: ' in command.output)
|
||||
return (
|
||||
any(part.startswith('ru') for part in command.script_parts)
|
||||
and 'npm ERR! missing script: ' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
misspelled_script = re.findall(
|
||||
r'.*missing script: (.*)\n', command.output)[0]
|
||||
r'.*missing script: (.*)\n', command.output
|
||||
)[0]
|
||||
return replace_command(command, misspelled_script, get_scripts())
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ enabled_by_default = npm_available
|
|||
|
||||
@for_app('npm')
|
||||
def match(command):
|
||||
return ('Usage: npm <command>' in command.output
|
||||
return (
|
||||
'Usage: npm <command>' in command.output
|
||||
and not any(part.startswith('ru') for part in command.script_parts)
|
||||
and command.script_parts[1] in get_scripts())
|
||||
and command.script_parts[1] in get_scripts()
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ def _get_wrong_command(script_parts):
|
|||
@sudo_support
|
||||
@for_app('npm')
|
||||
def match(command):
|
||||
return (command.script_parts[0] == 'npm' and
|
||||
'where <command> is one of:' in command.output and
|
||||
_get_wrong_command(command.script_parts))
|
||||
return (
|
||||
command.script_parts[0] == 'npm' and
|
||||
'where <command> is one of:' in command.output and
|
||||
_get_wrong_command(command.script_parts)
|
||||
)
|
||||
|
||||
|
||||
@eager
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ def get_app_commands(app):
|
|||
|
||||
def get_new_command(command):
|
||||
broken = re.findall(r"env: no such command ['`]([^']*)'", command.output)[0]
|
||||
matched = [replace_argument(command.script, broken, common_typo)
|
||||
for common_typo in COMMON_TYPOS.get(broken, [])]
|
||||
matched = [
|
||||
replace_argument(command.script, broken, common_typo)
|
||||
for common_typo in COMMON_TYPOS.get(broken, [])
|
||||
]
|
||||
|
||||
app = command.script_parts[0]
|
||||
app_commands = cache(which(app))(get_app_commands)(app)
|
||||
|
|
|
|||
|
|
@ -10,23 +10,27 @@ from thefuck.utils import eager, for_app
|
|||
|
||||
|
||||
def is_arg_url(command):
|
||||
return ('.com' in command.script or
|
||||
'.edu' in command.script or
|
||||
'.info' in command.script or
|
||||
'.io' in command.script or
|
||||
'.ly' in command.script or
|
||||
'.me' in command.script or
|
||||
'.net' in command.script or
|
||||
'.org' in command.script or
|
||||
'.se' in command.script or
|
||||
'www.' in command.script)
|
||||
return (
|
||||
'.com' in command.script or
|
||||
'.edu' in command.script or
|
||||
'.info' in command.script or
|
||||
'.io' in command.script or
|
||||
'.ly' in command.script or
|
||||
'.me' in command.script or
|
||||
'.net' in command.script or
|
||||
'.org' in command.script or
|
||||
'.se' in command.script or
|
||||
'www.' in command.script
|
||||
)
|
||||
|
||||
|
||||
@for_app('open', 'xdg-open', 'gnome-open', 'kde-open')
|
||||
def match(command):
|
||||
return (is_arg_url(command) or
|
||||
command.output.strip().startswith('The file ') and
|
||||
command.output.strip().endswith(' does not exist.'))
|
||||
return (
|
||||
is_arg_url(command) or
|
||||
command.output.strip().startswith('The file ') and
|
||||
command.output.strip().endswith(' does not exist.')
|
||||
)
|
||||
|
||||
|
||||
@eager
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ def get_new_command(command):
|
|||
packages = get_pkgfile(command.script)
|
||||
|
||||
formatme = shell.and_('{} -S {}', '{}')
|
||||
return [formatme.format(pacman, package, command.script)
|
||||
for package in packages]
|
||||
return [
|
||||
formatme.format(pacman, package, command.script)
|
||||
for package in packages
|
||||
]
|
||||
|
||||
|
||||
enabled_by_default, pacman = archlinux_env()
|
||||
|
|
|
|||
|
|
@ -11,10 +11,14 @@ from thefuck.specific.archlinux import get_pkgfile, archlinux_env
|
|||
|
||||
|
||||
def match(command):
|
||||
return (command.script_parts
|
||||
and (command.script_parts[0] in ('pacman', 'yay', 'pikaur', 'yaourt')
|
||||
or command.script_parts[0:2] == ['sudo', 'pacman'])
|
||||
and 'error: target not found:' in command.output)
|
||||
return (
|
||||
command.script_parts
|
||||
and (
|
||||
command.script_parts[0] in ('pacman', 'yay', 'pikaur', 'yaourt')
|
||||
or command.script_parts[0:2] == ['sudo', 'pacman']
|
||||
)
|
||||
and 'error: target not found:' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ from thefuck.utils import (get_valid_history_without_current,
|
|||
from thefuck.shells import shell
|
||||
|
||||
|
||||
patterns = [r'no such file or directory: (.*)$',
|
||||
r"cannot access '(.*)': No such file or directory",
|
||||
r': (.*): No such file or directory',
|
||||
r"can't cd to (.*)$"]
|
||||
patterns = [
|
||||
r'no such file or directory: (.*)$',
|
||||
r"cannot access '(.*)': No such file or directory",
|
||||
r': (.*): No such file or directory',
|
||||
r"can't cd to (.*)$"
|
||||
]
|
||||
|
||||
|
||||
@memoize
|
||||
|
|
@ -45,9 +47,11 @@ def get_new_command(command):
|
|||
destination = _get_destination(command)
|
||||
paths = _get_all_absolute_paths_from_history(command)
|
||||
|
||||
return [replace_argument(command.script, destination, path)
|
||||
for path in paths if path.endswith(destination)
|
||||
and Path(path).expanduser().exists()]
|
||||
return [
|
||||
replace_argument(command.script, destination, path)
|
||||
for path in paths if path.endswith(destination)
|
||||
and Path(path).expanduser().exists()
|
||||
]
|
||||
|
||||
|
||||
priority = 800
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ from thefuck.utils import replace_argument, for_app
|
|||
|
||||
@for_app('php', at_least=2)
|
||||
def match(command):
|
||||
return ('-s' in command.script_parts
|
||||
and command.script_parts[-1] != '-s')
|
||||
return (
|
||||
'-s' in command.script_parts
|
||||
and command.script_parts[-1] != '-s'
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -6,14 +6,18 @@ from thefuck.specific.sudo import sudo_support
|
|||
@sudo_support
|
||||
@for_app('pip', 'pip2', 'pip3')
|
||||
def match(command):
|
||||
return ('pip' in command.script and
|
||||
'unknown command' in command.output and
|
||||
'maybe you meant' in command.output)
|
||||
return (
|
||||
'pip' in command.script and
|
||||
'unknown command' in command.output and
|
||||
'maybe you meant' in command.output
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
broken_cmd = re.findall(r'ERROR: unknown command "([^"]+)"',
|
||||
command.output)[0]
|
||||
broken_cmd = re.findall(
|
||||
r'ERROR: unknown command "([^"]+)"',
|
||||
command.output
|
||||
)[0]
|
||||
new_cmd = re.findall(r'maybe you meant "([^"]+)"', command.output)[0]
|
||||
|
||||
return replace_argument(command.script, broken_cmd, new_cmd)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ from thefuck.shells import shell
|
|||
|
||||
enabled_by_default = bool(which('lsof'))
|
||||
|
||||
patterns = [r"bind on address \('.*', (?P<port>\d+)\)",
|
||||
r'Unable to bind [^ ]*:(?P<port>\d+)',
|
||||
r"can't listen on port (?P<port>\d+)",
|
||||
r'listen EADDRINUSE [^ ]*:(?P<port>\d+)']
|
||||
patterns = [
|
||||
r"bind on address \('.*', (?P<port>\d+)\)",
|
||||
r'Unable to bind [^ ]*:(?P<port>\d+)',
|
||||
r"can't listen on port (?P<port>\d+)",
|
||||
r'listen EADDRINUSE [^ ]*:(?P<port>\d+)'
|
||||
]
|
||||
|
||||
|
||||
@memoize
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ def _isdir(part):
|
|||
def match(command):
|
||||
return (
|
||||
'NOTESTS' in command.output
|
||||
and not any(_is_recursive(part) for part in command.script_parts[1:])
|
||||
and any(_isdir(part) for part in command.script_parts[1:]))
|
||||
and not any(_is_recursive(part) for part in command.script_parts[1:])
|
||||
and any(_isdir(part) for part in command.script_parts[1:])
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return (command.script_parts
|
||||
return (
|
||||
command.script_parts
|
||||
and command.script_parts[0].endswith('.py')
|
||||
and ('Permission denied' in command.output or
|
||||
'command not found' in command.output))
|
||||
and (
|
||||
'Permission denied' in command.output or
|
||||
'command not found' in command.output
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ def _get_commands():
|
|||
|
||||
|
||||
def get_new_command(command):
|
||||
misspelled_command = re.findall(r"Unrecognized command '(.*)'",
|
||||
command.output)[0]
|
||||
misspelled_command = re.findall(
|
||||
r"Unrecognized command '(.*)'",
|
||||
command.output
|
||||
)[0]
|
||||
commands = _get_commands()
|
||||
return replace_command(command, misspelled_command, commands)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ from thefuck.specific.sudo import sudo_support
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return ('rm' in command.script
|
||||
and 'is a directory' in command.output.lower())
|
||||
return (
|
||||
'rm' in command.script
|
||||
and 'is a directory' in command.output.lower()
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ enabled_by_default = False
|
|||
|
||||
@sudo_support
|
||||
def match(command):
|
||||
return (command.script_parts
|
||||
return (
|
||||
command.script_parts
|
||||
and {'rm', '/'}.issubset(command.script_parts)
|
||||
and '--no-preserve-root' not in command.script
|
||||
and '--no-preserve-root' in command.output)
|
||||
and '--no-preserve-root' in command.output
|
||||
)
|
||||
|
||||
|
||||
@sudo_support
|
||||
|
|
|
|||
|
|
@ -1,31 +1,33 @@
|
|||
patterns = ['permission denied',
|
||||
'eacces',
|
||||
'pkg: insufficient privileges',
|
||||
'you cannot perform this operation unless you are root',
|
||||
'non-root users cannot',
|
||||
'operation not permitted',
|
||||
'not super-user',
|
||||
'superuser privilege',
|
||||
'root privilege',
|
||||
'this command has to be run under the root user.',
|
||||
'this operation requires root.',
|
||||
'requested operation requires superuser privilege',
|
||||
'must be run as root',
|
||||
'must run as root',
|
||||
'must be superuser',
|
||||
'must be root',
|
||||
'need to be root',
|
||||
'need root',
|
||||
'needs to be run as root',
|
||||
'only root can ',
|
||||
'you don\'t have access to the history db.',
|
||||
'authentication is required',
|
||||
'edspermissionerror',
|
||||
'you don\'t have write permissions',
|
||||
'use `sudo`',
|
||||
'sudorequirederror',
|
||||
'error: insufficient privileges',
|
||||
'updatedb: can not open a temporary file']
|
||||
patterns = [
|
||||
'permission denied',
|
||||
'eacces',
|
||||
'pkg: insufficient privileges',
|
||||
'you cannot perform this operation unless you are root',
|
||||
'non-root users cannot',
|
||||
'operation not permitted',
|
||||
'not super-user',
|
||||
'superuser privilege',
|
||||
'root privilege',
|
||||
'this command has to be run under the root user.',
|
||||
'this operation requires root.',
|
||||
'requested operation requires superuser privilege',
|
||||
'must be run as root',
|
||||
'must run as root',
|
||||
'must be superuser',
|
||||
'must be root',
|
||||
'need to be root',
|
||||
'need root',
|
||||
'needs to be run as root',
|
||||
'only root can ',
|
||||
'you don\'t have access to the history db.',
|
||||
'authentication is required',
|
||||
'edspermissionerror',
|
||||
'you don\'t have write permissions',
|
||||
'use `sudo`',
|
||||
'sudorequirederror',
|
||||
'error: insufficient privileges',
|
||||
'updatedb: can not open a temporary file'
|
||||
]
|
||||
|
||||
|
||||
def match(command):
|
||||
|
|
|
|||
|
|
@ -17,5 +17,7 @@ def match(command):
|
|||
|
||||
def get_new_command(command):
|
||||
command_name = _get_command_name(command)
|
||||
return replace_argument(command.script, command_name,
|
||||
u'env "PATH=$PATH" {}'.format(command_name))
|
||||
return replace_argument(
|
||||
command.script, command_name,
|
||||
u'env "PATH=$PATH" {}'.format(command_name)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,42 +7,56 @@ target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVB
|
|||
greek = u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?'''
|
||||
korean = u'''ㅂㅈㄷㄱㅅㅛㅕㅑㅐㅔ[]ㅁㄴㅇㄹㅎㅗㅓㅏㅣ;'ㅋㅌㅊㅍㅠㅜㅡ,./ㅃㅉㄸㄲㅆㅛㅕㅑㅒㅖ{}ㅁㄴㅇㄹㅎㅗㅓㅏㅣ:"ㅋㅌㅊㅍㅠㅜㅡ<>?'''
|
||||
|
||||
source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
|
||||
u'''йцукенгшщзхїфівапролджєячсмитьбю.ЙЦУКЕНГШЩЗХЇФІВАПРОЛДЖЄЯЧСМИТЬБЮ,''',
|
||||
u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
|
||||
u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''',
|
||||
greek,
|
||||
korean]
|
||||
source_layouts = [
|
||||
u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
|
||||
u'''йцукенгшщзхїфівапролджєячсмитьбю.ЙЦУКЕНГШЩЗХЇФІВАПРОЛДЖЄЯЧСМИТЬБЮ,''',
|
||||
u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
|
||||
u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''',
|
||||
greek,
|
||||
korean
|
||||
]
|
||||
|
||||
source_to_target = {
|
||||
greek: {u';': "q", u'ς': "w", u'ε': "e", u'ρ': "r", u'τ': "t", u'υ': "y",
|
||||
u'θ': "u", u'ι': "i", u'ο': "o", u'π': "p", u'[': "[", u']': "]",
|
||||
u'α': "a", u'σ': "s", u'δ': "d", u'φ': "f", u'γ': "g", u'η': "h",
|
||||
u'ξ': "j", u'κ': "k", u'λ': "l", u'΄': "'", u'ζ': "z", u'χ': "x",
|
||||
u'ψ': "c", u'ω': "v", u'β': "b", u'ν': "n", u'μ': "m", u',': ",",
|
||||
u'.': ".", u'/': "/", u':': "Q", u'΅': "W", u'Ε': "E", u'Ρ': "R",
|
||||
u'Τ': "T", u'Υ': "Y", u'Θ': "U", u'Ι': "I", u'Ο': "O", u'Π': "P",
|
||||
u'{': "{", u'}': "}", u'Α': "A", u'Σ': "S", u'Δ': "D", u'Φ': "F",
|
||||
u'Γ': "G", u'Η': "H", u'Ξ': "J", u'Κ': "K", u'Λ': "L", u'¨': ":",
|
||||
u'"': '"', u'Ζ': "Z", u'Χ': "X", u'Ψ': "C", u'Ω': "V", u'Β': "B",
|
||||
u'Ν': "N", u'Μ': "M", u'<': "<", u'>': ">", u'?': "?", u'ά': "a",
|
||||
u'έ': "e", u'ύ': "y", u'ί': "i", u'ό': "o", u'ή': 'h', u'ώ': u"v",
|
||||
u'Ά': "A", u'Έ': "E", u'Ύ': "Y", u'Ί': "I", u'Ό': "O", u'Ή': "H",
|
||||
u'Ώ': "V"},
|
||||
greek: {
|
||||
u';': "q", u'ς': "w", u'ε': "e", u'ρ': "r", u'τ': "t", u'υ': "y",
|
||||
u'θ': "u", u'ι': "i", u'ο': "o", u'π': "p", u'[': "[", u']': "]",
|
||||
u'α': "a", u'σ': "s", u'δ': "d", u'φ': "f", u'γ': "g", u'η': "h",
|
||||
u'ξ': "j", u'κ': "k", u'λ': "l", u'΄': "'", u'ζ': "z", u'χ': "x",
|
||||
u'ψ': "c", u'ω': "v", u'β': "b", u'ν': "n", u'μ': "m", u',': ",",
|
||||
u'.': ".", u'/': "/", u':': "Q", u'΅': "W", u'Ε': "E", u'Ρ': "R",
|
||||
u'Τ': "T", u'Υ': "Y", u'Θ': "U", u'Ι': "I", u'Ο': "O", u'Π': "P",
|
||||
u'{': "{", u'}': "}", u'Α': "A", u'Σ': "S", u'Δ': "D", u'Φ': "F",
|
||||
u'Γ': "G", u'Η': "H", u'Ξ': "J", u'Κ': "K", u'Λ': "L", u'¨': ":",
|
||||
u'"': '"', u'Ζ': "Z", u'Χ': "X", u'Ψ': "C", u'Ω': "V", u'Β': "B",
|
||||
u'Ν': "N", u'Μ': "M", u'<': "<", u'>': ">", u'?': "?", u'ά': "a",
|
||||
u'έ': "e", u'ύ': "y", u'ί': "i", u'ό': "o", u'ή': 'h', u'ώ': u"v",
|
||||
u'Ά': "A", u'Έ': "E", u'Ύ': "Y", u'Ί': "I", u'Ό': "O", u'Ή': "H",
|
||||
u'Ώ': "V"
|
||||
},
|
||||
}
|
||||
|
||||
'''Lists used for decomposing korean letters.'''
|
||||
HEAD_LIST = [u'ㄱ', u'ㄲ', u'ㄴ', u'ㄷ', u'ㄸ', u'ㄹ', u'ㅁ', u'ㅂ', u'ㅃ', u'ㅅ', u'ㅆ',
|
||||
u'ㅇ', u'ㅈ', u'ㅉ', u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
|
||||
BODY_LIST = [u'ㅏ', u'ㅐ', u'ㅑ', u'ㅒ', u'ㅓ', u'ㅔ', u'ㅕ', u'ㅖ', u'ㅗ', u'ㅘ', u'ㅙ',
|
||||
u'ㅚ', u'ㅛ', u'ㅜ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅠ', u'ㅡ', u'ㅢ', u'ㅣ']
|
||||
TAIL_LIST = [u' ', u'ㄱ', u'ㄲ', u'ㄳ', u'ㄴ', u'ㄵ', u'ㄶ', u'ㄷ', u'ㄹ', u'ㄺ', u'ㄻ',
|
||||
u'ㄼ', u'ㄽ', u'ㄾ', u'ㄿ', u'ㅀ', u'ㅁ', u'ㅂ', u'ㅄ', u'ㅅ', u'ㅆ', u'ㅇ', u'ㅈ',
|
||||
u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
|
||||
DOUBLE_LIST = [u'ㅘ', u'ㅙ', u'ㅚ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅢ', u'ㄳ', u'ㄵ', u'ㄶ', u'ㄺ',
|
||||
u'ㄻ', u'ㄼ', u'ㄽ', u'ㄾ', u'ㅀ', u'ㅄ']
|
||||
DOUBLE_MOD_LIST = [u'ㅗㅏ', u'ㅗㅐ', u'ㅗㅣ', u'ㅜㅓ', u'ㅜㅔ', u'ㅜㅣ', u'ㅡㅣ', u'ㄱㅅ',
|
||||
u'ㄴㅈ', u'ㄴㅎ', u'ㄹㄱ', u'ㄹㅁ', u'ㄹㅂ', u'ㄹㅅ', u'ㄹㅌ', u'ㄹㅎ', u'ㅂㅅ']
|
||||
HEAD_LIST = [
|
||||
u'ㄱ', u'ㄲ', u'ㄴ', u'ㄷ', u'ㄸ', u'ㄹ', u'ㅁ', u'ㅂ', u'ㅃ', u'ㅅ', u'ㅆ',
|
||||
u'ㅇ', u'ㅈ', u'ㅉ', u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ'
|
||||
]
|
||||
BODY_LIST = [
|
||||
u'ㅏ', u'ㅐ', u'ㅑ', u'ㅒ', u'ㅓ', u'ㅔ', u'ㅕ', u'ㅖ', u'ㅗ', u'ㅘ', u'ㅙ',
|
||||
u'ㅚ', u'ㅛ', u'ㅜ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅠ', u'ㅡ', u'ㅢ', u'ㅣ'
|
||||
]
|
||||
TAIL_LIST = [
|
||||
u' ', u'ㄱ', u'ㄲ', u'ㄳ', u'ㄴ', u'ㄵ', u'ㄶ', u'ㄷ', u'ㄹ', u'ㄺ', u'ㄻ',
|
||||
u'ㄼ', u'ㄽ', u'ㄾ', u'ㄿ', u'ㅀ', u'ㅁ', u'ㅂ', u'ㅄ', u'ㅅ', u'ㅆ', u'ㅇ', u'ㅈ',
|
||||
u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ'
|
||||
]
|
||||
DOUBLE_LIST = [
|
||||
u'ㅘ', u'ㅙ', u'ㅚ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅢ', u'ㄳ', u'ㄵ', u'ㄶ', u'ㄺ',
|
||||
u'ㄻ', u'ㄼ', u'ㄽ', u'ㄾ', u'ㅀ', u'ㅄ'
|
||||
]
|
||||
DOUBLE_MOD_LIST = [
|
||||
u'ㅗㅏ', u'ㅗㅐ', u'ㅗㅣ', u'ㅜㅓ', u'ㅜㅔ', u'ㅜㅣ', u'ㅡㅣ', u'ㄱㅅ',
|
||||
u'ㄴㅈ', u'ㄴㅎ', u'ㄹㄱ', u'ㄹㅁ', u'ㄹㅂ', u'ㄹㅅ', u'ㄹㅌ', u'ㄹㅎ', u'ㅂㅅ'
|
||||
]
|
||||
|
||||
|
||||
@memoize
|
||||
|
|
@ -70,8 +84,10 @@ def _switch(ch, layout):
|
|||
def _switch_command(command, layout):
|
||||
# Layouts with different amount of characters than English
|
||||
if layout in source_to_target:
|
||||
return ''.join(source_to_target[layout].get(ch, ch)
|
||||
for ch in command.script)
|
||||
return ''.join(
|
||||
source_to_target[layout].get(ch, ch)
|
||||
for ch in command.script
|
||||
)
|
||||
|
||||
return ''.join(_switch(ch, layout) for ch in command.script)
|
||||
|
||||
|
|
@ -105,8 +121,10 @@ def match(command):
|
|||
return True
|
||||
|
||||
matched_layout = _get_matched_layout(command)
|
||||
return (matched_layout and
|
||||
_switch_command(command, matched_layout) != get_alias())
|
||||
return (
|
||||
matched_layout and
|
||||
_switch_command(command, matched_layout) != get_alias()
|
||||
)
|
||||
|
||||
|
||||
def get_new_command(command):
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue