This commit is contained in:
DashBing 2023-08-21 03:32:04 +00:00 committed by GitHub
commit f9ccade8d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
115 changed files with 1122 additions and 618 deletions

View File

@ -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

View File

@ -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
)

View File

@ -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)

View File

@ -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,

View File

@ -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()

View File

@ -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):

View File

@ -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'])

View File

@ -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'])

View File

@ -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

View File

@ -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:

View File

@ -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."""

View File

@ -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
#

View 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)

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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':

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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()
)
)

View File

@ -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):

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)
)

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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
)

View File

@ -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):

View File

@ -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)
)

View File

@ -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())

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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'
]

View File

@ -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')

View File

@ -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]

View File

@ -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())

View File

@ -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):

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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)
)

View File

@ -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