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.
Files changed (218) hide show
  1. thefuck/__init__.py +0 -0
  2. thefuck/ai.py +765 -0
  3. thefuck/argument_parser.py +96 -0
  4. thefuck/conf.py +141 -0
  5. thefuck/const.py +111 -0
  6. thefuck/corrector.py +92 -0
  7. thefuck/entrypoints/__init__.py +0 -0
  8. thefuck/entrypoints/alias.py +28 -0
  9. thefuck/entrypoints/fix_command.py +105 -0
  10. thefuck/entrypoints/main.py +50 -0
  11. thefuck/entrypoints/not_configured.py +201 -0
  12. thefuck/entrypoints/setup.py +227 -0
  13. thefuck/entrypoints/shell_logger.py +79 -0
  14. thefuck/exceptions.py +10 -0
  15. thefuck/logs.py +255 -0
  16. thefuck/output_readers/__init__.py +20 -0
  17. thefuck/output_readers/read_log.py +108 -0
  18. thefuck/output_readers/rerun.py +72 -0
  19. thefuck/output_readers/shell_logger.py +60 -0
  20. thefuck/rules/__init__.py +0 -0
  21. thefuck/rules/adb_unknown_command.py +54 -0
  22. thefuck/rules/ag_literal.py +10 -0
  23. thefuck/rules/apt_get.py +50 -0
  24. thefuck/rules/apt_get_search.py +14 -0
  25. thefuck/rules/apt_invalid_operation.py +63 -0
  26. thefuck/rules/apt_list_upgradable.py +16 -0
  27. thefuck/rules/apt_upgrade.py +16 -0
  28. thefuck/rules/aws_cli.py +17 -0
  29. thefuck/rules/az_cli.py +17 -0
  30. thefuck/rules/brew_cask_dependency.py +33 -0
  31. thefuck/rules/brew_install.py +24 -0
  32. thefuck/rules/brew_link.py +15 -0
  33. thefuck/rules/brew_reinstall.py +19 -0
  34. thefuck/rules/brew_uninstall.py +14 -0
  35. thefuck/rules/brew_unknown_command.py +82 -0
  36. thefuck/rules/brew_update_formula.py +12 -0
  37. thefuck/rules/cargo.py +6 -0
  38. thefuck/rules/cargo_no_command.py +15 -0
  39. thefuck/rules/cat_dir.py +14 -0
  40. thefuck/rules/cd_correction.py +61 -0
  41. thefuck/rules/cd_cs.py +21 -0
  42. thefuck/rules/cd_mkdir.py +21 -0
  43. thefuck/rules/cd_parent.py +16 -0
  44. thefuck/rules/chmod_x.py +15 -0
  45. thefuck/rules/choco_install.py +25 -0
  46. thefuck/rules/composer_not_command.py +22 -0
  47. thefuck/rules/conda_mistype.py +17 -0
  48. thefuck/rules/cp_create_destination.py +15 -0
  49. thefuck/rules/cp_omitting_directory.py +15 -0
  50. thefuck/rules/cpp11.py +12 -0
  51. thefuck/rules/dirty_untar.py +53 -0
  52. thefuck/rules/dirty_unzip.py +60 -0
  53. thefuck/rules/django_south_ghost.py +8 -0
  54. thefuck/rules/django_south_merge.py +8 -0
  55. thefuck/rules/dnf_no_such_command.py +37 -0
  56. thefuck/rules/docker_image_being_used_by_container.py +20 -0
  57. thefuck/rules/docker_login.py +13 -0
  58. thefuck/rules/docker_not_command.py +49 -0
  59. thefuck/rules/dry.py +15 -0
  60. thefuck/rules/fab_command_not_found.py +38 -0
  61. thefuck/rules/fix_alt_space.py +15 -0
  62. thefuck/rules/fix_file.py +80 -0
  63. thefuck/rules/gem_unknown_command.py +36 -0
  64. thefuck/rules/git_add.py +27 -0
  65. thefuck/rules/git_add_force.py +13 -0
  66. thefuck/rules/git_bisect_usage.py +16 -0
  67. thefuck/rules/git_branch_0flag.py +24 -0
  68. thefuck/rules/git_branch_delete.py +13 -0
  69. thefuck/rules/git_branch_delete_checked_out.py +19 -0
  70. thefuck/rules/git_branch_exists.py +25 -0
  71. thefuck/rules/git_branch_list.py +14 -0
  72. thefuck/rules/git_checkout.py +49 -0
  73. thefuck/rules/git_clone_git_clone.py +12 -0
  74. thefuck/rules/git_clone_missing.py +42 -0
  75. thefuck/rules/git_commit_add.py +17 -0
  76. thefuck/rules/git_commit_amend.py +11 -0
  77. thefuck/rules/git_commit_reset.py +11 -0
  78. thefuck/rules/git_diff_no_index.py +16 -0
  79. thefuck/rules/git_diff_staged.py +13 -0
  80. thefuck/rules/git_fix_stash.py +37 -0
  81. thefuck/rules/git_flag_after_filename.py +31 -0
  82. thefuck/rules/git_help_aliased.py +12 -0
  83. thefuck/rules/git_hook_bypass.py +27 -0
  84. thefuck/rules/git_lfs_mistype.py +18 -0
  85. thefuck/rules/git_main_master.py +16 -0
  86. thefuck/rules/git_merge.py +18 -0
  87. thefuck/rules/git_merge_unrelated.py +12 -0
  88. thefuck/rules/git_not_command.py +18 -0
  89. thefuck/rules/git_pull.py +16 -0
  90. thefuck/rules/git_pull_clone.py +13 -0
  91. thefuck/rules/git_pull_uncommitted_changes.py +14 -0
  92. thefuck/rules/git_push.py +44 -0
  93. thefuck/rules/git_push_different_branch_names.py +12 -0
  94. thefuck/rules/git_push_force.py +18 -0
  95. thefuck/rules/git_push_pull.py +20 -0
  96. thefuck/rules/git_push_without_commits.py +12 -0
  97. thefuck/rules/git_rebase_merge_dir.py +17 -0
  98. thefuck/rules/git_rebase_no_changes.py +13 -0
  99. thefuck/rules/git_remote_delete.py +13 -0
  100. thefuck/rules/git_remote_seturl_add.py +12 -0
  101. thefuck/rules/git_rm_local_modifications.py +19 -0
  102. thefuck/rules/git_rm_recursive.py +16 -0
  103. thefuck/rules/git_rm_staged.py +19 -0
  104. thefuck/rules/git_stash.py +15 -0
  105. thefuck/rules/git_stash_pop.py +18 -0
  106. thefuck/rules/git_tag_force.py +13 -0
  107. thefuck/rules/git_two_dashes.py +14 -0
  108. thefuck/rules/go_run.py +16 -0
  109. thefuck/rules/go_unknown_command.py +28 -0
  110. thefuck/rules/gradle_no_task.py +34 -0
  111. thefuck/rules/gradle_wrapper.py +13 -0
  112. thefuck/rules/grep_arguments_order.py +23 -0
  113. thefuck/rules/grep_recursive.py +10 -0
  114. thefuck/rules/grunt_task_not_found.py +37 -0
  115. thefuck/rules/gulp_not_task.py +22 -0
  116. thefuck/rules/has_exists_script.py +13 -0
  117. thefuck/rules/heroku_multiple_apps.py +12 -0
  118. thefuck/rules/heroku_not_command.py +11 -0
  119. thefuck/rules/history.py +15 -0
  120. thefuck/rules/hostscli.py +27 -0
  121. thefuck/rules/ifconfig_device_not_found.py +23 -0
  122. thefuck/rules/java.py +17 -0
  123. thefuck/rules/javac.py +18 -0
  124. thefuck/rules/lein_not_task.py +19 -0
  125. thefuck/rules/ln_no_hard_link.py +23 -0
  126. thefuck/rules/ln_s_order.py +26 -0
  127. thefuck/rules/long_form_help.py +27 -0
  128. thefuck/rules/ls_all.py +10 -0
  129. thefuck/rules/ls_lah.py +12 -0
  130. thefuck/rules/man.py +33 -0
  131. thefuck/rules/man_no_space.py +10 -0
  132. thefuck/rules/mercurial.py +27 -0
  133. thefuck/rules/missing_space_before_subcommand.py +21 -0
  134. thefuck/rules/mkdir_p.py +13 -0
  135. thefuck/rules/mvn_no_command.py +11 -0
  136. thefuck/rules/mvn_unknown_lifecycle_phase.py +30 -0
  137. thefuck/rules/nixos_cmd_not_found.py +15 -0
  138. thefuck/rules/no_command.py +41 -0
  139. thefuck/rules/no_such_file.py +30 -0
  140. thefuck/rules/npm_missing_script.py +17 -0
  141. thefuck/rules/npm_run_script.py +17 -0
  142. thefuck/rules/npm_wrong_command.py +42 -0
  143. thefuck/rules/omnienv_no_such_command.py +35 -0
  144. thefuck/rules/open.py +40 -0
  145. thefuck/rules/pacman.py +17 -0
  146. thefuck/rules/pacman_invalid_option.py +20 -0
  147. thefuck/rules/pacman_not_found.py +26 -0
  148. thefuck/rules/path_from_history.py +53 -0
  149. thefuck/rules/php_s.py +11 -0
  150. thefuck/rules/pip_install.py +15 -0
  151. thefuck/rules/pip_unknown_command.py +19 -0
  152. thefuck/rules/port_already_in_use.py +40 -0
  153. thefuck/rules/prove_recursively.py +27 -0
  154. thefuck/rules/python_command.py +17 -0
  155. thefuck/rules/python_execute.py +15 -0
  156. thefuck/rules/python_module_error.py +13 -0
  157. thefuck/rules/quotation_marks.py +12 -0
  158. thefuck/rules/rails_migrations_pending.py +14 -0
  159. thefuck/rules/react_native_command_unrecognized.py +34 -0
  160. thefuck/rules/remove_shell_prompt_literal.py +23 -0
  161. thefuck/rules/remove_trailing_cedilla.py +11 -0
  162. thefuck/rules/rm_dir.py +16 -0
  163. thefuck/rules/rm_root.py +16 -0
  164. thefuck/rules/scm_correction.py +32 -0
  165. thefuck/rules/sed_unterminated_s.py +18 -0
  166. thefuck/rules/sl_ls.py +14 -0
  167. thefuck/rules/ssh_known_hosts.py +37 -0
  168. thefuck/rules/sudo.py +47 -0
  169. thefuck/rules/sudo_command_from_user_path.py +21 -0
  170. thefuck/rules/switch_lang.py +117 -0
  171. thefuck/rules/systemctl.py +22 -0
  172. thefuck/rules/terraform_init.py +13 -0
  173. thefuck/rules/terraform_no_command.py +16 -0
  174. thefuck/rules/test.py.py +10 -0
  175. thefuck/rules/tmux.py +18 -0
  176. thefuck/rules/touch.py +14 -0
  177. thefuck/rules/tsuru_login.py +12 -0
  178. thefuck/rules/tsuru_not_command.py +15 -0
  179. thefuck/rules/unknown_command.py +13 -0
  180. thefuck/rules/unsudo.py +15 -0
  181. thefuck/rules/vagrant_up.py +21 -0
  182. thefuck/rules/whois.py +34 -0
  183. thefuck/rules/workon_doesnt_exists.py +32 -0
  184. thefuck/rules/wrong_hyphen_before_subcommand.py +20 -0
  185. thefuck/rules/yarn_alias.py +14 -0
  186. thefuck/rules/yarn_command_not_found.py +43 -0
  187. thefuck/rules/yarn_command_replaced.py +13 -0
  188. thefuck/rules/yarn_help.py +17 -0
  189. thefuck/rules/yum_invalid_operation.py +39 -0
  190. thefuck/shells/__init__.py +52 -0
  191. thefuck/shells/bash.py +94 -0
  192. thefuck/shells/fish.py +131 -0
  193. thefuck/shells/generic.py +154 -0
  194. thefuck/shells/powershell.py +43 -0
  195. thefuck/shells/tcsh.py +44 -0
  196. thefuck/shells/zsh.py +98 -0
  197. thefuck/specific/__init__.py +0 -0
  198. thefuck/specific/apt.py +3 -0
  199. thefuck/specific/archlinux.py +48 -0
  200. thefuck/specific/brew.py +15 -0
  201. thefuck/specific/dnf.py +3 -0
  202. thefuck/specific/git.py +32 -0
  203. thefuck/specific/nix.py +3 -0
  204. thefuck/specific/npm.py +21 -0
  205. thefuck/specific/sudo.py +18 -0
  206. thefuck/specific/yum.py +3 -0
  207. thefuck/system/__init__.py +7 -0
  208. thefuck/system/unix.py +57 -0
  209. thefuck/system/win32.py +43 -0
  210. thefuck/types.py +261 -0
  211. thefuck/ui.py +116 -0
  212. thefuck/utils.py +385 -0
  213. thefuck_leeguoo-3.41.dist-info/METADATA +681 -0
  214. thefuck_leeguoo-3.41.dist-info/RECORD +218 -0
  215. thefuck_leeguoo-3.41.dist-info/WHEEL +6 -0
  216. thefuck_leeguoo-3.41.dist-info/entry_points.txt +3 -0
  217. thefuck_leeguoo-3.41.dist-info/licenses/LICENSE.md +22 -0
  218. thefuck_leeguoo-3.41.dist-info/top_level.txt +1 -0
@@ -0,0 +1,53 @@
1
+ import tarfile
2
+ import os
3
+ from thefuck.utils import for_app
4
+ from thefuck.shells import shell
5
+
6
+
7
+ tar_extensions = ('.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
8
+ '.tar.lzma', '.tar.xz', '.taz', '.tb2', '.tbz', '.tbz2',
9
+ '.tgz', '.tlz', '.txz', '.tz')
10
+
11
+
12
+ def _is_tar_extract(cmd):
13
+ if '--extract' in cmd:
14
+ return True
15
+
16
+ cmd = cmd.split()
17
+
18
+ return len(cmd) > 1 and 'x' in cmd[1]
19
+
20
+
21
+ def _tar_file(cmd):
22
+ for c in cmd:
23
+ for ext in tar_extensions:
24
+ if c.endswith(ext):
25
+ return (c, c[0:len(c) - len(ext)])
26
+
27
+
28
+ @for_app('tar')
29
+ def match(command):
30
+ return ('-C' not in command.script
31
+ and _is_tar_extract(command.script)
32
+ and _tar_file(command.script_parts) is not None)
33
+
34
+
35
+ def get_new_command(command):
36
+ dir = shell.quote(_tar_file(command.script_parts)[1])
37
+ return shell.and_('mkdir -p {dir}', '{cmd} -C {dir}') \
38
+ .format(dir=dir, cmd=command.script)
39
+
40
+
41
+ def side_effect(old_cmd, command):
42
+ with tarfile.TarFile(_tar_file(old_cmd.script_parts)[0]) as archive:
43
+ for file in archive.getnames():
44
+ if not os.path.abspath(file).startswith(os.getcwd()):
45
+ # it's unsafe to overwrite files outside of the current directory
46
+ continue
47
+
48
+ try:
49
+ os.remove(file)
50
+ except OSError:
51
+ # does not try to remove directories as we cannot know if they
52
+ # already existed before
53
+ pass
@@ -0,0 +1,60 @@
1
+ import os
2
+ import zipfile
3
+ from thefuck.utils import for_app
4
+ from thefuck.shells import shell
5
+
6
+
7
+ def _is_bad_zip(file):
8
+ try:
9
+ with zipfile.ZipFile(file, 'r') as archive:
10
+ return len(archive.namelist()) > 1
11
+ except Exception:
12
+ return False
13
+
14
+
15
+ def _zip_file(command):
16
+ # unzip works that way:
17
+ # unzip [-flags] file[.zip] [file(s) ...] [-x file(s) ...]
18
+ # ^ ^ files to unzip from the archive
19
+ # archive to unzip
20
+ for c in command.script_parts[1:]:
21
+ if not c.startswith('-'):
22
+ if c.endswith('.zip'):
23
+ return c
24
+ else:
25
+ return u'{}.zip'.format(c)
26
+
27
+
28
+ @for_app('unzip')
29
+ def match(command):
30
+ if '-d' in command.script:
31
+ return False
32
+
33
+ zip_file = _zip_file(command)
34
+ if zip_file:
35
+ return _is_bad_zip(zip_file)
36
+ else:
37
+ return False
38
+
39
+
40
+ def get_new_command(command):
41
+ return u'{} -d {}'.format(
42
+ command.script, shell.quote(_zip_file(command)[:-4]))
43
+
44
+
45
+ def side_effect(old_cmd, command):
46
+ with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
47
+ for file in archive.namelist():
48
+ if not os.path.abspath(file).startswith(os.getcwd()):
49
+ # it's unsafe to overwrite files outside of the current directory
50
+ continue
51
+
52
+ try:
53
+ os.remove(file)
54
+ except OSError:
55
+ # does not try to remove directories as we cannot know if they
56
+ # already existed before
57
+ pass
58
+
59
+
60
+ requires_output = False
@@ -0,0 +1,8 @@
1
+ def match(command):
2
+ return 'manage.py' in command.script and \
3
+ 'migrate' in command.script \
4
+ and 'or pass --delete-ghost-migrations' in command.output
5
+
6
+
7
+ def get_new_command(command):
8
+ return u'{} --delete-ghost-migrations'.format(command.script)
@@ -0,0 +1,8 @@
1
+ def match(command):
2
+ return 'manage.py' in command.script and \
3
+ 'migrate' in command.script \
4
+ and '--merge: will just attempt the migration' in command.output
5
+
6
+
7
+ def get_new_command(command):
8
+ return u'{} --merge'.format(command.script)
@@ -0,0 +1,37 @@
1
+ import subprocess
2
+ import re
3
+ from thefuck.specific.sudo import sudo_support
4
+ from thefuck.utils import for_app, replace_command
5
+ from thefuck.specific.dnf import dnf_available
6
+
7
+
8
+ regex = re.compile(r'No such command: (.*)\.')
9
+
10
+
11
+ @sudo_support
12
+ @for_app('dnf')
13
+ def match(command):
14
+ return 'no such command' in command.output.lower()
15
+
16
+
17
+ def _parse_operations(help_text_lines):
18
+ operation_regex = re.compile(r'^([a-z-]+) +', re.MULTILINE)
19
+ return operation_regex.findall(help_text_lines)
20
+
21
+
22
+ def _get_operations():
23
+ proc = subprocess.Popen(["dnf", '--help'],
24
+ stdout=subprocess.PIPE,
25
+ stderr=subprocess.PIPE)
26
+ lines = proc.stdout.read().decode("utf-8")
27
+
28
+ return _parse_operations(lines)
29
+
30
+
31
+ @sudo_support
32
+ def get_new_command(command):
33
+ misspelled_command = regex.findall(command.output)[0]
34
+ return replace_command(command, misspelled_command, _get_operations())
35
+
36
+
37
+ enabled_by_default = dnf_available
@@ -0,0 +1,20 @@
1
+ from thefuck.utils import for_app
2
+ from thefuck.shells import shell
3
+
4
+
5
+ @for_app('docker')
6
+ def match(command):
7
+ '''
8
+ Matches a command's output with docker's output
9
+ warning you that you need to remove a container before removing an image.
10
+ '''
11
+ return 'image is being used by running container' in command.output
12
+
13
+
14
+ def get_new_command(command):
15
+ '''
16
+ Prepends docker container rm -f {container ID} to
17
+ the previous docker image rm {image ID} command
18
+ '''
19
+ container_id = command.output.strip().split(' ')
20
+ return shell.and_('docker container rm -f {}', '{}').format(container_id[-1], command.script)
@@ -0,0 +1,13 @@
1
+ from thefuck.utils import for_app
2
+ from thefuck.shells import shell
3
+
4
+
5
+ @for_app('docker')
6
+ def match(command):
7
+ return ('docker' in command.script
8
+ and "access denied" in command.output
9
+ and "may require 'docker login'" in command.output)
10
+
11
+
12
+ def get_new_command(command):
13
+ return shell.and_('docker login', command.script)
@@ -0,0 +1,49 @@
1
+ from itertools import dropwhile, takewhile, islice
2
+ import re
3
+ import subprocess
4
+ from thefuck.utils import replace_command, for_app, which, cache
5
+ from thefuck.specific.sudo import sudo_support
6
+
7
+
8
+ @sudo_support
9
+ @for_app('docker')
10
+ def match(command):
11
+ return 'is not a docker command' in command.output or 'Usage: docker' in command.output
12
+
13
+
14
+ def _parse_commands(lines, starts_with):
15
+ lines = dropwhile(lambda line: not line.startswith(starts_with), lines)
16
+ lines = islice(lines, 1, None)
17
+ lines = list(takewhile(lambda line: line.strip(), lines))
18
+ return [line.strip().split(' ')[0] for line in lines]
19
+
20
+
21
+ def get_docker_commands():
22
+ proc = subprocess.Popen('docker', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
23
+
24
+ # Old version docker returns its output to stdout, while newer version returns to stderr.
25
+ lines = proc.stdout.readlines() or proc.stderr.readlines()
26
+ lines = [line.decode('utf-8') for line in lines]
27
+
28
+ # Only newer versions of docker have management commands in the help text.
29
+ if 'Management Commands:\n' in lines:
30
+ management_commands = _parse_commands(lines, 'Management Commands:')
31
+ else:
32
+ management_commands = []
33
+ regular_commands = _parse_commands(lines, 'Commands:')
34
+ return management_commands + regular_commands
35
+
36
+
37
+ if which('docker'):
38
+ get_docker_commands = cache(which('docker'))(get_docker_commands)
39
+
40
+
41
+ @sudo_support
42
+ def get_new_command(command):
43
+ if 'Usage:' in command.output and len(command.script_parts) > 1:
44
+ management_subcommands = _parse_commands(command.output.split('\n'), 'Commands:')
45
+ return replace_command(command, command.script_parts[2], management_subcommands)
46
+
47
+ wrong_command = re.findall(
48
+ r"docker: '(\w+)' is not a docker command.", command.output)[0]
49
+ return replace_command(command, wrong_command, get_docker_commands())
thefuck/rules/dry.py ADDED
@@ -0,0 +1,15 @@
1
+ def match(command):
2
+ split_command = command.script_parts
3
+
4
+ return (split_command
5
+ and len(split_command) >= 2
6
+ and split_command[0] == split_command[1])
7
+
8
+
9
+ def get_new_command(command):
10
+ return ' '.join(command.script_parts[1:])
11
+
12
+
13
+ # it should be rare enough to actually have to type twice the same word, so
14
+ # this rule can have a higher priority to come before things like "cd cd foo"
15
+ priority = 900
@@ -0,0 +1,38 @@
1
+ from thefuck.utils import eager, get_closest, for_app
2
+
3
+
4
+ @for_app('fab')
5
+ def match(command):
6
+ return 'Warning: Command(s) not found:' in command.output
7
+
8
+
9
+ # We need different behavior then in get_all_matched_commands.
10
+ @eager
11
+ def _get_between(content, start, end=None):
12
+ should_yield = False
13
+ for line in content.split('\n'):
14
+ if start in line:
15
+ should_yield = True
16
+ continue
17
+
18
+ if end and end in line:
19
+ return
20
+
21
+ if should_yield and line:
22
+ yield line.strip().split(' ')[0]
23
+
24
+
25
+ def get_new_command(command):
26
+ not_found_commands = _get_between(
27
+ command.output, 'Warning: Command(s) not found:',
28
+ 'Available commands:')
29
+ possible_commands = _get_between(
30
+ command.output, 'Available commands:')
31
+
32
+ script = command.script
33
+ for not_found in not_found_commands:
34
+ fix = get_closest(not_found, possible_commands)
35
+ script = script.replace(' {}'.format(not_found),
36
+ ' {}'.format(fix))
37
+
38
+ return script
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ import re
4
+ from thefuck.specific.sudo import sudo_support
5
+
6
+
7
+ @sudo_support
8
+ def match(command):
9
+ return ('command not found' in command.output.lower()
10
+ and u' ' in command.script)
11
+
12
+
13
+ @sudo_support
14
+ def get_new_command(command):
15
+ return re.sub(u' ', ' ', command.script)
@@ -0,0 +1,80 @@
1
+ import re
2
+ import os
3
+ from thefuck.utils import memoize, default_settings
4
+ from thefuck.conf import settings
5
+ from thefuck.shells import shell
6
+
7
+
8
+ # order is important: only the first match is considered
9
+ patterns = (
10
+ # js, node:
11
+ '^ at {file}:{line}:{col}',
12
+ # cargo:
13
+ '^ {file}:{line}:{col}',
14
+ # python, thefuck:
15
+ '^ File "{file}", line {line}',
16
+ # awk:
17
+ '^awk: {file}:{line}:',
18
+ # git
19
+ '^fatal: bad config file line {line} in {file}',
20
+ # llc:
21
+ '^llc: {file}:{line}:{col}:',
22
+ # lua:
23
+ '^lua: {file}:{line}:',
24
+ # fish:
25
+ '^{file} \\(line {line}\\):',
26
+ # bash, sh, ssh:
27
+ '^{file}: line {line}: ',
28
+ # cargo, clang, gcc, go, pep8, rustc:
29
+ '^{file}:{line}:{col}',
30
+ # ghc, make, ruby, zsh:
31
+ '^{file}:{line}:',
32
+ # perl:
33
+ 'at {file} line {line}',
34
+ )
35
+
36
+
37
+ # for the sake of readability do not use named groups above
38
+ def _make_pattern(pattern):
39
+ pattern = pattern.replace('{file}', '(?P<file>[^:\n]+)') \
40
+ .replace('{line}', '(?P<line>[0-9]+)') \
41
+ .replace('{col}', '(?P<col>[0-9]+)')
42
+ return re.compile(pattern, re.MULTILINE)
43
+
44
+
45
+ patterns = [_make_pattern(p).search for p in patterns]
46
+
47
+
48
+ @memoize
49
+ def _search(output):
50
+ for pattern in patterns:
51
+ m = pattern(output)
52
+ if m and os.path.isfile(m.group('file')):
53
+ return m
54
+
55
+
56
+ def match(command):
57
+ if 'EDITOR' not in os.environ:
58
+ return False
59
+
60
+ return _search(command.output)
61
+
62
+
63
+ @default_settings({'fixlinecmd': u'{editor} {file} +{line}',
64
+ 'fixcolcmd': None})
65
+ def get_new_command(command):
66
+ m = _search(command.output)
67
+
68
+ # Note: there does not seem to be a standard for columns, so they are just
69
+ # ignored by default
70
+ if settings.fixcolcmd and 'col' in m.groupdict():
71
+ editor_call = settings.fixcolcmd.format(editor=os.environ['EDITOR'],
72
+ file=m.group('file'),
73
+ line=m.group('line'),
74
+ col=m.group('col'))
75
+ else:
76
+ editor_call = settings.fixlinecmd.format(editor=os.environ['EDITOR'],
77
+ file=m.group('file'),
78
+ line=m.group('line'))
79
+
80
+ return shell.and_(editor_call, command.script)
@@ -0,0 +1,36 @@
1
+ import re
2
+ import subprocess
3
+ from thefuck.utils import for_app, eager, replace_command, cache, which
4
+
5
+
6
+ @for_app('gem')
7
+ def match(command):
8
+ return ('ERROR: While executing gem ... (Gem::CommandLineError)'
9
+ in command.output
10
+ and 'Unknown command' in command.output)
11
+
12
+
13
+ def _get_unknown_command(command):
14
+ return re.findall(r'Unknown command (.*)$', command.output)[0]
15
+
16
+
17
+ @eager
18
+ def _get_all_commands():
19
+ proc = subprocess.Popen(['gem', 'help', 'commands'],
20
+ stdout=subprocess.PIPE)
21
+
22
+ for line in proc.stdout.readlines():
23
+ line = line.decode()
24
+
25
+ if line.startswith(' '):
26
+ yield line.strip().split(' ')[0]
27
+
28
+
29
+ if which('gem'):
30
+ _get_all_commands = cache(which('gem'))(_get_all_commands)
31
+
32
+
33
+ def get_new_command(command):
34
+ unknown_command = _get_unknown_command(command)
35
+ all_commands = _get_all_commands()
36
+ return replace_command(command, unknown_command, all_commands)
@@ -0,0 +1,27 @@
1
+ import re
2
+ from thefuck.shells import shell
3
+ from thefuck.specific.git import git_support
4
+ from thefuck.system import Path
5
+ from thefuck.utils import memoize
6
+
7
+
8
+ @memoize
9
+ def _get_missing_file(command):
10
+ pathspec = re.findall(
11
+ r"error: pathspec '([^']*)' "
12
+ r'did not match any file\(s\) known to git.', command.output)[0]
13
+ if Path(pathspec).exists():
14
+ return pathspec
15
+
16
+
17
+ @git_support
18
+ def match(command):
19
+ return ('did not match any file(s) known to git.' in command.output
20
+ and _get_missing_file(command))
21
+
22
+
23
+ @git_support
24
+ def get_new_command(command):
25
+ missing_file = _get_missing_file(command)
26
+ formatme = shell.and_('git add -- {}', '{}')
27
+ return formatme.format(missing_file, command.script)
@@ -0,0 +1,13 @@
1
+ from thefuck.utils import replace_argument
2
+ from thefuck.specific.git import git_support
3
+
4
+
5
+ @git_support
6
+ def match(command):
7
+ return ('add' in command.script_parts
8
+ and 'Use -f if you really want to add them.' in command.output)
9
+
10
+
11
+ @git_support
12
+ def get_new_command(command):
13
+ return replace_argument(command.script, 'add', 'add --force')
@@ -0,0 +1,16 @@
1
+ import re
2
+ from thefuck.utils import replace_command
3
+ from thefuck.specific.git import git_support
4
+
5
+
6
+ @git_support
7
+ def match(command):
8
+ return ('bisect' in command.script_parts and
9
+ 'usage: git bisect' in command.output)
10
+
11
+
12
+ @git_support
13
+ def get_new_command(command):
14
+ broken = re.findall(r'git bisect ([^ $]*).*', command.script)[0]
15
+ usage = re.findall(r'usage: git bisect \[([^\]]+)\]', command.output)[0]
16
+ return replace_command(command, broken, usage.split('|'))
@@ -0,0 +1,24 @@
1
+ from thefuck.shells import shell
2
+ from thefuck.specific.git import git_support
3
+ from thefuck.utils import memoize
4
+
5
+
6
+ @memoize
7
+ def first_0flag(script_parts):
8
+ return next((p for p in script_parts if len(p) == 2 and p.startswith("0")), None)
9
+
10
+
11
+ @git_support
12
+ def match(command):
13
+ return command.script_parts[1] == "branch" and first_0flag(command.script_parts)
14
+
15
+
16
+ @git_support
17
+ def get_new_command(command):
18
+ branch_name = first_0flag(command.script_parts)
19
+ fixed_flag = branch_name.replace("0", "-")
20
+ fixed_script = command.script.replace(branch_name, fixed_flag)
21
+ if "A branch named '" in command.output and "' already exists." in command.output:
22
+ delete_branch = u"git branch -D {}".format(branch_name)
23
+ return shell.and_(delete_branch, fixed_script)
24
+ return fixed_script
@@ -0,0 +1,13 @@
1
+ from thefuck.utils import replace_argument
2
+ from thefuck.specific.git import git_support
3
+
4
+
5
+ @git_support
6
+ def match(command):
7
+ return ('branch -d' in command.script
8
+ and 'If you are sure you want to delete it' in command.output)
9
+
10
+
11
+ @git_support
12
+ def get_new_command(command):
13
+ return replace_argument(command.script, '-d', '-D')
@@ -0,0 +1,19 @@
1
+ from thefuck.shells import shell
2
+ from thefuck.specific.git import git_support
3
+ from thefuck.utils import replace_argument
4
+
5
+
6
+ @git_support
7
+ def match(command):
8
+ return (
9
+ ("branch -d" in command.script or "branch -D" in command.script)
10
+ and "error: Cannot delete branch '" in command.output
11
+ and "' checked out at '" in command.output
12
+ )
13
+
14
+
15
+ @git_support
16
+ def get_new_command(command):
17
+ return shell.and_("git checkout master", "{}").format(
18
+ replace_argument(command.script, "-d", "-D")
19
+ )
@@ -0,0 +1,25 @@
1
+ import re
2
+ from thefuck.shells import shell
3
+ from thefuck.specific.git import git_support
4
+ from thefuck.utils import eager
5
+
6
+
7
+ @git_support
8
+ def match(command):
9
+ return ("fatal: A branch named '" in command.output
10
+ and "' already exists." in command.output)
11
+
12
+
13
+ @git_support
14
+ @eager
15
+ def get_new_command(command):
16
+ branch_name = re.findall(
17
+ r"fatal: A branch named '(.+)' already exists.", command.output)[0]
18
+ branch_name = branch_name.replace("'", r"\'")
19
+ new_command_templates = [['git branch -d {0}', 'git branch {0}'],
20
+ ['git branch -d {0}', 'git checkout -b {0}'],
21
+ ['git branch -D {0}', 'git branch {0}'],
22
+ ['git branch -D {0}', 'git checkout -b {0}'],
23
+ ['git checkout {0}']]
24
+ for new_command_template in new_command_templates:
25
+ yield shell.and_(*new_command_template).format(branch_name)
@@ -0,0 +1,14 @@
1
+ from thefuck.shells import shell
2
+ from thefuck.specific.git import git_support
3
+
4
+
5
+ @git_support
6
+ def match(command):
7
+ # catches "git branch list" in place of "git branch"
8
+ return (command.script_parts
9
+ and command.script_parts[1:] == 'branch list'.split())
10
+
11
+
12
+ @git_support
13
+ def get_new_command(command):
14
+ return shell.and_('git branch --delete list', 'git branch')
@@ -0,0 +1,49 @@
1
+ import re
2
+ import subprocess
3
+ from thefuck import utils
4
+ from thefuck.utils import replace_argument
5
+ from thefuck.specific.git import git_support
6
+ from thefuck.shells import shell
7
+
8
+
9
+ @git_support
10
+ def match(command):
11
+ return ('did not match any file(s) known to git' in command.output
12
+ and "Did you forget to 'git add'?" not in command.output)
13
+
14
+
15
+ def get_branches():
16
+ proc = subprocess.Popen(
17
+ ['git', 'branch', '-a', '--no-color', '--no-column'],
18
+ stdout=subprocess.PIPE)
19
+ for line in proc.stdout.readlines():
20
+ line = line.decode('utf-8')
21
+ if '->' in line: # Remote HEAD like b' remotes/origin/HEAD -> origin/master'
22
+ continue
23
+ if line.startswith('*'):
24
+ line = line.split(' ')[1]
25
+ if line.strip().startswith('remotes/'):
26
+ line = '/'.join(line.split('/')[2:])
27
+ yield line.strip()
28
+
29
+
30
+ @git_support
31
+ def get_new_command(command):
32
+ missing_file = re.findall(
33
+ r"error: pathspec '([^']*)' "
34
+ r"did not match any file\(s\) known to git", command.output)[0]
35
+ closest_branch = utils.get_closest(missing_file, get_branches(),
36
+ fallback_to_first=False)
37
+
38
+ new_commands = []
39
+
40
+ if closest_branch:
41
+ new_commands.append(replace_argument(command.script, missing_file, closest_branch))
42
+ if command.script_parts[1] == 'checkout':
43
+ new_commands.append(replace_argument(command.script, 'checkout', 'checkout -b'))
44
+
45
+ if not new_commands:
46
+ new_commands.append(shell.and_('git branch {}', '{}').format(
47
+ missing_file, command.script))
48
+
49
+ return new_commands
@@ -0,0 +1,12 @@
1
+ from thefuck.specific.git import git_support
2
+
3
+
4
+ @git_support
5
+ def match(command):
6
+ return (' git clone ' in command.script
7
+ and 'fatal: Too many arguments.' in command.output)
8
+
9
+
10
+ @git_support
11
+ def get_new_command(command):
12
+ return command.script.replace(' git clone ', ' ', 1)