thefuck-leeguoo 3.41__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thefuck/__init__.py +0 -0
- thefuck/ai.py +765 -0
- thefuck/argument_parser.py +96 -0
- thefuck/conf.py +141 -0
- thefuck/const.py +111 -0
- thefuck/corrector.py +92 -0
- thefuck/entrypoints/__init__.py +0 -0
- thefuck/entrypoints/alias.py +28 -0
- thefuck/entrypoints/fix_command.py +105 -0
- thefuck/entrypoints/main.py +50 -0
- thefuck/entrypoints/not_configured.py +201 -0
- thefuck/entrypoints/setup.py +227 -0
- thefuck/entrypoints/shell_logger.py +79 -0
- thefuck/exceptions.py +10 -0
- thefuck/logs.py +255 -0
- thefuck/output_readers/__init__.py +20 -0
- thefuck/output_readers/read_log.py +108 -0
- thefuck/output_readers/rerun.py +72 -0
- thefuck/output_readers/shell_logger.py +60 -0
- thefuck/rules/__init__.py +0 -0
- thefuck/rules/adb_unknown_command.py +54 -0
- thefuck/rules/ag_literal.py +10 -0
- thefuck/rules/apt_get.py +50 -0
- thefuck/rules/apt_get_search.py +14 -0
- thefuck/rules/apt_invalid_operation.py +63 -0
- thefuck/rules/apt_list_upgradable.py +16 -0
- thefuck/rules/apt_upgrade.py +16 -0
- thefuck/rules/aws_cli.py +17 -0
- thefuck/rules/az_cli.py +17 -0
- thefuck/rules/brew_cask_dependency.py +33 -0
- thefuck/rules/brew_install.py +24 -0
- thefuck/rules/brew_link.py +15 -0
- thefuck/rules/brew_reinstall.py +19 -0
- thefuck/rules/brew_uninstall.py +14 -0
- thefuck/rules/brew_unknown_command.py +82 -0
- thefuck/rules/brew_update_formula.py +12 -0
- thefuck/rules/cargo.py +6 -0
- thefuck/rules/cargo_no_command.py +15 -0
- thefuck/rules/cat_dir.py +14 -0
- thefuck/rules/cd_correction.py +61 -0
- thefuck/rules/cd_cs.py +21 -0
- thefuck/rules/cd_mkdir.py +21 -0
- thefuck/rules/cd_parent.py +16 -0
- thefuck/rules/chmod_x.py +15 -0
- thefuck/rules/choco_install.py +25 -0
- thefuck/rules/composer_not_command.py +22 -0
- thefuck/rules/conda_mistype.py +17 -0
- thefuck/rules/cp_create_destination.py +15 -0
- thefuck/rules/cp_omitting_directory.py +15 -0
- thefuck/rules/cpp11.py +12 -0
- thefuck/rules/dirty_untar.py +53 -0
- thefuck/rules/dirty_unzip.py +60 -0
- thefuck/rules/django_south_ghost.py +8 -0
- thefuck/rules/django_south_merge.py +8 -0
- thefuck/rules/dnf_no_such_command.py +37 -0
- thefuck/rules/docker_image_being_used_by_container.py +20 -0
- thefuck/rules/docker_login.py +13 -0
- thefuck/rules/docker_not_command.py +49 -0
- thefuck/rules/dry.py +15 -0
- thefuck/rules/fab_command_not_found.py +38 -0
- thefuck/rules/fix_alt_space.py +15 -0
- thefuck/rules/fix_file.py +80 -0
- thefuck/rules/gem_unknown_command.py +36 -0
- thefuck/rules/git_add.py +27 -0
- thefuck/rules/git_add_force.py +13 -0
- thefuck/rules/git_bisect_usage.py +16 -0
- thefuck/rules/git_branch_0flag.py +24 -0
- thefuck/rules/git_branch_delete.py +13 -0
- thefuck/rules/git_branch_delete_checked_out.py +19 -0
- thefuck/rules/git_branch_exists.py +25 -0
- thefuck/rules/git_branch_list.py +14 -0
- thefuck/rules/git_checkout.py +49 -0
- thefuck/rules/git_clone_git_clone.py +12 -0
- thefuck/rules/git_clone_missing.py +42 -0
- thefuck/rules/git_commit_add.py +17 -0
- thefuck/rules/git_commit_amend.py +11 -0
- thefuck/rules/git_commit_reset.py +11 -0
- thefuck/rules/git_diff_no_index.py +16 -0
- thefuck/rules/git_diff_staged.py +13 -0
- thefuck/rules/git_fix_stash.py +37 -0
- thefuck/rules/git_flag_after_filename.py +31 -0
- thefuck/rules/git_help_aliased.py +12 -0
- thefuck/rules/git_hook_bypass.py +27 -0
- thefuck/rules/git_lfs_mistype.py +18 -0
- thefuck/rules/git_main_master.py +16 -0
- thefuck/rules/git_merge.py +18 -0
- thefuck/rules/git_merge_unrelated.py +12 -0
- thefuck/rules/git_not_command.py +18 -0
- thefuck/rules/git_pull.py +16 -0
- thefuck/rules/git_pull_clone.py +13 -0
- thefuck/rules/git_pull_uncommitted_changes.py +14 -0
- thefuck/rules/git_push.py +44 -0
- thefuck/rules/git_push_different_branch_names.py +12 -0
- thefuck/rules/git_push_force.py +18 -0
- thefuck/rules/git_push_pull.py +20 -0
- thefuck/rules/git_push_without_commits.py +12 -0
- thefuck/rules/git_rebase_merge_dir.py +17 -0
- thefuck/rules/git_rebase_no_changes.py +13 -0
- thefuck/rules/git_remote_delete.py +13 -0
- thefuck/rules/git_remote_seturl_add.py +12 -0
- thefuck/rules/git_rm_local_modifications.py +19 -0
- thefuck/rules/git_rm_recursive.py +16 -0
- thefuck/rules/git_rm_staged.py +19 -0
- thefuck/rules/git_stash.py +15 -0
- thefuck/rules/git_stash_pop.py +18 -0
- thefuck/rules/git_tag_force.py +13 -0
- thefuck/rules/git_two_dashes.py +14 -0
- thefuck/rules/go_run.py +16 -0
- thefuck/rules/go_unknown_command.py +28 -0
- thefuck/rules/gradle_no_task.py +34 -0
- thefuck/rules/gradle_wrapper.py +13 -0
- thefuck/rules/grep_arguments_order.py +23 -0
- thefuck/rules/grep_recursive.py +10 -0
- thefuck/rules/grunt_task_not_found.py +37 -0
- thefuck/rules/gulp_not_task.py +22 -0
- thefuck/rules/has_exists_script.py +13 -0
- thefuck/rules/heroku_multiple_apps.py +12 -0
- thefuck/rules/heroku_not_command.py +11 -0
- thefuck/rules/history.py +15 -0
- thefuck/rules/hostscli.py +27 -0
- thefuck/rules/ifconfig_device_not_found.py +23 -0
- thefuck/rules/java.py +17 -0
- thefuck/rules/javac.py +18 -0
- thefuck/rules/lein_not_task.py +19 -0
- thefuck/rules/ln_no_hard_link.py +23 -0
- thefuck/rules/ln_s_order.py +26 -0
- thefuck/rules/long_form_help.py +27 -0
- thefuck/rules/ls_all.py +10 -0
- thefuck/rules/ls_lah.py +12 -0
- thefuck/rules/man.py +33 -0
- thefuck/rules/man_no_space.py +10 -0
- thefuck/rules/mercurial.py +27 -0
- thefuck/rules/missing_space_before_subcommand.py +21 -0
- thefuck/rules/mkdir_p.py +13 -0
- thefuck/rules/mvn_no_command.py +11 -0
- thefuck/rules/mvn_unknown_lifecycle_phase.py +30 -0
- thefuck/rules/nixos_cmd_not_found.py +15 -0
- thefuck/rules/no_command.py +41 -0
- thefuck/rules/no_such_file.py +30 -0
- thefuck/rules/npm_missing_script.py +17 -0
- thefuck/rules/npm_run_script.py +17 -0
- thefuck/rules/npm_wrong_command.py +42 -0
- thefuck/rules/omnienv_no_such_command.py +35 -0
- thefuck/rules/open.py +40 -0
- thefuck/rules/pacman.py +17 -0
- thefuck/rules/pacman_invalid_option.py +20 -0
- thefuck/rules/pacman_not_found.py +26 -0
- thefuck/rules/path_from_history.py +53 -0
- thefuck/rules/php_s.py +11 -0
- thefuck/rules/pip_install.py +15 -0
- thefuck/rules/pip_unknown_command.py +19 -0
- thefuck/rules/port_already_in_use.py +40 -0
- thefuck/rules/prove_recursively.py +27 -0
- thefuck/rules/python_command.py +17 -0
- thefuck/rules/python_execute.py +15 -0
- thefuck/rules/python_module_error.py +13 -0
- thefuck/rules/quotation_marks.py +12 -0
- thefuck/rules/rails_migrations_pending.py +14 -0
- thefuck/rules/react_native_command_unrecognized.py +34 -0
- thefuck/rules/remove_shell_prompt_literal.py +23 -0
- thefuck/rules/remove_trailing_cedilla.py +11 -0
- thefuck/rules/rm_dir.py +16 -0
- thefuck/rules/rm_root.py +16 -0
- thefuck/rules/scm_correction.py +32 -0
- thefuck/rules/sed_unterminated_s.py +18 -0
- thefuck/rules/sl_ls.py +14 -0
- thefuck/rules/ssh_known_hosts.py +37 -0
- thefuck/rules/sudo.py +47 -0
- thefuck/rules/sudo_command_from_user_path.py +21 -0
- thefuck/rules/switch_lang.py +117 -0
- thefuck/rules/systemctl.py +22 -0
- thefuck/rules/terraform_init.py +13 -0
- thefuck/rules/terraform_no_command.py +16 -0
- thefuck/rules/test.py.py +10 -0
- thefuck/rules/tmux.py +18 -0
- thefuck/rules/touch.py +14 -0
- thefuck/rules/tsuru_login.py +12 -0
- thefuck/rules/tsuru_not_command.py +15 -0
- thefuck/rules/unknown_command.py +13 -0
- thefuck/rules/unsudo.py +15 -0
- thefuck/rules/vagrant_up.py +21 -0
- thefuck/rules/whois.py +34 -0
- thefuck/rules/workon_doesnt_exists.py +32 -0
- thefuck/rules/wrong_hyphen_before_subcommand.py +20 -0
- thefuck/rules/yarn_alias.py +14 -0
- thefuck/rules/yarn_command_not_found.py +43 -0
- thefuck/rules/yarn_command_replaced.py +13 -0
- thefuck/rules/yarn_help.py +17 -0
- thefuck/rules/yum_invalid_operation.py +39 -0
- thefuck/shells/__init__.py +52 -0
- thefuck/shells/bash.py +94 -0
- thefuck/shells/fish.py +131 -0
- thefuck/shells/generic.py +154 -0
- thefuck/shells/powershell.py +43 -0
- thefuck/shells/tcsh.py +44 -0
- thefuck/shells/zsh.py +98 -0
- thefuck/specific/__init__.py +0 -0
- thefuck/specific/apt.py +3 -0
- thefuck/specific/archlinux.py +48 -0
- thefuck/specific/brew.py +15 -0
- thefuck/specific/dnf.py +3 -0
- thefuck/specific/git.py +32 -0
- thefuck/specific/nix.py +3 -0
- thefuck/specific/npm.py +21 -0
- thefuck/specific/sudo.py +18 -0
- thefuck/specific/yum.py +3 -0
- thefuck/system/__init__.py +7 -0
- thefuck/system/unix.py +57 -0
- thefuck/system/win32.py +43 -0
- thefuck/types.py +261 -0
- thefuck/ui.py +116 -0
- thefuck/utils.py +385 -0
- thefuck_leeguoo-3.41.dist-info/METADATA +681 -0
- thefuck_leeguoo-3.41.dist-info/RECORD +218 -0
- thefuck_leeguoo-3.41.dist-info/WHEEL +6 -0
- thefuck_leeguoo-3.41.dist-info/entry_points.txt +3 -0
- thefuck_leeguoo-3.41.dist-info/licenses/LICENSE.md +22 -0
- thefuck_leeguoo-3.41.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from thefuck.utils import for_app, memoize
|
|
2
|
+
from thefuck.system import Path
|
|
3
|
+
|
|
4
|
+
path_to_scm = {
|
|
5
|
+
'.git': 'git',
|
|
6
|
+
'.hg': 'hg',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
wrong_scm_patterns = {
|
|
10
|
+
'git': 'fatal: Not a git repository',
|
|
11
|
+
'hg': 'abort: no repository found',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@memoize
|
|
16
|
+
def _get_actual_scm():
|
|
17
|
+
for path, scm in path_to_scm.items():
|
|
18
|
+
if Path(path).is_dir():
|
|
19
|
+
return scm
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@for_app(*wrong_scm_patterns.keys())
|
|
23
|
+
def match(command):
|
|
24
|
+
scm = command.script_parts[0]
|
|
25
|
+
pattern = wrong_scm_patterns[scm]
|
|
26
|
+
|
|
27
|
+
return pattern in command.output and _get_actual_scm()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_new_command(command):
|
|
31
|
+
scm = _get_actual_scm()
|
|
32
|
+
return u' '.join([scm] + command.script_parts[1:])
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import shlex
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
from thefuck.utils import for_app
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@for_app('sed')
|
|
7
|
+
def match(command):
|
|
8
|
+
return "unterminated `s' command" in command.output
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
script = shlex.split(command.script)
|
|
13
|
+
|
|
14
|
+
for (i, e) in enumerate(script):
|
|
15
|
+
if e.startswith(('s/', '-es/')) and e[-1] != '/':
|
|
16
|
+
script[i] += '/'
|
|
17
|
+
|
|
18
|
+
return ' '.join(map(shell.quote, script))
|
thefuck/rules/sl_ls.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
commands = ('ssh', 'scp')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@for_app(*commands)
|
|
8
|
+
def match(command):
|
|
9
|
+
if not command.script:
|
|
10
|
+
return False
|
|
11
|
+
if not command.script.startswith(commands):
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
patterns = (
|
|
15
|
+
r'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!',
|
|
16
|
+
r'WARNING: POSSIBLE DNS SPOOFING DETECTED!',
|
|
17
|
+
r"Warning: the \S+ host key for '([^']+)' differs from the key for the IP address '([^']+)'",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return any(re.findall(pattern, command.output) for pattern in patterns)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_new_command(command):
|
|
24
|
+
return command.script
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def side_effect(old_cmd, command):
|
|
28
|
+
offending_pattern = re.compile(
|
|
29
|
+
r'(?:Offending (?:key for IP|\S+ key)|Matching host key) in ([^:]+):(\d+)',
|
|
30
|
+
re.MULTILINE)
|
|
31
|
+
offending = offending_pattern.findall(old_cmd.output)
|
|
32
|
+
for filepath, lineno in offending:
|
|
33
|
+
with open(filepath, 'r') as fh:
|
|
34
|
+
lines = fh.readlines()
|
|
35
|
+
del lines[int(lineno) - 1]
|
|
36
|
+
with open(filepath, 'w') as fh:
|
|
37
|
+
fh.writelines(lines)
|
thefuck/rules/sudo.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
patterns = ['permission denied',
|
|
2
|
+
'eacces',
|
|
3
|
+
'pkg: insufficient privileges',
|
|
4
|
+
'you cannot perform this operation unless you are root',
|
|
5
|
+
'non-root users cannot',
|
|
6
|
+
'operation not permitted',
|
|
7
|
+
'not super-user',
|
|
8
|
+
'superuser privilege',
|
|
9
|
+
'root privilege',
|
|
10
|
+
'this command has to be run under the root user.',
|
|
11
|
+
'this operation requires root.',
|
|
12
|
+
'requested operation requires superuser privilege',
|
|
13
|
+
'must be run as root',
|
|
14
|
+
'must run as root',
|
|
15
|
+
'must be superuser',
|
|
16
|
+
'must be root',
|
|
17
|
+
'need to be root',
|
|
18
|
+
'need root',
|
|
19
|
+
'needs to be run as root',
|
|
20
|
+
'only root can ',
|
|
21
|
+
'you don\'t have access to the history db.',
|
|
22
|
+
'authentication is required',
|
|
23
|
+
'edspermissionerror',
|
|
24
|
+
'you don\'t have write permissions',
|
|
25
|
+
'use `sudo`',
|
|
26
|
+
'sudorequirederror',
|
|
27
|
+
'error: insufficient privileges',
|
|
28
|
+
'updatedb: can not open a temporary file']
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def match(command):
|
|
32
|
+
if command.script_parts and '&&' not in command.script_parts and command.script_parts[0] == 'sudo':
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
for pattern in patterns:
|
|
36
|
+
if pattern in command.output.lower():
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_new_command(command):
|
|
42
|
+
if '&&' in command.script:
|
|
43
|
+
return u'sudo sh -c "{}"'.format(" ".join([part for part in command.script_parts if part != "sudo"]))
|
|
44
|
+
elif '>' in command.script:
|
|
45
|
+
return u'sudo sh -c "{}"'.format(command.script.replace('"', '\\"'))
|
|
46
|
+
else:
|
|
47
|
+
return u'sudo {}'.format(command.script)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import for_app, which, replace_argument
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _get_command_name(command):
|
|
6
|
+
found = re.findall(r'sudo: (.*): command not found', command.output)
|
|
7
|
+
if found:
|
|
8
|
+
return found[0]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@for_app('sudo')
|
|
12
|
+
def match(command):
|
|
13
|
+
if 'command not found' in command.output:
|
|
14
|
+
command_name = _get_command_name(command)
|
|
15
|
+
return which(command_name)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_new_command(command):
|
|
19
|
+
command_name = _get_command_name(command)
|
|
20
|
+
return replace_argument(command.script, command_name,
|
|
21
|
+
u'env "PATH=$PATH" {}'.format(command_name))
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
from thefuck.utils import memoize, get_alias
|
|
3
|
+
|
|
4
|
+
target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?'''
|
|
5
|
+
# any new keyboard layout must be appended
|
|
6
|
+
|
|
7
|
+
greek = u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?'''
|
|
8
|
+
korean = u'''ㅂㅈㄷㄱㅅㅛㅕㅑㅐㅔ[]ㅁㄴㅇㄹㅎㅗㅓㅏㅣ;'ㅋㅌㅊㅍㅠㅜㅡ,./ㅃㅉㄸㄲㅆㅛㅕㅑㅒㅖ{}ㅁㄴㅇㄹㅎㅗㅓㅏㅣ:"ㅋㅌㅊㅍㅠㅜㅡ<>?'''
|
|
9
|
+
|
|
10
|
+
source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
|
|
11
|
+
u'''йцукенгшщзхїфівапролджєячсмитьбю.ЙЦУКЕНГШЩЗХЇФІВАПРОЛДЖЄЯЧСМИТЬБЮ,''',
|
|
12
|
+
u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
|
|
13
|
+
u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''',
|
|
14
|
+
greek,
|
|
15
|
+
korean]
|
|
16
|
+
|
|
17
|
+
source_to_target = {
|
|
18
|
+
greek: {u';': "q", u'ς': "w", u'ε': "e", u'ρ': "r", u'τ': "t", u'υ': "y",
|
|
19
|
+
u'θ': "u", u'ι': "i", u'ο': "o", u'π': "p", u'[': "[", u']': "]",
|
|
20
|
+
u'α': "a", u'σ': "s", u'δ': "d", u'φ': "f", u'γ': "g", u'η': "h",
|
|
21
|
+
u'ξ': "j", u'κ': "k", u'λ': "l", u'΄': "'", u'ζ': "z", u'χ': "x",
|
|
22
|
+
u'ψ': "c", u'ω': "v", u'β': "b", u'ν': "n", u'μ': "m", u',': ",",
|
|
23
|
+
u'.': ".", u'/': "/", u':': "Q", u'΅': "W", u'Ε': "E", u'Ρ': "R",
|
|
24
|
+
u'Τ': "T", u'Υ': "Y", u'Θ': "U", u'Ι': "I", u'Ο': "O", u'Π': "P",
|
|
25
|
+
u'{': "{", u'}': "}", u'Α': "A", u'Σ': "S", u'Δ': "D", u'Φ': "F",
|
|
26
|
+
u'Γ': "G", u'Η': "H", u'Ξ': "J", u'Κ': "K", u'Λ': "L", u'¨': ":",
|
|
27
|
+
u'"': '"', u'Ζ': "Z", u'Χ': "X", u'Ψ': "C", u'Ω': "V", u'Β': "B",
|
|
28
|
+
u'Ν': "N", u'Μ': "M", u'<': "<", u'>': ">", u'?': "?", u'ά': "a",
|
|
29
|
+
u'έ': "e", u'ύ': "y", u'ί': "i", u'ό': "o", u'ή': 'h', u'ώ': u"v",
|
|
30
|
+
u'Ά': "A", u'Έ': "E", u'Ύ': "Y", u'Ί': "I", u'Ό': "O", u'Ή': "H",
|
|
31
|
+
u'Ώ': "V"},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
'''Lists used for decomposing korean letters.'''
|
|
35
|
+
HEAD_LIST = [u'ㄱ', u'ㄲ', u'ㄴ', u'ㄷ', u'ㄸ', u'ㄹ', u'ㅁ', u'ㅂ', u'ㅃ', u'ㅅ', u'ㅆ',
|
|
36
|
+
u'ㅇ', u'ㅈ', u'ㅉ', u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
|
|
37
|
+
BODY_LIST = [u'ㅏ', u'ㅐ', u'ㅑ', u'ㅒ', u'ㅓ', u'ㅔ', u'ㅕ', u'ㅖ', u'ㅗ', u'ㅘ', u'ㅙ',
|
|
38
|
+
u'ㅚ', u'ㅛ', u'ㅜ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅠ', u'ㅡ', u'ㅢ', u'ㅣ']
|
|
39
|
+
TAIL_LIST = [u' ', u'ㄱ', u'ㄲ', u'ㄳ', u'ㄴ', u'ㄵ', u'ㄶ', u'ㄷ', u'ㄹ', u'ㄺ', u'ㄻ',
|
|
40
|
+
u'ㄼ', u'ㄽ', u'ㄾ', u'ㄿ', u'ㅀ', u'ㅁ', u'ㅂ', u'ㅄ', u'ㅅ', u'ㅆ', u'ㅇ', u'ㅈ',
|
|
41
|
+
u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
|
|
42
|
+
DOUBLE_LIST = [u'ㅘ', u'ㅙ', u'ㅚ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅢ', u'ㄳ', u'ㄵ', u'ㄶ', u'ㄺ',
|
|
43
|
+
u'ㄻ', u'ㄼ', u'ㄽ', u'ㄾ', u'ㅀ', u'ㅄ']
|
|
44
|
+
DOUBLE_MOD_LIST = [u'ㅗㅏ', u'ㅗㅐ', u'ㅗㅣ', u'ㅜㅓ', u'ㅜㅔ', u'ㅜㅣ', u'ㅡㅣ', u'ㄱㅅ',
|
|
45
|
+
u'ㄴㅈ', u'ㄴㅎ', u'ㄹㄱ', u'ㄹㅁ', u'ㄹㅂ', u'ㄹㅅ', u'ㄹㅌ', u'ㄹㅎ', u'ㅂㅅ']
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@memoize
|
|
49
|
+
def _get_matched_layout(command):
|
|
50
|
+
# don't use command.split_script here because a layout mismatch will likely
|
|
51
|
+
# result in a non-splitable script as per shlex
|
|
52
|
+
cmd = command.script.split(' ')
|
|
53
|
+
for source_layout in source_layouts:
|
|
54
|
+
is_all_match = True
|
|
55
|
+
for cmd_part in cmd:
|
|
56
|
+
if not all([ch in source_layout or ch in '-_' for ch in cmd_part]):
|
|
57
|
+
is_all_match = False
|
|
58
|
+
break
|
|
59
|
+
|
|
60
|
+
if is_all_match:
|
|
61
|
+
return source_layout
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _switch(ch, layout):
|
|
65
|
+
if ch in layout:
|
|
66
|
+
return target_layout[layout.index(ch)]
|
|
67
|
+
return ch
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _switch_command(command, layout):
|
|
71
|
+
# Layouts with different amount of characters than English
|
|
72
|
+
if layout in source_to_target:
|
|
73
|
+
return ''.join(source_to_target[layout].get(ch, ch)
|
|
74
|
+
for ch in command.script)
|
|
75
|
+
|
|
76
|
+
return ''.join(_switch(ch, layout) for ch in command.script)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _decompose_korean(command):
|
|
80
|
+
def _change_double(ch):
|
|
81
|
+
if ch in DOUBLE_LIST:
|
|
82
|
+
return DOUBLE_MOD_LIST[DOUBLE_LIST.index(ch)]
|
|
83
|
+
return ch
|
|
84
|
+
|
|
85
|
+
hg_str = u''
|
|
86
|
+
for ch in command.script:
|
|
87
|
+
if u'가' <= ch <= u'힣':
|
|
88
|
+
ord_ch = ord(ch) - ord(u'가')
|
|
89
|
+
hd = ord_ch // 588
|
|
90
|
+
bd = (ord_ch - 588 * hd) // 28
|
|
91
|
+
tl = ord_ch - 588 * hd - 28 * bd
|
|
92
|
+
for ch in [HEAD_LIST[hd], BODY_LIST[bd], TAIL_LIST[tl]]:
|
|
93
|
+
if ch != ' ':
|
|
94
|
+
hg_str += _change_double(ch)
|
|
95
|
+
else:
|
|
96
|
+
hg_str += _change_double(ch)
|
|
97
|
+
return hg_str
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def match(command):
|
|
101
|
+
if 'not found' not in command.output:
|
|
102
|
+
return False
|
|
103
|
+
if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣'
|
|
104
|
+
for ch in command.script):
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
matched_layout = _get_matched_layout(command)
|
|
108
|
+
return (matched_layout and
|
|
109
|
+
_switch_command(command, matched_layout) != get_alias())
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def get_new_command(command):
|
|
113
|
+
if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣'
|
|
114
|
+
for ch in command.script):
|
|
115
|
+
command.script = _decompose_korean(command)
|
|
116
|
+
matched_layout = _get_matched_layout(command)
|
|
117
|
+
return _switch_command(command, matched_layout)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The confusion in systemctl's param order is massive.
|
|
3
|
+
"""
|
|
4
|
+
from thefuck.specific.sudo import sudo_support
|
|
5
|
+
from thefuck.utils import for_app
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@sudo_support
|
|
9
|
+
@for_app('systemctl')
|
|
10
|
+
def match(command):
|
|
11
|
+
# Catches "Unknown operation 'service'." when executing systemctl with
|
|
12
|
+
# misordered arguments
|
|
13
|
+
cmd = command.script_parts
|
|
14
|
+
return (cmd and 'Unknown operation \'' in command.output and
|
|
15
|
+
len(cmd) - cmd.index('systemctl') == 3)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@sudo_support
|
|
19
|
+
def get_new_command(command):
|
|
20
|
+
cmd = command.script_parts[:]
|
|
21
|
+
cmd[-1], cmd[-2] = cmd[-2], cmd[-1]
|
|
22
|
+
return ' '.join(cmd)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('terraform')
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('this module is not yet installed' in command.output.lower() or
|
|
8
|
+
'initialization required' in command.output.lower()
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
return shell.and_('terraform init', command.script)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
MISTAKE = r'(?<=Terraform has no command named ")([^"]+)(?="\.)'
|
|
5
|
+
FIX = r'(?<=Did you mean ")([^"]+)(?="\?)'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@for_app('terraform')
|
|
9
|
+
def match(command):
|
|
10
|
+
return re.search(MISTAKE, command.output) and re.search(FIX, command.output)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_new_command(command):
|
|
14
|
+
mistake = re.search(MISTAKE, command.output).group(0)
|
|
15
|
+
fix = re.search(FIX, command.output).group(0)
|
|
16
|
+
return command.script.replace(mistake, fix)
|
thefuck/rules/test.py.py
ADDED
thefuck/rules/tmux.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import replace_command, for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('tmux')
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('ambiguous command:' in command.output
|
|
8
|
+
and 'could be:' in command.output)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
cmd = re.match(r"ambiguous command: (.*), could be: (.*)",
|
|
13
|
+
command.output)
|
|
14
|
+
|
|
15
|
+
old_cmd = cmd.group(1)
|
|
16
|
+
suggestions = [c.strip() for c in cmd.group(2).split(',')]
|
|
17
|
+
|
|
18
|
+
return replace_command(command, old_cmd, suggestions)
|
thefuck/rules/touch.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
from thefuck.utils import for_app
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@for_app('touch')
|
|
7
|
+
def match(command):
|
|
8
|
+
return 'No such file or directory' in command.output
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
path = re.findall(
|
|
13
|
+
r"touch: (?:cannot touch ')?(.+)/.+'?:", command.output)[0]
|
|
14
|
+
return shell.and_(u'mkdir -p {}'.format(path), command.script)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('tsuru')
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('not authenticated' in command.output
|
|
8
|
+
and 'session has expired' in command.output)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
return shell.and_('tsuru login', command.script)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import get_all_matched_commands, replace_command, for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('tsuru')
|
|
6
|
+
def match(command):
|
|
7
|
+
return (' is not a tsuru command. See "tsuru help".' in command.output
|
|
8
|
+
and '\nDid you mean?\n\t' in command.output)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
broken_cmd = re.findall(r'tsuru: "([^"]*)" is not a tsuru command',
|
|
13
|
+
command.output)[0]
|
|
14
|
+
return replace_command(command, broken_cmd,
|
|
15
|
+
get_all_matched_commands(command.output))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import replace_command
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def match(command):
|
|
6
|
+
return (re.search(r"([^:]*): Unknown command.*", command.output) is not None
|
|
7
|
+
and re.search(r"Did you mean ([^?]*)?", command.output) is not None)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_new_command(command):
|
|
11
|
+
broken_cmd = re.findall(r"([^:]*): Unknown command.*", command.output)[0]
|
|
12
|
+
matched = re.findall(r"Did you mean ([^?]*)?", command.output)
|
|
13
|
+
return replace_command(command, broken_cmd, matched)
|
thefuck/rules/unsudo.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
patterns = ['you cannot perform this operation as root']
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def match(command):
|
|
5
|
+
if command.script_parts and command.script_parts[0] != 'sudo':
|
|
6
|
+
return False
|
|
7
|
+
|
|
8
|
+
for pattern in patterns:
|
|
9
|
+
if pattern in command.output.lower():
|
|
10
|
+
return True
|
|
11
|
+
return False
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_new_command(command):
|
|
15
|
+
return ' '.join(command.script_parts[1:])
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('vagrant')
|
|
6
|
+
def match(command):
|
|
7
|
+
return 'run `vagrant up`' in command.output.lower()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_new_command(command):
|
|
11
|
+
cmds = command.script_parts
|
|
12
|
+
machine = None
|
|
13
|
+
if len(cmds) >= 3:
|
|
14
|
+
machine = cmds[2]
|
|
15
|
+
|
|
16
|
+
start_all_instances = shell.and_(u"vagrant up", command.script)
|
|
17
|
+
if machine is None:
|
|
18
|
+
return start_all_instances
|
|
19
|
+
else:
|
|
20
|
+
return [shell.and_(u"vagrant up {}".format(machine), command.script),
|
|
21
|
+
start_all_instances]
|
thefuck/rules/whois.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
from six.moves.urllib.parse import urlparse
|
|
3
|
+
from thefuck.utils import for_app
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@for_app('whois', at_least=1)
|
|
7
|
+
def match(command):
|
|
8
|
+
"""
|
|
9
|
+
What the `whois` command returns depends on the 'Whois server' it contacted
|
|
10
|
+
and is not consistent through different servers. But there can be only two
|
|
11
|
+
types of errors I can think of with `whois`:
|
|
12
|
+
- `whois https://en.wikipedia.org/` → `whois en.wikipedia.org`;
|
|
13
|
+
- `whois en.wikipedia.org` → `whois wikipedia.org`.
|
|
14
|
+
So we match any `whois` command and then:
|
|
15
|
+
- if there is a slash: keep only the FQDN;
|
|
16
|
+
- if there is no slash but there is a point: removes the left-most
|
|
17
|
+
subdomain.
|
|
18
|
+
|
|
19
|
+
We cannot either remove all subdomains because we cannot know which part is
|
|
20
|
+
the subdomains and which is the domain, consider:
|
|
21
|
+
- www.google.fr → subdomain: www, domain: 'google.fr';
|
|
22
|
+
- google.co.uk → subdomain: None, domain; 'google.co.uk'.
|
|
23
|
+
"""
|
|
24
|
+
return True
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_new_command(command):
|
|
28
|
+
url = command.script_parts[1]
|
|
29
|
+
|
|
30
|
+
if '/' in command.script:
|
|
31
|
+
return 'whois ' + urlparse(url).netloc
|
|
32
|
+
elif '.' in command.script:
|
|
33
|
+
path = urlparse(url).path.split('.')
|
|
34
|
+
return ['whois ' + '.'.join(path[n:]) for n in range(1, len(path))]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from thefuck.utils import for_app, replace_command, eager, memoize
|
|
2
|
+
from thefuck.system import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@memoize
|
|
6
|
+
@eager
|
|
7
|
+
def _get_all_environments():
|
|
8
|
+
root = Path('~/.virtualenvs').expanduser()
|
|
9
|
+
if not root.is_dir():
|
|
10
|
+
return
|
|
11
|
+
|
|
12
|
+
for child in root.iterdir():
|
|
13
|
+
if child.is_dir():
|
|
14
|
+
yield child.name
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@for_app('workon')
|
|
18
|
+
def match(command):
|
|
19
|
+
return (len(command.script_parts) >= 2
|
|
20
|
+
and command.script_parts[1] not in _get_all_environments())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_new_command(command):
|
|
24
|
+
misspelled_env = command.script_parts[1]
|
|
25
|
+
create_new = u'mkvirtualenv {}'.format(misspelled_env)
|
|
26
|
+
|
|
27
|
+
available = _get_all_environments()
|
|
28
|
+
if available:
|
|
29
|
+
return (replace_command(command, misspelled_env, available)
|
|
30
|
+
+ [create_new])
|
|
31
|
+
else:
|
|
32
|
+
return create_new
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from thefuck.utils import get_all_executables
|
|
2
|
+
from thefuck.specific.sudo import sudo_support
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@sudo_support
|
|
6
|
+
def match(command):
|
|
7
|
+
first_part = command.script_parts[0]
|
|
8
|
+
if "-" not in first_part or first_part in get_all_executables():
|
|
9
|
+
return False
|
|
10
|
+
cmd, _ = first_part.split("-", 1)
|
|
11
|
+
return cmd in get_all_executables()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@sudo_support
|
|
15
|
+
def get_new_command(command):
|
|
16
|
+
return command.script.replace("-", " ", 1)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
priority = 4500
|
|
20
|
+
requires_output = False
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import replace_argument, for_app
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('yarn', at_least=1)
|
|
6
|
+
def match(command):
|
|
7
|
+
return 'Did you mean' in command.output
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_new_command(command):
|
|
11
|
+
broken = command.script_parts[1]
|
|
12
|
+
fix = re.findall(r'Did you mean [`"](?:yarn )?([^`"]*)[`"]', command.output)[0]
|
|
13
|
+
|
|
14
|
+
return replace_argument(command.script, broken, fix)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from subprocess import Popen, PIPE
|
|
3
|
+
from thefuck.utils import (for_app, eager, replace_command, replace_argument,
|
|
4
|
+
cache, which)
|
|
5
|
+
|
|
6
|
+
regex = re.compile(r'error Command "(.*)" not found.')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@for_app('yarn')
|
|
10
|
+
def match(command):
|
|
11
|
+
return regex.findall(command.output)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
npm_commands = {'require': 'add'}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@eager
|
|
18
|
+
def _get_all_tasks():
|
|
19
|
+
proc = Popen(['yarn', '--help'], stdout=PIPE)
|
|
20
|
+
should_yield = False
|
|
21
|
+
for line in proc.stdout.readlines():
|
|
22
|
+
line = line.decode().strip()
|
|
23
|
+
|
|
24
|
+
if 'Commands:' in line:
|
|
25
|
+
should_yield = True
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
if should_yield and '- ' in line:
|
|
29
|
+
yield line.split(' ')[-1]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if which('yarn'):
|
|
33
|
+
_get_all_tasks = cache(which('yarn'))(_get_all_tasks)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_new_command(command):
|
|
37
|
+
misspelled_task = regex.findall(command.output)[0]
|
|
38
|
+
if misspelled_task in npm_commands:
|
|
39
|
+
yarn_command = npm_commands[misspelled_task]
|
|
40
|
+
return replace_argument(command.script, misspelled_task, yarn_command)
|
|
41
|
+
else:
|
|
42
|
+
tasks = _get_all_tasks()
|
|
43
|
+
return replace_command(command, misspelled_task, tasks)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
|
|
4
|
+
regex = re.compile(r'Run "(.*)" instead')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@for_app('yarn', at_least=1)
|
|
8
|
+
def match(command):
|
|
9
|
+
return regex.findall(command.output)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
return regex.findall(command.output)[0]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import for_app
|
|
3
|
+
from thefuck.system import open_command
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@for_app('yarn', at_least=2)
|
|
7
|
+
def match(command):
|
|
8
|
+
return (command.script_parts[1] == 'help'
|
|
9
|
+
and 'for documentation about this command.' in command.output)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
url = re.findall(
|
|
14
|
+
r'Visit ([^ ]*) for documentation about this command.',
|
|
15
|
+
command.output)[0]
|
|
16
|
+
|
|
17
|
+
return open_command(url)
|