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,39 @@
1
+ import subprocess
2
+ from itertools import dropwhile, islice, takewhile
3
+
4
+ from thefuck.specific.sudo import sudo_support
5
+ from thefuck.specific.yum import yum_available
6
+ from thefuck.utils import for_app, replace_command, which, cache
7
+
8
+ enabled_by_default = yum_available
9
+
10
+
11
+ @sudo_support
12
+ @for_app('yum')
13
+ def match(command):
14
+ return 'No such command: ' in command.output
15
+
16
+
17
+ def _get_operations():
18
+ proc = subprocess.Popen('yum', stdout=subprocess.PIPE)
19
+
20
+ lines = proc.stdout.readlines()
21
+ lines = [line.decode('utf-8') for line in lines]
22
+ lines = dropwhile(lambda line: not line.startswith("List of Commands:"), lines)
23
+ lines = islice(lines, 2, None)
24
+ lines = list(takewhile(lambda line: line.strip(), lines))
25
+ return [line.strip().split(' ')[0] for line in lines]
26
+
27
+
28
+ if which('yum'):
29
+ _get_operations = cache(which('yum'))(_get_operations)
30
+
31
+
32
+ @sudo_support
33
+ def get_new_command(command):
34
+ invalid_operation = command.script_parts[1]
35
+
36
+ if invalid_operation == 'uninstall':
37
+ return [command.script.replace('uninstall', 'remove')]
38
+
39
+ return replace_command(command, invalid_operation, _get_operations())
@@ -0,0 +1,52 @@
1
+ """Package with shell specific actions, each shell class should
2
+ implement `from_shell`, `to_shell`, `app_alias`, `put_to_history` and
3
+ `get_aliases` methods.
4
+ """
5
+ import os
6
+ from psutil import Process
7
+ from .bash import Bash
8
+ from .fish import Fish
9
+ from .generic import Generic
10
+ from .tcsh import Tcsh
11
+ from .zsh import Zsh
12
+ from .powershell import Powershell
13
+
14
+ shells = {'bash': Bash,
15
+ 'fish': Fish,
16
+ 'zsh': Zsh,
17
+ 'csh': Tcsh,
18
+ 'tcsh': Tcsh,
19
+ 'powershell': Powershell,
20
+ 'pwsh': Powershell}
21
+
22
+
23
+ def _get_shell_from_env():
24
+ name = os.environ.get('TF_SHELL')
25
+
26
+ if name in shells:
27
+ return shells[name]()
28
+
29
+
30
+ def _get_shell_from_proc():
31
+ proc = Process(os.getpid())
32
+
33
+ while proc is not None and proc.pid > 0:
34
+ try:
35
+ name = proc.name()
36
+ except TypeError:
37
+ name = proc.name
38
+
39
+ name = os.path.splitext(name)[0]
40
+
41
+ if name in shells:
42
+ return shells[name]()
43
+
44
+ try:
45
+ proc = proc.parent()
46
+ except TypeError:
47
+ proc = proc.parent
48
+
49
+ return Generic()
50
+
51
+
52
+ shell = _get_shell_from_env() or _get_shell_from_proc()
thefuck/shells/bash.py ADDED
@@ -0,0 +1,94 @@
1
+ import os
2
+ from subprocess import Popen, PIPE
3
+ from tempfile import gettempdir
4
+ from uuid import uuid4
5
+ from ..conf import settings
6
+ from ..const import ARGUMENT_PLACEHOLDER, USER_COMMAND_MARK
7
+ from ..utils import DEVNULL, memoize
8
+ from .generic import Generic
9
+
10
+
11
+ class Bash(Generic):
12
+ friendly_name = 'Bash'
13
+
14
+ def app_alias(self, alias_name):
15
+ # It is VERY important to have the variables declared WITHIN the function
16
+ return '''
17
+ function {name} () {{
18
+ TF_PYTHONIOENCODING=$PYTHONIOENCODING;
19
+ export TF_SHELL=bash;
20
+ export TF_ALIAS={name};
21
+ export TF_SHELL_ALIASES=$(alias);
22
+ export TF_HISTORY=$(fc -ln -10);
23
+ export TF_PROMPT="$*";
24
+ export PYTHONIOENCODING=utf-8;
25
+ TF_CMD=$(
26
+ thefuck {argument_placeholder} "$@"
27
+ ) && eval "$TF_CMD";
28
+ unset TF_HISTORY;
29
+ unset TF_PROMPT;
30
+ export PYTHONIOENCODING=$TF_PYTHONIOENCODING;
31
+ {alter_history}
32
+ }}
33
+ '''.format(
34
+ name=alias_name,
35
+ argument_placeholder=ARGUMENT_PLACEHOLDER,
36
+ alter_history=('history -s $TF_CMD;'
37
+ if settings.alter_history else ''))
38
+
39
+ def instant_mode_alias(self, alias_name):
40
+ if os.environ.get('THEFUCK_INSTANT_MODE', '').lower() == 'true':
41
+ mark = USER_COMMAND_MARK + '\b' * len(USER_COMMAND_MARK)
42
+ return '''
43
+ export PS1="{user_command_mark}$PS1";
44
+ {app_alias}
45
+ '''.format(user_command_mark=mark,
46
+ app_alias=self.app_alias(alias_name))
47
+ else:
48
+ log_path = os.path.join(
49
+ gettempdir(), 'thefuck-script-log-{}'.format(uuid4().hex))
50
+ return '''
51
+ export THEFUCK_INSTANT_MODE=True;
52
+ export THEFUCK_OUTPUT_LOG={log};
53
+ thefuck --shell-logger {log};
54
+ rm {log};
55
+ exit
56
+ '''.format(log=log_path)
57
+
58
+ def _parse_alias(self, alias):
59
+ name, value = alias.replace('alias ', '', 1).split('=', 1)
60
+ if value[0] == value[-1] == '"' or value[0] == value[-1] == "'":
61
+ value = value[1:-1]
62
+ return name, value
63
+
64
+ @memoize
65
+ def get_aliases(self):
66
+ raw_aliases = os.environ.get('TF_SHELL_ALIASES', '').split('\n')
67
+ return dict(self._parse_alias(alias)
68
+ for alias in raw_aliases if alias and '=' in alias)
69
+
70
+ def _get_history_file_name(self):
71
+ return os.environ.get("HISTFILE",
72
+ os.path.expanduser('~/.bash_history'))
73
+
74
+ def _get_history_line(self, command_script):
75
+ return u'{}\n'.format(command_script)
76
+
77
+ def how_to_configure(self):
78
+ if os.path.join(os.path.expanduser('~'), '.bashrc'):
79
+ config = '~/.bashrc'
80
+ elif os.path.join(os.path.expanduser('~'), '.bash_profile'):
81
+ config = '~/.bash_profile'
82
+ else:
83
+ config = 'bash config'
84
+
85
+ return self._create_shell_configuration(
86
+ content=u'eval "$(thefuck --alias)"',
87
+ path=config,
88
+ reload=u'source {}'.format(config))
89
+
90
+ def _get_version(self):
91
+ """Returns the version of the current shell"""
92
+ proc = Popen(['bash', '-c', 'echo $BASH_VERSION'],
93
+ stdout=PIPE, stderr=DEVNULL)
94
+ return proc.stdout.read().decode('utf-8').strip()
thefuck/shells/fish.py ADDED
@@ -0,0 +1,131 @@
1
+ from subprocess import Popen, PIPE
2
+ from time import time
3
+ import os
4
+ import sys
5
+ import six
6
+ from .. import logs
7
+ from ..conf import settings
8
+ from ..const import ARGUMENT_PLACEHOLDER
9
+ from ..utils import DEVNULL, cache
10
+ from .generic import Generic
11
+
12
+
13
+ @cache('~/.config/fish/config.fish', '~/.config/fish/functions')
14
+ def _get_functions(overridden):
15
+ proc = Popen(['fish', '-ic', 'functions'], stdout=PIPE, stderr=DEVNULL)
16
+ functions = proc.stdout.read().decode('utf-8').strip().split('\n')
17
+ return {func: func for func in functions if func not in overridden}
18
+
19
+
20
+ @cache('~/.config/fish/config.fish')
21
+ def _get_aliases(overridden):
22
+ aliases = {}
23
+ proc = Popen(['fish', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL)
24
+ alias_out = proc.stdout.read().decode('utf-8').strip()
25
+ if not alias_out:
26
+ return aliases
27
+ for alias in alias_out.split('\n'):
28
+ for separator in (' ', '='):
29
+ split_alias = alias.replace('alias ', '', 1).split(separator, 1)
30
+ if len(split_alias) == 2:
31
+ name, value = split_alias
32
+ break
33
+ else:
34
+ continue
35
+ if name not in overridden:
36
+ aliases[name] = value
37
+ return aliases
38
+
39
+
40
+ class Fish(Generic):
41
+ friendly_name = 'Fish Shell'
42
+
43
+ def _get_overridden_aliases(self):
44
+ overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES',
45
+ os.environ.get('TF_OVERRIDDEN_ALIASES', ''))
46
+ default = {'cd', 'grep', 'ls', 'man', 'open'}
47
+ for alias in overridden.split(','):
48
+ default.add(alias.strip())
49
+ return sorted(default)
50
+
51
+ def app_alias(self, alias_name):
52
+ if settings.alter_history:
53
+ alter_history = (' builtin history delete --exact'
54
+ ' --case-sensitive -- $fucked_up_command\n'
55
+ ' builtin history merge\n')
56
+ else:
57
+ alter_history = ''
58
+ # It is VERY important to have the variables declared WITHIN the alias
59
+ return ('function {0} -d "Correct your previous console command"\n'
60
+ ' set -l fucked_up_command $history[1]\n'
61
+ ' set -l tf_prompt (string join " " -- $argv)\n'
62
+ ' env TF_SHELL=fish TF_ALIAS={0} PYTHONIOENCODING=utf-8'
63
+ ' TF_COMMAND="$fucked_up_command" TF_PROMPT="$tf_prompt"'
64
+ ' thefuck $fucked_up_command {2} $argv | read -l unfucked_command\n'
65
+ ' if [ "$unfucked_command" != "" ]\n'
66
+ ' eval $unfucked_command\n{1}'
67
+ ' end\n'
68
+ 'end').format(alias_name, alter_history, ARGUMENT_PLACEHOLDER)
69
+
70
+ def get_aliases(self):
71
+ overridden = self._get_overridden_aliases()
72
+ functions = _get_functions(overridden)
73
+ raw_aliases = _get_aliases(overridden)
74
+ functions.update(raw_aliases)
75
+ return functions
76
+
77
+ def _expand_aliases(self, command_script):
78
+ aliases = self.get_aliases()
79
+ binary = command_script.split(' ')[0]
80
+ if binary in aliases and aliases[binary] != binary:
81
+ return command_script.replace(binary, aliases[binary], 1)
82
+ elif binary in aliases:
83
+ return u'fish -ic "{}"'.format(command_script.replace('"', r'\"'))
84
+ else:
85
+ return command_script
86
+
87
+ def _get_history_file_name(self):
88
+ return os.path.expanduser('~/.config/fish/fish_history')
89
+
90
+ def _get_history_line(self, command_script):
91
+ return u'- cmd: {}\n when: {}\n'.format(command_script, int(time()))
92
+
93
+ def _script_from_history(self, line):
94
+ if '- cmd: ' in line:
95
+ return line.split('- cmd: ', 1)[1]
96
+ else:
97
+ return ''
98
+
99
+ def and_(self, *commands):
100
+ return u'; and '.join(commands)
101
+
102
+ def or_(self, *commands):
103
+ return u'; or '.join(commands)
104
+
105
+ def how_to_configure(self):
106
+ return self._create_shell_configuration(
107
+ content=u"thefuck --alias | source",
108
+ path='~/.config/fish/config.fish',
109
+ reload='fish')
110
+
111
+ def _get_version(self):
112
+ """Returns the version of the current shell"""
113
+ proc = Popen(['fish', '--version'], stdout=PIPE, stderr=DEVNULL)
114
+ return proc.stdout.read().decode('utf-8').split()[-1]
115
+
116
+ def put_to_history(self, command):
117
+ try:
118
+ return self._put_to_history(command)
119
+ except IOError:
120
+ logs.exception("Can't update history", sys.exc_info())
121
+
122
+ def _put_to_history(self, command_script):
123
+ """Puts command script to shell history."""
124
+ history_file_name = self._get_history_file_name()
125
+ if os.path.isfile(history_file_name):
126
+ with open(history_file_name, 'a') as history:
127
+ entry = self._get_history_line(command_script)
128
+ if six.PY2:
129
+ history.write(entry.encode('utf-8'))
130
+ else:
131
+ history.write(entry)
@@ -0,0 +1,154 @@
1
+ import io
2
+ import os
3
+ import shlex
4
+ import six
5
+ from collections import namedtuple
6
+ from ..logs import warn
7
+ from ..utils import memoize
8
+ from ..conf import settings
9
+ from ..system import Path
10
+
11
+
12
+ ShellConfiguration = namedtuple('ShellConfiguration', (
13
+ 'content', 'path', 'reload', 'can_configure_automatically'))
14
+
15
+
16
+ class Generic(object):
17
+ friendly_name = 'Generic Shell'
18
+
19
+ def get_aliases(self):
20
+ return {}
21
+
22
+ def _expand_aliases(self, command_script):
23
+ aliases = self.get_aliases()
24
+ binary = command_script.split(' ')[0]
25
+ if binary in aliases:
26
+ return command_script.replace(binary, aliases[binary], 1)
27
+ else:
28
+ return command_script
29
+
30
+ def from_shell(self, command_script):
31
+ """Prepares command before running in app."""
32
+ return self._expand_aliases(command_script)
33
+
34
+ def to_shell(self, command_script):
35
+ """Prepares command for running in shell."""
36
+ return command_script
37
+
38
+ def app_alias(self, alias_name):
39
+ return """alias {0}='eval "$(TF_ALIAS={0} PYTHONIOENCODING=utf-8 """ \
40
+ """thefuck "$(fc -ln -1)")"'""".format(alias_name)
41
+
42
+ def instant_mode_alias(self, alias_name):
43
+ warn("Instant mode not supported by your shell")
44
+ return self.app_alias(alias_name)
45
+
46
+ def _get_history_file_name(self):
47
+ return ''
48
+
49
+ def _get_history_line(self, command_script):
50
+ return ''
51
+
52
+ @memoize
53
+ def get_history(self):
54
+ return list(self._get_history_lines())
55
+
56
+ def _get_history_lines(self):
57
+ """Returns list of history entries."""
58
+ history_file_name = self._get_history_file_name()
59
+ if os.path.isfile(history_file_name):
60
+ with io.open(history_file_name, 'r',
61
+ encoding='utf-8', errors='ignore') as history_file:
62
+
63
+ lines = history_file.readlines()
64
+ if settings.history_limit:
65
+ lines = lines[-settings.history_limit:]
66
+
67
+ for line in lines:
68
+ prepared = self._script_from_history(line) \
69
+ .strip()
70
+ if prepared:
71
+ yield prepared
72
+
73
+ def and_(self, *commands):
74
+ return u' && '.join(commands)
75
+
76
+ def or_(self, *commands):
77
+ return u' || '.join(commands)
78
+
79
+ def how_to_configure(self):
80
+ return
81
+
82
+ def split_command(self, command):
83
+ """Split the command using shell-like syntax."""
84
+ encoded = self.encode_utf8(command)
85
+
86
+ try:
87
+ splitted = [s.replace("??", "\\ ") for s in shlex.split(encoded.replace('\\ ', '??'))]
88
+ except ValueError:
89
+ splitted = encoded.split(' ')
90
+
91
+ return self.decode_utf8(splitted)
92
+
93
+ def encode_utf8(self, command):
94
+ if six.PY2:
95
+ return command.encode('utf8')
96
+ return command
97
+
98
+ def decode_utf8(self, command_parts):
99
+ if six.PY2:
100
+ return [s.decode('utf8') for s in command_parts]
101
+ return command_parts
102
+
103
+ def quote(self, s):
104
+ """Return a shell-escaped version of the string s."""
105
+
106
+ if six.PY2:
107
+ from pipes import quote
108
+ else:
109
+ from shlex import quote
110
+
111
+ return quote(s)
112
+
113
+ def _script_from_history(self, line):
114
+ return line
115
+
116
+ def put_to_history(self, command):
117
+ """Adds fixed command to shell history.
118
+
119
+ In most of shells we change history on shell-level, but not
120
+ all shells support it (Fish).
121
+
122
+ """
123
+
124
+ def get_builtin_commands(self):
125
+ """Returns shells builtin commands."""
126
+ return ['alias', 'bg', 'bind', 'break', 'builtin', 'case', 'cd',
127
+ 'command', 'compgen', 'complete', 'continue', 'declare',
128
+ 'dirs', 'disown', 'echo', 'enable', 'eval', 'exec', 'exit',
129
+ 'export', 'fc', 'fg', 'getopts', 'hash', 'help', 'history',
130
+ 'if', 'jobs', 'kill', 'let', 'local', 'logout', 'popd',
131
+ 'printf', 'pushd', 'pwd', 'read', 'readonly', 'return', 'set',
132
+ 'shift', 'shopt', 'source', 'suspend', 'test', 'times', 'trap',
133
+ 'type', 'typeset', 'ulimit', 'umask', 'unalias', 'unset',
134
+ 'until', 'wait', 'while']
135
+
136
+ def _get_version(self):
137
+ """Returns the version of the current shell"""
138
+ return ''
139
+
140
+ def info(self):
141
+ """Returns the name and version of the current shell"""
142
+ try:
143
+ version = self._get_version()
144
+ except Exception as e:
145
+ warn(u'Could not determine shell version: {}'.format(e))
146
+ version = ''
147
+ return u'{} {}'.format(self.friendly_name, version).rstrip()
148
+
149
+ def _create_shell_configuration(self, content, path, reload):
150
+ return ShellConfiguration(
151
+ content=content,
152
+ path=path,
153
+ reload=reload,
154
+ can_configure_automatically=Path(path).expanduser().exists())
@@ -0,0 +1,43 @@
1
+ from subprocess import Popen, PIPE
2
+ from ..utils import DEVNULL
3
+ from .generic import Generic, ShellConfiguration
4
+
5
+
6
+ class Powershell(Generic):
7
+ friendly_name = 'PowerShell'
8
+
9
+ def app_alias(self, alias_name):
10
+ return 'function ' + alias_name + ' {\n' \
11
+ ' $history = (Get-History -Count 1).CommandLine;\n' \
12
+ ' if (-not [string]::IsNullOrWhiteSpace($history)) {\n' \
13
+ ' $fuck = $(thefuck $args $history);\n' \
14
+ ' if (-not [string]::IsNullOrWhiteSpace($fuck)) {\n' \
15
+ ' if ($fuck.StartsWith("echo")) { $fuck = $fuck.Substring(5); }\n' \
16
+ ' else { iex "$fuck"; }\n' \
17
+ ' }\n' \
18
+ ' }\n' \
19
+ ' [Console]::ResetColor() \n' \
20
+ '}\n'
21
+
22
+ def and_(self, *commands):
23
+ return u' -and '.join('({0})'.format(c) for c in commands)
24
+
25
+ def how_to_configure(self):
26
+ return ShellConfiguration(
27
+ content=u'iex "$(thefuck --alias)"',
28
+ path='$profile',
29
+ reload='. $profile',
30
+ can_configure_automatically=False)
31
+
32
+ def _get_version(self):
33
+ """Returns the version of the current shell"""
34
+ try:
35
+ proc = Popen(
36
+ ['powershell.exe', '$PSVersionTable.PSVersion'],
37
+ stdout=PIPE,
38
+ stderr=DEVNULL)
39
+ version = proc.stdout.read().decode('utf-8').rstrip().split('\n')
40
+ return '.'.join(version[-1].split())
41
+ except IOError:
42
+ proc = Popen(['pwsh', '--version'], stdout=PIPE, stderr=DEVNULL)
43
+ return proc.stdout.read().decode('utf-8').split()[-1]
thefuck/shells/tcsh.py ADDED
@@ -0,0 +1,44 @@
1
+ from subprocess import Popen, PIPE
2
+ from time import time
3
+ import os
4
+ from ..utils import DEVNULL, memoize
5
+ from .generic import Generic
6
+
7
+
8
+ class Tcsh(Generic):
9
+ friendly_name = 'Tcsh'
10
+
11
+ def app_alias(self, alias_name):
12
+ return ("alias {0} 'setenv TF_SHELL tcsh && setenv TF_ALIAS {0} && "
13
+ "set fucked_cmd=`history -h 2 | head -n 1` && "
14
+ "eval `thefuck ${{fucked_cmd}}`'").format(alias_name)
15
+
16
+ def _parse_alias(self, alias):
17
+ name, value = alias.split("\t", 1)
18
+ return name, value
19
+
20
+ @memoize
21
+ def get_aliases(self):
22
+ proc = Popen(['tcsh', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL)
23
+ return dict(
24
+ self._parse_alias(alias)
25
+ for alias in proc.stdout.read().decode('utf-8').split('\n')
26
+ if alias and '\t' in alias)
27
+
28
+ def _get_history_file_name(self):
29
+ return os.environ.get("HISTFILE",
30
+ os.path.expanduser('~/.history'))
31
+
32
+ def _get_history_line(self, command_script):
33
+ return u'#+{}\n{}\n'.format(int(time()), command_script)
34
+
35
+ def how_to_configure(self):
36
+ return self._create_shell_configuration(
37
+ content=u'eval `thefuck --alias`',
38
+ path='~/.tcshrc',
39
+ reload='tcsh')
40
+
41
+ def _get_version(self):
42
+ """Returns the version of the current shell"""
43
+ proc = Popen(['tcsh', '--version'], stdout=PIPE, stderr=DEVNULL)
44
+ return proc.stdout.read().decode('utf-8').split()[1]
thefuck/shells/zsh.py ADDED
@@ -0,0 +1,98 @@
1
+ from time import time
2
+ import os
3
+ from subprocess import Popen, PIPE
4
+ from tempfile import gettempdir
5
+ from uuid import uuid4
6
+ from ..conf import settings
7
+ from ..const import ARGUMENT_PLACEHOLDER, USER_COMMAND_MARK
8
+ from ..utils import DEVNULL, memoize
9
+ from .generic import Generic
10
+
11
+
12
+ class Zsh(Generic):
13
+ friendly_name = 'ZSH'
14
+
15
+ def app_alias(self, alias_name):
16
+ # It is VERY important to have the variables declared WITHIN the function
17
+ return '''
18
+ {name} () {{
19
+ TF_PYTHONIOENCODING=$PYTHONIOENCODING;
20
+ export TF_SHELL=zsh;
21
+ export TF_ALIAS={name};
22
+ TF_SHELL_ALIASES=$(alias);
23
+ export TF_SHELL_ALIASES;
24
+ TF_HISTORY="$(fc -ln -10)";
25
+ export TF_HISTORY;
26
+ export TF_PROMPT="$*";
27
+ export PYTHONIOENCODING=utf-8;
28
+ TF_CMD=$(
29
+ thefuck {argument_placeholder} $@
30
+ ) && eval $TF_CMD;
31
+ unset TF_HISTORY;
32
+ unset TF_PROMPT;
33
+ export PYTHONIOENCODING=$TF_PYTHONIOENCODING;
34
+ {alter_history}
35
+ }}
36
+ '''.format(
37
+ name=alias_name,
38
+ argument_placeholder=ARGUMENT_PLACEHOLDER,
39
+ alter_history=('test -n "$TF_CMD" && print -s $TF_CMD'
40
+ if settings.alter_history else ''))
41
+
42
+ def instant_mode_alias(self, alias_name):
43
+ if os.environ.get('THEFUCK_INSTANT_MODE', '').lower() == 'true':
44
+ mark = ('%{' +
45
+ USER_COMMAND_MARK + '\b' * len(USER_COMMAND_MARK)
46
+ + '%}')
47
+ return '''
48
+ export PS1="{user_command_mark}$PS1";
49
+ {app_alias}
50
+ '''.format(user_command_mark=mark,
51
+ app_alias=self.app_alias(alias_name))
52
+ else:
53
+ log_path = os.path.join(
54
+ gettempdir(), 'thefuck-script-log-{}'.format(uuid4().hex))
55
+ return '''
56
+ export THEFUCK_INSTANT_MODE=True;
57
+ export THEFUCK_OUTPUT_LOG={log};
58
+ thefuck --shell-logger {log};
59
+ rm -f {log};
60
+ exit
61
+ '''.format(log=log_path)
62
+
63
+ def _parse_alias(self, alias):
64
+ name, value = alias.split('=', 1)
65
+ if value[0] == value[-1] == '"' or value[0] == value[-1] == "'":
66
+ value = value[1:-1]
67
+ return name, value
68
+
69
+ @memoize
70
+ def get_aliases(self):
71
+ raw_aliases = os.environ.get('TF_SHELL_ALIASES', '').split('\n')
72
+ return dict(self._parse_alias(alias)
73
+ for alias in raw_aliases if alias and '=' in alias)
74
+
75
+ def _get_history_file_name(self):
76
+ return os.environ.get("HISTFILE",
77
+ os.path.expanduser('~/.zsh_history'))
78
+
79
+ def _get_history_line(self, command_script):
80
+ return u': {}:0;{}\n'.format(int(time()), command_script)
81
+
82
+ def _script_from_history(self, line):
83
+ if ';' in line:
84
+ return line.split(';', 1)[1]
85
+ else:
86
+ return ''
87
+
88
+ def how_to_configure(self):
89
+ return self._create_shell_configuration(
90
+ content=u'eval $(thefuck --alias)',
91
+ path='~/.zshrc',
92
+ reload='source ~/.zshrc')
93
+
94
+ def _get_version(self):
95
+ """Returns the version of the current shell"""
96
+ proc = Popen(['zsh', '-c', 'echo $ZSH_VERSION'],
97
+ stdout=PIPE, stderr=DEVNULL)
98
+ return proc.stdout.read().decode('utf-8').strip()
File without changes
@@ -0,0 +1,3 @@
1
+ from thefuck.utils import which
2
+
3
+ apt_available = bool(which('apt-get'))