mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 07:04:12 +00:00 
			
		
		
		
	Merge branch 'master' into flake8
This commit is contained in:
		
							
								
								
									
										11
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -2,6 +2,9 @@ language: python | |||||||
| sudo: false | sudo: false | ||||||
| matrix: | matrix: | ||||||
|   include: |   include: | ||||||
|  |     - os: linux | ||||||
|  |       dist: trusty | ||||||
|  |       python: "3.6" | ||||||
|     - os: linux |     - os: linux | ||||||
|       dist: trusty |       dist: trusty | ||||||
|       python: "3.5" |       python: "3.5" | ||||||
| @@ -29,7 +32,7 @@ addons: | |||||||
|       - python3-commandnotfound |       - python3-commandnotfound | ||||||
| before_install: | before_install: | ||||||
|   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi |   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi | ||||||
|   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew install $FORMULA; fi |   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then if brew ls --versions $FORMULA; then brew upgrade $FORMULA || echo Python is up to date; else brew install $FORMULA; fi; fi | ||||||
|   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p $FORMULA; fi |   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p $FORMULA; fi | ||||||
|   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi |   - if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi | ||||||
|   - pip install -U pip |   - pip install -U pip | ||||||
| @@ -42,7 +45,7 @@ script: | |||||||
|   - flake8 |   - flake8 | ||||||
|   - export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1} |   - export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1} | ||||||
|   - export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests" |   - export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests" | ||||||
|   - if [[ $TRAVIS_PYTHON_VERSION == 3.5 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi |   - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi | ||||||
|   - if [[ $TRAVIS_PYTHON_VERSION != 3.5 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi |   - if [[ $TRAVIS_PYTHON_VERSION != 3.6 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi | ||||||
| after_success: | after_success: | ||||||
|   - coveralls |   - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
									
									
									
									
								
							| @@ -144,7 +144,8 @@ sudo -H pip install thefuck --upgrade | |||||||
| The Fuck tries to match a rule for the previous command, creates a new command | The Fuck tries to match a rule for the previous command, creates a new command | ||||||
| using the matched rule and runs it. Rules enabled by default are as follows: | using the matched rule and runs it. Rules enabled by default are as follows: | ||||||
|  |  | ||||||
| * `aws_cli` – fixes misspelled commands like `aws dynamdb scan` | * `ag_literal` – adds `-Q` to `ag` when suggested; | ||||||
|  | * `aws_cli` – fixes misspelled commands like `aws dynamdb scan`; | ||||||
| * `cargo` – runs `cargo build` instead of `cargo`; | * `cargo` – runs `cargo build` instead of `cargo`; | ||||||
| * `cargo_no_command` – fixes wrongs commands like `cargo buid`; | * `cargo_no_command` – fixes wrongs commands like `cargo buid`; | ||||||
| * `cd_correction` – spellchecks and correct failed cd commands; | * `cd_correction` – spellchecks and correct failed cd commands; | ||||||
| @@ -163,7 +164,9 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `fab_command_not_found` – fix misspelled fabric commands; | * `fab_command_not_found` – fix misspelled fabric commands; | ||||||
| * `fix_alt_space` – replaces Alt+Space with Space character; | * `fix_alt_space` – replaces Alt+Space with Space character; | ||||||
| * `fix_file` – opens a file with an error in your `$EDITOR`; | * `fix_file` – opens a file with an error in your `$EDITOR`; | ||||||
|  | * `gem_unknown_command` – fixes wrong `gem` commands; | ||||||
| * `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*; | * `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*; | ||||||
|  | * `git_add_force` – adds `--force` to `git add <pathspec>...` when paths are .gitignore'd; | ||||||
| * `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting; | * `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting; | ||||||
| * `git_branch_delete` – changes `git branch -d` to `git branch -D`; | * `git_branch_delete` – changes `git branch -d` to `git branch -D`; | ||||||
| * `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists; | * `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists; | ||||||
| @@ -172,6 +175,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files; | * `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files; | ||||||
| * `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output; | * `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output; | ||||||
| * `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`); | * `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`); | ||||||
|  | * `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename` | ||||||
| * `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command; | * `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command; | ||||||
| * `git_not_command` – fixes wrong git commands like `git brnch`; | * `git_not_command` – fixes wrong git commands like `git brnch`; | ||||||
| * `git_pull` – sets upstream before executing previous `git pull`; | * `git_pull` – sets upstream before executing previous `git pull`; | ||||||
| @@ -180,9 +184,14 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`; | * `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`; | ||||||
| * `git_push_pull` – runs `git pull` when `push` was rejected; | * `git_push_pull` – runs `git pull` when `push` was rejected; | ||||||
| * `git_rebase_no_changes` – runs `git rebase --skip` instead of `git rebase --continue` when there are no changes; | * `git_rebase_no_changes` – runs `git rebase --skip` instead of `git rebase --continue` when there are no changes; | ||||||
|  | * `git_rm_local_modifications` –  adds `-f` or `--cached` when you try to `rm` a locally modified file; | ||||||
| * `git_rm_recursive` – adds `-r` when you try to `rm` a directory; | * `git_rm_recursive` – adds `-r` when you try to `rm` a directory; | ||||||
|  | * `git_rm_staged` –  adds `-f` or `--cached` when you try to `rm` a file with staged changes | ||||||
|  | * `git_rebase_merge_dir` – offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress; | ||||||
| * `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote; | * `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote; | ||||||
| * `git_stash` – stashes you local modifications before rebasing or switching branch; | * `git_stash` – stashes your local modifications before rebasing or switching branch; | ||||||
|  | * `git_stash_pop` – adds your local modifications before popping stash, then resets; | ||||||
|  | * `git_tag_force` – adds `--force` to `git tag <tagname>` when the tag already exists; | ||||||
| * `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`; | * `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`; | ||||||
| * `go_run` – appends `.go` extension when compiling/running Go programs; | * `go_run` – appends `.go` extension when compiling/running Go programs; | ||||||
| * `gradle_no_task` – fixes not found or ambiguous `gradle` task; | * `gradle_no_task` – fixes not found or ambiguous `gradle` task; | ||||||
| @@ -194,11 +203,13 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `has_exists_script` – prepends `./` when script/binary exists; | * `has_exists_script` – prepends `./` when script/binary exists; | ||||||
| * `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`; | * `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`; | ||||||
| * `history` – tries to replace command with most similar command from history; | * `history` – tries to replace command with most similar command from history; | ||||||
|  | * `ifconfig_device_not_found` – fixes wrong device names like `wlan0` to `wlp2s0`; | ||||||
| * `java` – removes `.java` extension when running Java programs; | * `java` – removes `.java` extension when running Java programs; | ||||||
| * `javac` – appends missing `.java` when compiling Java files; | * `javac` – appends missing `.java` when compiling Java files; | ||||||
| * `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`; | * `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`; | ||||||
| * `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link; | * `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link; | ||||||
| * `ln_s_order` – fixes `ln -s` arguments order; | * `ln_s_order` – fixes `ln -s` arguments order; | ||||||
|  | * `ls_all` – adds `-A` to `ls` when output is empty; | ||||||
| * `ls_lah` – adds `-lah` to `ls`; | * `ls_lah` – adds `-lah` to `ls`; | ||||||
| * `man` – changes manual section; | * `man` – changes manual section; | ||||||
| * `man_no_space` – fixes man commands without spaces, for example `mandiff`; | * `man_no_space` – fixes man commands without spaces, for example `mandiff`; | ||||||
| @@ -220,10 +231,12 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `react_native_command_unrecognized` – fixes unrecognized `react-native` commands; | * `react_native_command_unrecognized` – fixes unrecognized `react-native` commands; | ||||||
| * `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts; | * `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts; | ||||||
| * `rm_dir` – adds `-rf` when you trying to remove directory; | * `rm_dir` – adds `-rf` when you trying to remove directory; | ||||||
|  | * `scm_correction` – corrects wrong scm like `hg log` to `git log`; | ||||||
| * `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands; | * `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands; | ||||||
| * `sl_ls` – changes `sl` to `ls`; | * `sl_ls` – changes `sl` to `ls`; | ||||||
| * `ssh_known_hosts` – removes host from `known_hosts` on warning; | * `ssh_known_hosts` – removes host from `known_hosts` on warning; | ||||||
| * `sudo` – prepends `sudo` to previous command if it failed because of permissions; | * `sudo` – prepends `sudo` to previous command if it failed because of permissions; | ||||||
|  | * `sudo_command_from_user_path` – runs commands from users `$PATH` with `sudo`; | ||||||
| * `switch_lang` – switches command from your local layout to en; | * `switch_lang` – switches command from your local layout to en; | ||||||
| * `systemctl` – correctly orders parameters of confusing `systemctl`; | * `systemctl` – correctly orders parameters of confusing `systemctl`; | ||||||
| * `test.py` – runs `py.test` instead of `test.py`; | * `test.py` – runs `py.test` instead of `test.py`; | ||||||
| @@ -235,6 +248,8 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `vagrant_up` – starts up the vagrant instance; | * `vagrant_up` – starts up the vagrant instance; | ||||||
| * `whois` – fixes `whois` command; | * `whois` – fixes `whois` command; | ||||||
| * `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new. | * `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new. | ||||||
|  | * `yarn_alias` – fixes aliased `yarn` commands like `yarn ls`; | ||||||
|  | * `yarn_command_not_found` – fixes misspelled `yarn` commands; | ||||||
|  |  | ||||||
| Enabled by default only on specific platforms: | Enabled by default only on specific platforms: | ||||||
|  |  | ||||||
| @@ -272,7 +287,9 @@ side_effect(old_command: Command, fixed_command: str) -> None | |||||||
| ``` | ``` | ||||||
| and optional `enabled_by_default`, `requires_output` and `priority` variables. | and optional `enabled_by_default`, `requires_output` and `priority` variables. | ||||||
|  |  | ||||||
| `Command` has three attributes: `script`, `stdout` and `stderr`. | `Command` has three attributes: `script`, `stdout`, `stderr` and `script_parts`. | ||||||
|  | Rule shouldn't change `Command`. | ||||||
|  |  | ||||||
|  |  | ||||||
| *Rules api changed in 3.0:* For accessing settings in rule you need to import it with `from thefuck.conf import settings`. | *Rules api changed in 3.0:* For accessing settings in rule you need to import it with `from thefuck.conf import settings`. | ||||||
| `settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)). | `settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)). | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ environment: | |||||||
|     - PYTHON: "C:/Python33" |     - PYTHON: "C:/Python33" | ||||||
|     - PYTHON: "C:/Python34" |     - PYTHON: "C:/Python34" | ||||||
|     - PYTHON: "C:/Python35" |     - PYTHON: "C:/Python35" | ||||||
|  |     - PYTHON: "C:/Python36" | ||||||
|  |  | ||||||
| init: | init: | ||||||
|   - "ECHO %PYTHON%" |   - "ECHO %PYTHON%" | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -29,7 +29,7 @@ elif (3, 0) < version < (3, 3): | |||||||
|           ' ({}.{} detected).'.format(*version)) |           ' ({}.{} detected).'.format(*version)) | ||||||
|     sys.exit(-1) |     sys.exit(-1) | ||||||
|  |  | ||||||
| VERSION = '3.11' | VERSION = '3.14' | ||||||
|  |  | ||||||
| install_requires = ['psutil', 'colorama', 'six', 'decorator'] | install_requires = ['psutil', 'colorama', 'six', 'decorator'] | ||||||
| extras_require = {':python_version<"3.4"': ['pathlib2'], | extras_require = {':python_version<"3.4"': ['pathlib2'], | ||||||
|   | |||||||
| @@ -3,18 +3,11 @@ from tests.functional.plots import with_confirmation, without_confirmation, \ | |||||||
|     refuse_with_confirmation, history_changed, history_not_changed, \ |     refuse_with_confirmation, history_changed, history_not_changed, \ | ||||||
|     select_command_with_arrows, how_to_configure |     select_command_with_arrows, how_to_configure | ||||||
|  |  | ||||||
| containers = ((u'thefuck/ubuntu-python3-bash', | containers = ((u'thefuck/python3-bash', | ||||||
|                u'''FROM ubuntu:latest |                u'FROM python:3', | ||||||
|                    RUN apt-get update |  | ||||||
|                    RUN apt-get install -yy python3 python3-pip python3-dev git |  | ||||||
|                    RUN pip3 install -U setuptools |  | ||||||
|                    RUN ln -s /usr/bin/pip3 /usr/bin/pip''', |  | ||||||
|                u'bash'), |                u'bash'), | ||||||
|               (u'thefuck/ubuntu-python2-bash', |               (u'thefuck/python2-bash', | ||||||
|                u'''FROM ubuntu:latest |                u'FROM python:2', | ||||||
|                    RUN apt-get update |  | ||||||
|                    RUN apt-get install -yy python python-pip python-dev git |  | ||||||
|                    RUN pip2 install -U pip setuptools''', |  | ||||||
|                u'bash')) |                u'bash')) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,19 +2,20 @@ import pytest | |||||||
| from tests.functional.plots import with_confirmation, without_confirmation, \ | from tests.functional.plots import with_confirmation, without_confirmation, \ | ||||||
|     refuse_with_confirmation, select_command_with_arrows |     refuse_with_confirmation, select_command_with_arrows | ||||||
|  |  | ||||||
| containers = (('thefuck/ubuntu-python3-fish', | containers = (('thefuck/python3-fish', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:3 | ||||||
|  |                    # Use jessie-backports since it has the fish package. See here for details: | ||||||
|  |                    # https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile | ||||||
|  |                    RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python3 python3-pip python3-dev fish git |  | ||||||
|                    RUN pip3 install -U setuptools |  | ||||||
|                    RUN ln -s /usr/bin/pip3 /usr/bin/pip |  | ||||||
|                    RUN apt-get install -yy fish''', |                    RUN apt-get install -yy fish''', | ||||||
|                u'fish'), |                u'fish'), | ||||||
|               ('thefuck/ubuntu-python2-fish', |               ('thefuck/python2-fish', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:2 | ||||||
|  |                    # Use jessie-backports since it has the fish package. See here for details: | ||||||
|  |                    # https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile | ||||||
|  |                    RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python python-pip python-dev git |  | ||||||
|                    RUN pip2 install -U pip setuptools |  | ||||||
|                    RUN apt-get install -yy fish''', |                    RUN apt-get install -yy fish''', | ||||||
|                u'fish')) |                u'fish')) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,11 +2,7 @@ import pytest | |||||||
| import time | import time | ||||||
|  |  | ||||||
| dockerfile = u''' | dockerfile = u''' | ||||||
| FROM ubuntu:latest | FROM python:3 | ||||||
| RUN apt-get update |  | ||||||
| RUN apt-get install -yy python3 python3-pip python3-dev git |  | ||||||
| RUN pip3 install -U setuptools |  | ||||||
| RUN ln -s /usr/bin/pip3 /usr/bin/pip |  | ||||||
| RUN adduser --disabled-password --gecos '' test | RUN adduser --disabled-password --gecos '' test | ||||||
| ENV SEED "{seed}" | ENV SEED "{seed}" | ||||||
| WORKDIR /src | WORKDIR /src | ||||||
| @@ -42,7 +38,7 @@ def plot(proc, TIMEOUT): | |||||||
| @pytest.mark.functional | @pytest.mark.functional | ||||||
| @pytest.mark.benchmark(min_rounds=10) | @pytest.mark.benchmark(min_rounds=10) | ||||||
| def test_performance(spawnu, TIMEOUT, benchmark): | def test_performance(spawnu, TIMEOUT, benchmark): | ||||||
|     proc = spawnu(u'thefuck/ubuntu-python3-bash-performance', |     proc = spawnu(u'thefuck/python3-bash-performance', | ||||||
|                   dockerfile, u'bash') |                   dockerfile, u'bash') | ||||||
|     proc.sendline(u'pip install /src') |     proc.sendline(u'pip install /src') | ||||||
|     proc.sendline(u'su test') |     proc.sendline(u'su test') | ||||||
|   | |||||||
| @@ -2,19 +2,14 @@ import pytest | |||||||
| from tests.functional.plots import with_confirmation, without_confirmation, \ | from tests.functional.plots import with_confirmation, without_confirmation, \ | ||||||
|     refuse_with_confirmation, select_command_with_arrows |     refuse_with_confirmation, select_command_with_arrows | ||||||
|  |  | ||||||
| containers = (('thefuck/ubuntu-python3-tcsh', | containers = (('thefuck/python3-tcsh', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:3 | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python3 python3-pip python3-dev git |  | ||||||
|                    RUN pip3 install -U setuptools |  | ||||||
|                    RUN ln -s /usr/bin/pip3 /usr/bin/pip |  | ||||||
|                    RUN apt-get install -yy tcsh''', |                    RUN apt-get install -yy tcsh''', | ||||||
|                u'tcsh'), |                u'tcsh'), | ||||||
|               ('thefuck/ubuntu-python2-tcsh', |               ('thefuck/python2-tcsh', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:2 | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python python-pip python-dev git |  | ||||||
|                    RUN pip2 install -U pip setuptools |  | ||||||
|                    RUN apt-get install -yy tcsh''', |                    RUN apt-get install -yy tcsh''', | ||||||
|                u'tcsh')) |                u'tcsh')) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,19 +3,14 @@ from tests.functional.plots import with_confirmation, without_confirmation, \ | |||||||
|     refuse_with_confirmation, history_changed, history_not_changed, \ |     refuse_with_confirmation, history_changed, history_not_changed, \ | ||||||
|     select_command_with_arrows, how_to_configure |     select_command_with_arrows, how_to_configure | ||||||
|  |  | ||||||
| containers = (('thefuck/ubuntu-python3-zsh', | containers = (('thefuck/python3-zsh', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:3 | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python3 python3-pip python3-dev git |  | ||||||
|                    RUN pip3 install -U setuptools |  | ||||||
|                    RUN ln -s /usr/bin/pip3 /usr/bin/pip |  | ||||||
|                    RUN apt-get install -yy zsh''', |                    RUN apt-get install -yy zsh''', | ||||||
|                u'zsh'), |                u'zsh'), | ||||||
|               ('thefuck/ubuntu-python2-zsh', |               ('thefuck/python2-zsh', | ||||||
|                u'''FROM ubuntu:latest |                u'''FROM python:2 | ||||||
|                    RUN apt-get update |                    RUN apt-get update | ||||||
|                    RUN apt-get install -yy python python-pip python-dev git |  | ||||||
|                    RUN pip2 install -U pip setuptools |  | ||||||
|                    RUN apt-get install -yy zsh''', |                    RUN apt-get install -yy zsh''', | ||||||
|                u'zsh')) |                u'zsh')) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								tests/rules/test_ag_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_ag_literal.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.ag_literal import get_new_command, match | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(): | ||||||
|  |     return ('ERR: Bad regex! pcre_compile() failed at position 1: missing )\n' | ||||||
|  |             'If you meant to search for a literal string, run ag with -Q\n') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', ['ag \(']) | ||||||
|  | def test_match(script, stderr): | ||||||
|  |     assert match(Command(script=script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', ['ag foo']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script=script)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, new_cmd', [ | ||||||
|  |     ('ag \(', 'ag -Q \(')]) | ||||||
|  | def test_get_new_command(script, new_cmd, stderr): | ||||||
|  |     assert get_new_command((Command(script=script, stderr=stderr))) == new_cmd | ||||||
| @@ -7,6 +7,8 @@ from tests.utils import Command | |||||||
|     (Command(script='vim', stderr='vim: command not found'), |     (Command(script='vim', stderr='vim: command not found'), | ||||||
|      [('vim', 'main'), ('vim-tiny', 'main')]), |      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||||
|     (Command(script='sudo vim', stderr='vim: command not found'), |     (Command(script='sudo vim', stderr='vim: command not found'), | ||||||
|  |      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||||
|  |     (Command(script='vim', stderr="The program 'vim' is currently not installed. You can install it by typing: sudo apt install vim"), | ||||||
|      [('vim', 'main'), ('vim-tiny', 'main')])]) |      [('vim', 'main'), ('vim-tiny', 'main')])]) | ||||||
| def test_match(mocker, command, packages): | def test_match(mocker, command, packages): | ||||||
|     mocker.patch('thefuck.rules.apt_get.which', return_value=None) |     mocker.patch('thefuck.rules.apt_get.which', return_value=None) | ||||||
|   | |||||||
							
								
								
									
										82
									
								
								tests/rules/test_gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								tests/rules/test_gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | import pytest | ||||||
|  | from six import BytesIO | ||||||
|  | from thefuck.rules.gem_unknown_command import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  | stderr = ''' | ||||||
|  | ERROR:  While executing gem ... (Gem::CommandLineError) | ||||||
|  |     Unknown command {} | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  | gem_help_commands_stdout = b''' | ||||||
|  | GEM commands are: | ||||||
|  |  | ||||||
|  |     build             Build a gem from a gemspec | ||||||
|  |     cert              Manage RubyGems certificates and signing settings | ||||||
|  |     check             Check a gem repository for added or missing files | ||||||
|  |     cleanup           Clean up old versions of installed gems | ||||||
|  |     contents          Display the contents of the installed gems | ||||||
|  |     dependency        Show the dependencies of an installed gem | ||||||
|  |     environment       Display information about the RubyGems environment | ||||||
|  |     fetch             Download a gem and place it in the current directory | ||||||
|  |     generate_index    Generates the index files for a gem server directory | ||||||
|  |     help              Provide help on the 'gem' command | ||||||
|  |     install           Install a gem into the local repository | ||||||
|  |     list              Display local gems whose name matches REGEXP | ||||||
|  |     lock              Generate a lockdown list of gems | ||||||
|  |     mirror            Mirror all gem files (requires rubygems-mirror) | ||||||
|  |     open              Open gem sources in editor | ||||||
|  |     outdated          Display all gems that need updates | ||||||
|  |     owner             Manage gem owners of a gem on the push server | ||||||
|  |     pristine          Restores installed gems to pristine condition from files | ||||||
|  |                       located in the gem cache | ||||||
|  |     push              Push a gem up to the gem server | ||||||
|  |     query             Query gem information in local or remote repositories | ||||||
|  |     rdoc              Generates RDoc for pre-installed gems | ||||||
|  |     search            Display remote gems whose name matches REGEXP | ||||||
|  |     server            Documentation and gem repository HTTP server | ||||||
|  |     sources           Manage the sources and cache file RubyGems uses to search | ||||||
|  |                       for gems | ||||||
|  |     specification     Display gem specification (in yaml) | ||||||
|  |     stale             List gems along with access times | ||||||
|  |     uninstall         Uninstall gems from the local repository | ||||||
|  |     unpack            Unpack an installed gem to the current directory | ||||||
|  |     update            Update installed gems to the latest version | ||||||
|  |     which             Find the location of a library file you can require | ||||||
|  |     yank              Remove a pushed gem from the index | ||||||
|  |  | ||||||
|  | For help on a particular command, use 'gem help COMMAND'. | ||||||
|  |  | ||||||
|  | Commands may be abbreviated, so long as they are unambiguous. | ||||||
|  | e.g. 'gem i rake' is short for 'gem install rake'. | ||||||
|  |  | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(autouse=True) | ||||||
|  | def gem_help_commands(mocker): | ||||||
|  |     patch = mocker.patch('subprocess.Popen') | ||||||
|  |     patch.return_value.stdout = BytesIO(gem_help_commands_stdout) | ||||||
|  |     return patch | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, command', [ | ||||||
|  |     ('gem isntall jekyll', 'isntall'), | ||||||
|  |     ('gem last --local', 'last')]) | ||||||
|  | def test_match(script, command): | ||||||
|  |     assert match(Command(script, stderr=stderr.format(command))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr', [ | ||||||
|  |     ('gem install jekyll', ''), | ||||||
|  |     ('git log', stderr.format('log'))]) | ||||||
|  | def test_not_match(script, stderr): | ||||||
|  |     assert not match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr, result', [ | ||||||
|  |     ('gem isntall jekyll', stderr.format('isntall'), 'gem install jekyll'), | ||||||
|  |     ('gem last --local', stderr.format('last'), 'gem list --local')]) | ||||||
|  | def test_get_new_command(script, stderr, result): | ||||||
|  |     new_command = get_new_command(Command(script, stderr=stderr)) | ||||||
|  |     assert new_command[0] == result | ||||||
							
								
								
									
										22
									
								
								tests/rules/test_git_add_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/rules/test_git_add_force.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_add_force import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(): | ||||||
|  |     return ('The following paths are ignored by one of your .gitignore files:\n' | ||||||
|  |             'dist/app.js\n' | ||||||
|  |             'dist/background.js\n' | ||||||
|  |             'dist/options.js\n' | ||||||
|  |             'Use -f if you really want to add them.\n') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(stderr): | ||||||
|  |     assert match(Command('git add dist/*.js', stderr=stderr)) | ||||||
|  |     assert not match(Command('git add dist/*.js')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_get_new_command(stderr): | ||||||
|  |     assert get_new_command(Command('git add dist/*.js', stderr=stderr)) \ | ||||||
|  |            == "git add --force dist/*.js" | ||||||
							
								
								
									
										31
									
								
								tests/rules/test_git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/rules/test_git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_flag_after_filename import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  | command1 = Command('git log README.md -p', | ||||||
|  |                    stderr="fatal: bad flag '-p' used after filename") | ||||||
|  | command2 = Command('git log README.md -p CONTRIBUTING.md', | ||||||
|  |                    stderr="fatal: bad flag '-p' used after filename") | ||||||
|  | command3 = Command('git log -p README.md --name-only', | ||||||
|  |                    stderr="fatal: bad flag '--name-only' used after filename") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     command1, command2, command3]) | ||||||
|  | def test_match(command): | ||||||
|  |     assert match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     Command('git log README.md'), | ||||||
|  |     Command('git log -p README.md')]) | ||||||
|  | def test_not_match(command): | ||||||
|  |     assert not match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command, result', [ | ||||||
|  |     (command1, "git log -p README.md"), | ||||||
|  |     (command2, "git log -p README.md CONTRIBUTING.md"), | ||||||
|  |     (command3, "git log -p --name-only README.md")]) | ||||||
|  | def test_get_new_command(command, result): | ||||||
|  |     assert get_new_command(command) == result | ||||||
| @@ -23,6 +23,8 @@ def test_match(stderr): | |||||||
| def test_get_new_command(stderr): | def test_get_new_command(stderr): | ||||||
|     assert get_new_command(Command('git push', stderr=stderr))\ |     assert get_new_command(Command('git push', stderr=stderr))\ | ||||||
|         == "git push --set-upstream origin master" |         == "git push --set-upstream origin master" | ||||||
|  |     assert get_new_command(Command('git push -u', stderr=stderr))\ | ||||||
|  |         == "git push --set-upstream origin master" | ||||||
|     assert get_new_command(Command('git push -u origin', stderr=stderr))\ |     assert get_new_command(Command('git push -u origin', stderr=stderr))\ | ||||||
|         == "git push --set-upstream origin master" |         == "git push --set-upstream origin master" | ||||||
|     assert get_new_command(Command('git push --set-upstream origin', stderr=stderr))\ |     assert get_new_command(Command('git push --set-upstream origin', stderr=stderr))\ | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								tests/rules/test_git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/rules/test_git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_rebase_merge_dir import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(): | ||||||
|  |     return ('\n\nIt seems that there is already a rebase-merge directory, and\n' | ||||||
|  |             'I wonder if you are in the middle of another rebase.  If that is the\n' | ||||||
|  |             'case, please try\n' | ||||||
|  |             '\tgit rebase (--continue | --abort | --skip)\n' | ||||||
|  |             'If that is not the case, please\n' | ||||||
|  |             '\trm -fr "/foo/bar/baz/egg/.git/rebase-merge"\n' | ||||||
|  |             'and run me again.  I am stopping in case you still have something\n' | ||||||
|  |             'valuable there.\n') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', [ | ||||||
|  |     ('git rebase master'), ('git rebase -skip'), ('git rebase')]) | ||||||
|  | def test_match(stderr, script): | ||||||
|  |     assert match(Command(script=script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', ['git rebase master', 'git rebase -abort']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script=script)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, result', [ | ||||||
|  |     ('git rebase master', [ | ||||||
|  |         'git rebase --abort', 'git rebase --skip', 'git rebase --continue', | ||||||
|  |         'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']), | ||||||
|  |     ('git rebase -skip', [ | ||||||
|  |         'git rebase --skip', 'git rebase --abort', 'git rebase --continue', | ||||||
|  |         'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']), | ||||||
|  |     ('git rebase', [ | ||||||
|  |         'git rebase --skip', 'git rebase --abort', 'git rebase --continue', | ||||||
|  |         'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"'])]) | ||||||
|  | def test_get_new_command(stderr, script, result): | ||||||
|  |     assert get_new_command(Command(script=script, stderr=stderr)) == result | ||||||
							
								
								
									
										28
									
								
								tests/rules/test_git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/rules/test_git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_rm_local_modifications import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(target): | ||||||
|  |     return ('error: the following file has local modifications:\n    {}\n(use ' | ||||||
|  |             '--cached to keep the file, or -f to force removal)').format(target) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, target', [ | ||||||
|  |     ('git rm foo', 'foo'), | ||||||
|  |     ('git rm foo bar', 'bar')]) | ||||||
|  | def test_match(stderr, script, target): | ||||||
|  |     assert match(Command(script=script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar', 'git rm']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script=script, stderr='')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, target, new_command', [ | ||||||
|  |     ('git rm foo', 'foo', ['git rm --cached foo', 'git rm -f foo']), | ||||||
|  |     ('git rm foo bar', 'bar', ['git rm --cached foo bar', 'git rm -f foo bar'])]) | ||||||
|  | def test_get_new_command(stderr, script, target, new_command): | ||||||
|  |     assert get_new_command(Command(script=script, stderr=stderr)) == new_command | ||||||
							
								
								
									
										28
									
								
								tests/rules/test_git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/rules/test_git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_rm_staged import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(target): | ||||||
|  |     return ('error: the following file has changes staged in the index:\n    {}\n(use ' | ||||||
|  |             '--cached to keep the file, or -f to force removal)').format(target) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, target', [ | ||||||
|  |     ('git rm foo', 'foo'), | ||||||
|  |     ('git rm foo bar', 'bar')]) | ||||||
|  | def test_match(stderr, script, target): | ||||||
|  |     assert match(Command(script=script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar', 'git rm']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script=script, stderr='')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, target, new_command', [ | ||||||
|  |     ('git rm foo', 'foo', ['git rm --cached foo', 'git rm -f foo']), | ||||||
|  |     ('git rm foo bar', 'bar', ['git rm --cached foo bar', 'git rm -f foo bar'])]) | ||||||
|  | def test_get_new_command(stderr, script, target, new_command): | ||||||
|  |     assert get_new_command(Command(script=script, stderr=stderr)) == new_command | ||||||
							
								
								
									
										18
									
								
								tests/rules/test_git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/rules/test_git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_stash_pop import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(): | ||||||
|  |     return '''error: Your local changes to the following files would be overwritten by merge:''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(stderr): | ||||||
|  |     assert match(Command('git stash pop', stderr=stderr)) | ||||||
|  |     assert not match(Command('git stash')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_get_new_command(stderr): | ||||||
|  |     assert get_new_command(Command('git stash pop', stderr=stderr)) \ | ||||||
|  |            == "git add . && git stash pop && git reset ." | ||||||
							
								
								
									
										18
									
								
								tests/rules/test_git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/rules/test_git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_tag_force import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def stderr(): | ||||||
|  |     return '''fatal: tag 'alert' already exists''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(stderr): | ||||||
|  |     assert match(Command('git tag alert', stderr=stderr)) | ||||||
|  |     assert not match(Command('git tag alert')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_get_new_command(stderr): | ||||||
|  |     assert get_new_command(Command('git tag alert', stderr=stderr)) \ | ||||||
|  |            == "git tag --force alert" | ||||||
							
								
								
									
										53
									
								
								tests/rules/test_ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/rules/test_ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | import pytest | ||||||
|  | from six import BytesIO | ||||||
|  | from thefuck.rules.ifconfig_device_not_found import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | stderr = '{}: error fetching interface information: Device not found' | ||||||
|  |  | ||||||
|  | stdout = b''' | ||||||
|  | wlp2s0    Link encap:Ethernet  HWaddr 5c:51:4f:7c:58:5d | ||||||
|  |           inet addr:192.168.0.103  Bcast:192.168.0.255  Mask:255.255.255.0 | ||||||
|  |           inet6 addr: fe80::be23:69b9:96d2:6d39/64 Scope:Link | ||||||
|  |           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1 | ||||||
|  |           RX packets:23581604 errors:0 dropped:0 overruns:0 frame:0 | ||||||
|  |           TX packets:17017655 errors:0 dropped:0 overruns:0 carrier:0 | ||||||
|  |           collisions:0 txqueuelen:1000 | ||||||
|  |           RX bytes:16148429061 (16.1 GB)  TX bytes:7067533695 (7.0 GB) | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(autouse=True) | ||||||
|  | def ifconfig(mocker): | ||||||
|  |     mock = mocker.patch( | ||||||
|  |         'thefuck.rules.ifconfig_device_not_found.subprocess.Popen') | ||||||
|  |     mock.return_value.stdout = BytesIO(stdout) | ||||||
|  |     return mock | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr', [ | ||||||
|  |     ('ifconfig wlan0', stderr.format('wlan0')), | ||||||
|  |     ('ifconfig -s eth0', stderr.format('eth0')), | ||||||
|  | ]) | ||||||
|  | def test_match(script, stderr): | ||||||
|  |     assert match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr', [ | ||||||
|  |     ('config wlan0', | ||||||
|  |      'wlan0: error fetching interface information: Device not found'), | ||||||
|  |     ('ifconfig eth0', ''), | ||||||
|  | ]) | ||||||
|  | def test_not_match(script, stderr): | ||||||
|  |     assert not match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, result', [ | ||||||
|  |     ('ifconfig wlan0', ['ifconfig wlp2s0']), | ||||||
|  |     ('ifconfig -s wlan0', ['ifconfig -s wlp2s0']), | ||||||
|  | ]) | ||||||
|  | def test_get_new_comman(script, result): | ||||||
|  |     new_command = get_new_command( | ||||||
|  |         Command(script, stderr=stderr.format('wlan0'))) | ||||||
|  |     assert new_command == result | ||||||
							
								
								
									
										12
									
								
								tests/rules/test_ls_all.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/rules/test_ls_all.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | from thefuck.rules.ls_all import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(): | ||||||
|  |     assert match(Command(script='ls')) | ||||||
|  |     assert not match(Command(script='ls', stdout='file.py\n')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_get_new_command(): | ||||||
|  |     assert get_new_command(Command(script='ls empty_dir')) == 'ls -A empty_dir' | ||||||
|  |     assert get_new_command(Command(script='ls')) == 'ls -A' | ||||||
| @@ -23,7 +23,8 @@ def test_not_match(command): | |||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('command, new_command', [ | @pytest.mark.parametrize('command, new_command', [ | ||||||
|     (Command('man read'), ['man 3 read', 'man 2 read']), |     (Command('man read'), ['man 3 read', 'man 2 read', 'read --help']), | ||||||
|  |     (Command('man missing', stderr="No manual entry for missing\n"), ['missing --help']), | ||||||
|     (Command('man 2 read'), 'man 3 read'), |     (Command('man 2 read'), 'man 3 read'), | ||||||
|     (Command('man 3 read'), 'man 2 read'), |     (Command('man 3 read'), 'man 2 read'), | ||||||
|     (Command('man -s2 read'), 'man -s3 read'), |     (Command('man -s2 read'), 'man -s3 read'), | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								tests/rules/test_scm_correction.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								tests/rules/test_scm_correction.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.scm_correction import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def get_actual_scm_mock(mocker): | ||||||
|  |     return mocker.patch('thefuck.rules.scm_correction._get_actual_scm', | ||||||
|  |                         return_value=None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr, actual_scm', [ | ||||||
|  |     ('git log', 'fatal: Not a git repository ' | ||||||
|  |                 '(or any of the parent directories): .git', | ||||||
|  |      'hg'), | ||||||
|  |     ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' " | ||||||
|  |                "(.hg not found)!", | ||||||
|  |      'git')]) | ||||||
|  | def test_match(get_actual_scm_mock, script, stderr, actual_scm): | ||||||
|  |     get_actual_scm_mock.return_value = actual_scm | ||||||
|  |     assert match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr, actual_scm', [ | ||||||
|  |     ('git log', '', 'hg'), | ||||||
|  |     ('git log', 'fatal: Not a git repository ' | ||||||
|  |                 '(or any of the parent directories): .git', | ||||||
|  |      None), | ||||||
|  |     ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' " | ||||||
|  |                "(.hg not found)!", | ||||||
|  |      None), | ||||||
|  |     ('not-scm log', "abort: no repository found in '/home/nvbn/exp/thefuck' " | ||||||
|  |                     "(.hg not found)!", | ||||||
|  |      'git')]) | ||||||
|  | def test_not_match(get_actual_scm_mock, script, stderr, actual_scm): | ||||||
|  |     get_actual_scm_mock.return_value = actual_scm | ||||||
|  |     assert not match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, actual_scm, result', [ | ||||||
|  |     ('git log', 'hg', 'hg log'), | ||||||
|  |     ('hg log', 'git', 'git log')]) | ||||||
|  | def test_get_new_command(get_actual_scm_mock, script, actual_scm, result): | ||||||
|  |     get_actual_scm_mock.return_value = actual_scm | ||||||
|  |     new_command = get_new_command(Command(script)) | ||||||
|  |     assert new_command == result | ||||||
							
								
								
									
										39
									
								
								tests/rules/test_sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tests/rules/test_sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.sudo_command_from_user_path import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | stderr = 'sudo: {}: command not found' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(autouse=True) | ||||||
|  | def which(mocker): | ||||||
|  |     return mocker.patch('thefuck.rules.sudo_command_from_user_path.which', | ||||||
|  |                         return_value='/usr/bin/app') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr', [ | ||||||
|  |     ('sudo npm install -g react-native-cli', stderr.format('npm')), | ||||||
|  |     ('sudo -u app appcfg update .', stderr.format('appcfg'))]) | ||||||
|  | def test_match(script, stderr): | ||||||
|  |     assert match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr, which_result', [ | ||||||
|  |     ('npm --version', stderr.format('npm'), '/usr/bin/npm'), | ||||||
|  |     ('sudo npm --version', '', '/usr/bin/npm'), | ||||||
|  |     ('sudo npm --version', stderr.format('npm'), None)]) | ||||||
|  | def test_not_match(which, script, stderr, which_result): | ||||||
|  |     which.return_value = which_result | ||||||
|  |     assert not match(Command(script, stderr=stderr)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, stderr, result', [ | ||||||
|  |     ('sudo npm install -g react-native-cli', | ||||||
|  |      stderr.format('npm'), | ||||||
|  |      'sudo env "PATH=$PATH" npm install -g react-native-cli'), | ||||||
|  |     ('sudo -u app appcfg update .', | ||||||
|  |      stderr.format('appcfg'), | ||||||
|  |      'sudo -u app env "PATH=$PATH" appcfg update .')]) | ||||||
|  | def test_get_new_command(script, stderr, result): | ||||||
|  |     assert get_new_command(Command(script, stderr=stderr)) == result | ||||||
							
								
								
									
										22
									
								
								tests/rules/test_yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/rules/test_yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.yarn_alias import match, get_new_command | ||||||
|  | from tests.utils import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | stderr_remove = 'error Did you mean `yarn remove`?' | ||||||
|  |  | ||||||
|  | stderr_list = 'error Did you mean `yarn list`?' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     Command(script='yarn rm', stderr=stderr_remove), | ||||||
|  |     Command(script='yarn ls', stderr=stderr_list)]) | ||||||
|  | def test_match(command): | ||||||
|  |     assert match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command, new_command', [ | ||||||
|  |     (Command('yarn rm', stderr=stderr_remove), 'yarn remove'), | ||||||
|  |     (Command('yarn ls', stderr=stderr_list), 'yarn list')]) | ||||||
|  | def test_get_new_command(command, new_command): | ||||||
|  |     assert get_new_command(command) == new_command | ||||||
							
								
								
									
										111
									
								
								tests/rules/test_yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								tests/rules/test_yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | # -*- encoding: utf-8 -*- | ||||||
|  |  | ||||||
|  | from io import BytesIO | ||||||
|  | import pytest | ||||||
|  | from tests.utils import Command | ||||||
|  | from thefuck.rules.yarn_command_not_found import match, get_new_command | ||||||
|  |  | ||||||
|  | stderr = ''' | ||||||
|  | error Command "{}" not found. | ||||||
|  | '''.format | ||||||
|  |  | ||||||
|  | yarn_help_stdout = b''' | ||||||
|  |  | ||||||
|  |   Usage: yarn [command] [flags] | ||||||
|  |  | ||||||
|  |   Options: | ||||||
|  |  | ||||||
|  |     -h, --help                      output usage information | ||||||
|  |     -V, --version                   output the version number | ||||||
|  |     --verbose                       output verbose messages on internal operations | ||||||
|  |     --offline                       trigger an error if any required dependencies are not available in local cache | ||||||
|  |     --prefer-offline                use network only if dependencies are not available in local cache | ||||||
|  |     --strict-semver                  | ||||||
|  |     --json                           | ||||||
|  |     --ignore-scripts                don't run lifecycle scripts | ||||||
|  |     --har                           save HAR output of network traffic | ||||||
|  |     --ignore-platform               ignore platform checks | ||||||
|  |     --ignore-engines                ignore engines check | ||||||
|  |     --ignore-optional               ignore optional dependencies | ||||||
|  |     --force                         ignore all caches | ||||||
|  |     --no-bin-links                  don't generate bin links when setting up packages | ||||||
|  |     --flat                          only allow one version of a package | ||||||
|  |     --prod, --production [prod]      | ||||||
|  |     --no-lockfile                   don't read or generate a lockfile | ||||||
|  |     --pure-lockfile                 don't generate a lockfile | ||||||
|  |     --frozen-lockfile               don't generate a lockfile and fail if an update is needed | ||||||
|  |     --link-duplicates               create hardlinks to the repeated modules in node_modules | ||||||
|  |     --global-folder <path>           | ||||||
|  |     --modules-folder <path>         rather than installing modules into the node_modules folder relative to the cwd, output them here | ||||||
|  |     --cache-folder <path>           specify a custom folder to store the yarn cache | ||||||
|  |     --mutex <type>[:specifier]      use a mutex to ensure only one yarn instance is executing | ||||||
|  |     --no-emoji                      disable emoji in output | ||||||
|  |     --proxy <host>                   | ||||||
|  |     --https-proxy <host>             | ||||||
|  |     --no-progress                   disable progress bar | ||||||
|  |     --network-concurrency <number>  maximum number of concurrent network requests | ||||||
|  |  | ||||||
|  |   Commands: | ||||||
|  |  | ||||||
|  |     - access | ||||||
|  |     - add | ||||||
|  |     - bin | ||||||
|  |     - cache | ||||||
|  |     - check | ||||||
|  |     - clean | ||||||
|  |     - config | ||||||
|  |     - generate-lock-entry | ||||||
|  |     - global | ||||||
|  |     - import | ||||||
|  |     - info | ||||||
|  |     - init | ||||||
|  |     - install | ||||||
|  |     - licenses | ||||||
|  |     - link | ||||||
|  |     - list | ||||||
|  |     - login | ||||||
|  |     - logout | ||||||
|  |     - outdated | ||||||
|  |     - owner | ||||||
|  |     - pack | ||||||
|  |     - publish | ||||||
|  |     - remove | ||||||
|  |     - run | ||||||
|  |     - tag | ||||||
|  |     - team | ||||||
|  |     - unlink | ||||||
|  |     - upgrade | ||||||
|  |     - upgrade-interactive | ||||||
|  |     - version | ||||||
|  |     - versions | ||||||
|  |     - why | ||||||
|  |  | ||||||
|  |   Run `yarn help COMMAND` for more information on specific commands. | ||||||
|  |   Visit https://yarnpkg.com/en/docs/cli/ to learn more about Yarn. | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(autouse=True) | ||||||
|  | def yarn_help(mocker): | ||||||
|  |     patch = mocker.patch('thefuck.rules.yarn_command_not_found.Popen') | ||||||
|  |     patch.return_value.stdout = BytesIO(yarn_help_stdout) | ||||||
|  |     return patch | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     Command('yarn whyy webpack', stderr=stderr('whyy'))]) | ||||||
|  | def test_match(command): | ||||||
|  |     assert match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     Command('npm nuild', stderr=stderr('nuild')), | ||||||
|  |     Command('yarn install')]) | ||||||
|  | def test_not_match(command): | ||||||
|  |     assert not match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command, result', [ | ||||||
|  |     (Command('yarn whyy webpack', stderr=stderr('whyy')), 'yarn why webpack')]) | ||||||
|  | def test_get_new_command(command, result): | ||||||
|  |     assert get_new_command(command)[0] == result | ||||||
| @@ -56,3 +56,8 @@ class TestBash(object): | |||||||
|     def test_get_history(self, history_lines, shell): |     def test_get_history(self, history_lines, shell): | ||||||
|         history_lines(['ls', 'rm']) |         history_lines(['ls', 'rm']) | ||||||
|         assert list(shell.get_history()) == ['ls', 'rm'] |         assert list(shell.get_history()) == ['ls', 'rm'] | ||||||
|  |  | ||||||
|  |     def test_split_command(self, shell): | ||||||
|  |         command = 'git log -p' | ||||||
|  |         command_parts = ['git', 'log', '-p'] | ||||||
|  |         assert shell.split_command(command) == command_parts | ||||||
|   | |||||||
| @@ -76,11 +76,11 @@ class TestFish(object): | |||||||
|  |  | ||||||
|     def test_app_alias_alter_history(self, settings, shell): |     def test_app_alias_alter_history(self, settings, shell): | ||||||
|         settings.alter_history = True |         settings.alter_history = True | ||||||
|         assert 'history --delete' in shell.app_alias('FUCK') |         assert 'builtin history delete' in shell.app_alias('FUCK') | ||||||
|         assert 'history --merge' in shell.app_alias('FUCK') |         assert 'builtin history merge' in shell.app_alias('FUCK') | ||||||
|         settings.alter_history = False |         settings.alter_history = False | ||||||
|         assert 'history --delete' not in shell.app_alias('FUCK') |         assert 'builtin history delete' not in shell.app_alias('FUCK') | ||||||
|         assert 'history --merge' not in shell.app_alias('FUCK') |         assert 'builtin history merge' not in shell.app_alias('FUCK') | ||||||
|  |  | ||||||
|     def test_get_history(self, history_lines, shell): |     def test_get_history(self, history_lines, shell): | ||||||
|         history_lines(['- cmd: ls', '  when: 1432613911', |         history_lines(['- cmd: ls', '  when: 1432613911', | ||||||
|   | |||||||
| @@ -83,13 +83,14 @@ def how_to_configure_alias(configuration_details): | |||||||
|     print("Seems like {bold}fuck{reset} alias isn't configured!".format( |     print("Seems like {bold}fuck{reset} alias isn't configured!".format( | ||||||
|         bold=color(colorama.Style.BRIGHT), |         bold=color(colorama.Style.BRIGHT), | ||||||
|         reset=color(colorama.Style.RESET_ALL))) |         reset=color(colorama.Style.RESET_ALL))) | ||||||
|  |  | ||||||
|     if configuration_details: |     if configuration_details: | ||||||
|         content, path = configuration_details |  | ||||||
|         print( |         print( | ||||||
|             "Please put {bold}{content}{reset} in your " |             "Please put {bold}{content}{reset} in your " | ||||||
|             "{bold}{path}{reset}.".format( |             "{bold}{path}{reset} and apply " | ||||||
|  |             "changes with {bold}{reload}{reset} or restart your shell.".format( | ||||||
|                 bold=color(colorama.Style.BRIGHT), |                 bold=color(colorama.Style.BRIGHT), | ||||||
|                 reset=color(colorama.Style.RESET_ALL), |                 reset=color(colorama.Style.RESET_ALL), | ||||||
|                 path=path, |                 **configuration_details)) | ||||||
|                 content=content)) |  | ||||||
|     print('More details - https://github.com/nvbn/thefuck#manual-installation') |     print('More details - https://github.com/nvbn/thefuck#manual-installation') | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								thefuck/rules/ag_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								thefuck/rules/ag_literal.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | from thefuck.utils import for_app | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('ag') | ||||||
|  | def match(command): | ||||||
|  |     return command.stderr.endswith('run ag with -Q\n') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     return command.script.replace('ag', 'ag -Q', 1) | ||||||
| @@ -29,7 +29,7 @@ def get_package(executable): | |||||||
|  |  | ||||||
|  |  | ||||||
| def match(command): | def match(command): | ||||||
|     if 'not found' in command.stderr: |     if 'not found' in command.stderr or 'not installed' in command.stderr: | ||||||
|         executable = _get_executable(command) |         executable = _get_executable(command) | ||||||
|         return not which(executable) and get_package(executable) |         return not which(executable) and get_package(executable) | ||||||
|     else: |     else: | ||||||
|   | |||||||
| @@ -8,7 +8,8 @@ def match(command): | |||||||
|  |  | ||||||
|  |  | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     command.script_parts[1] = 'link' |     command_parts = command.script_parts[:] | ||||||
|     command.script_parts.insert(2, '--overwrite') |     command_parts[1] = 'link' | ||||||
|     command.script_parts.insert(3, '--dry-run') |     command_parts.insert(2, '--overwrite') | ||||||
|     return ' '.join(command.script_parts) |     command_parts.insert(3, '--dry-run') | ||||||
|  |     return ' '.join(command_parts) | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ def match(command): | |||||||
|  |  | ||||||
|  |  | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     command.script_parts[1] = 'uninstall' |     command_parts = command.script_parts[:] | ||||||
|     command.script_parts.insert(2, '--force') |     command_parts[1] = 'uninstall' | ||||||
|     return ' '.join(command.script_parts) |     command_parts.insert(2, '--force') | ||||||
|  |     return ' '.join(command_parts) | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								thefuck/rules/gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								thefuck/rules/gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | import re | ||||||
|  | import subprocess | ||||||
|  | from thefuck.utils import for_app, eager, replace_command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('gem') | ||||||
|  | def match(command): | ||||||
|  |     return ('ERROR:  While executing gem ... (Gem::CommandLineError)' | ||||||
|  |             in command.stderr | ||||||
|  |             and 'Unknown command' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _get_unknown_command(command): | ||||||
|  |     return re.findall(r'Unknown command (.*)$', command.stderr)[0] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @eager | ||||||
|  | def _get_all_commands(): | ||||||
|  |     proc = subprocess.Popen(['gem', 'help', 'commands'], | ||||||
|  |                             stdout=subprocess.PIPE) | ||||||
|  |  | ||||||
|  |     for line in proc.stdout.readlines(): | ||||||
|  |         line = line.decode() | ||||||
|  |  | ||||||
|  |         if line.startswith('    '): | ||||||
|  |             yield line.strip().split(' ')[0] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     unknown_command = _get_unknown_command(command) | ||||||
|  |     all_commands = _get_all_commands() | ||||||
|  |     return replace_command(command, unknown_command, all_commands) | ||||||
							
								
								
									
										13
									
								
								thefuck/rules/git_add_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								thefuck/rules/git_add_force.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | from thefuck.utils import replace_argument | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('add' in command.script_parts | ||||||
|  |             and 'Use -f if you really want to add them.' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  | 	return replace_argument(command.script, 'add', 'add --force') | ||||||
							
								
								
									
										30
									
								
								thefuck/rules/git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								thefuck/rules/git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | import re | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  | error_pattern = "fatal: bad flag '(.*?)' used after filename" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return re.search(error_pattern, command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     command_parts = command.script_parts[:] | ||||||
|  |  | ||||||
|  |     # find the bad flag | ||||||
|  |     bad_flag = re.search(error_pattern, command.stderr).group(1) | ||||||
|  |     bad_flag_index = command_parts.index(bad_flag) | ||||||
|  |  | ||||||
|  |     # find the filename | ||||||
|  |     for index in reversed(range(bad_flag_index)): | ||||||
|  |         if command_parts[index][0] != '-': | ||||||
|  |             filename_index = index | ||||||
|  |             break | ||||||
|  |  | ||||||
|  |     # swap them | ||||||
|  |     command_parts[bad_flag_index], command_parts[filename_index] = \ | ||||||
|  |     command_parts[filename_index], command_parts[bad_flag_index]  # noqa: E122 | ||||||
|  |  | ||||||
|  |     return u' '.join(command_parts) | ||||||
| @@ -8,23 +8,29 @@ def match(command): | |||||||
|             and 'set-upstream' in command.stderr) |             and 'set-upstream' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _get_upstream_option_index(command_parts): | ||||||
|  |     if '--set-upstream' in command_parts: | ||||||
|  |         return command_parts.index('--set-upstream') | ||||||
|  |     elif '-u' in command_parts: | ||||||
|  |         return command_parts.index('-u') | ||||||
|  |     else: | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |  | ||||||
| @git_support | @git_support | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     # If --set-upstream or -u are passed, remove it and its argument. This is |     # If --set-upstream or -u are passed, remove it and its argument. This is | ||||||
|     # because the remaining arguments are concatenated onto the command suggested |     # because the remaining arguments are concatenated onto the command suggested | ||||||
|     # by git, which includes --set-upstream and its argument |     # by git, which includes --set-upstream and its argument | ||||||
|     upstream_option_index = -1 |     command_parts = command.script_parts[:] | ||||||
|     try: |     upstream_option_index = _get_upstream_option_index(command_parts) | ||||||
|         upstream_option_index = command.script_parts.index('--set-upstream') |  | ||||||
|     except ValueError: |     if upstream_option_index is not None: | ||||||
|         pass |         command_parts.pop(upstream_option_index) | ||||||
|     try: |  | ||||||
|         upstream_option_index = command.script_parts.index('-u') |         # In case of `git push -u` we don't have next argument: | ||||||
|     except ValueError: |         if len(command_parts) > upstream_option_index: | ||||||
|         pass |             command_parts.pop(upstream_option_index) | ||||||
|     if upstream_option_index is not -1: |  | ||||||
|         command.script_parts.pop(upstream_option_index) |  | ||||||
|         command.script_parts.pop(upstream_option_index) |  | ||||||
|  |  | ||||||
|     push_upstream = command.stderr.split('\n')[-3].strip().partition('git ')[2] |     push_upstream = command.stderr.split('\n')[-3].strip().partition('git ')[2] | ||||||
|     return replace_argument(" ".join(command.script_parts), 'push', push_upstream) |     return replace_argument(" ".join(command_parts), 'push', push_upstream) | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								thefuck/rules/git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								thefuck/rules/git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | from difflib import get_close_matches | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return (' rebase' in command.script and | ||||||
|  |             'It seems that there is already a rebase-merge directory' in command.stderr and | ||||||
|  |             'I wonder if you are in the middle of another rebase' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     command_list = ['git rebase --continue', 'git rebase --abort', 'git rebase --skip'] | ||||||
|  |     rm_cmd = command.stderr.split('\n')[-4] | ||||||
|  |     command_list.append(rm_cmd.strip()) | ||||||
|  |     return get_close_matches(command.script, command_list, 4, 0) | ||||||
							
								
								
									
										19
									
								
								thefuck/rules/git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								thefuck/rules/git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return (' rm ' in command.script and | ||||||
|  |             'error: the following file has local modifications' in command.stderr and | ||||||
|  |             'use --cached to keep the file, or -f to force removal' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     command_parts = command.script_parts[:] | ||||||
|  |     index = command_parts.index('rm') + 1 | ||||||
|  |     command_parts.insert(index, '--cached') | ||||||
|  |     command_list = [u' '.join(command_parts)] | ||||||
|  |     command_parts[index] = '-f' | ||||||
|  |     command_list.append(u' '.join(command_parts)) | ||||||
|  |     return command_list | ||||||
| @@ -10,6 +10,7 @@ def match(command): | |||||||
|  |  | ||||||
| @git_support | @git_support | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     index = command.script_parts.index('rm') + 1 |     command_parts = command.script_parts[:] | ||||||
|     command.script_parts.insert(index, '-r') |     index = command_parts.index('rm') + 1 | ||||||
|     return u' '.join(command.script_parts) |     command_parts.insert(index, '-r') | ||||||
|  |     return u' '.join(command_parts) | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								thefuck/rules/git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								thefuck/rules/git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return (' rm ' in command.script and | ||||||
|  |             'error: the following file has changes staged in the index' in command.stderr and | ||||||
|  |             'use --cached to keep the file, or -f to force removal' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     command_parts = command.script_parts[:] | ||||||
|  |     index = command_parts.index('rm') + 1 | ||||||
|  |     command_parts.insert(index, '--cached') | ||||||
|  |     command_list = [u' '.join(command_parts)] | ||||||
|  |     command_parts[index] = '-f' | ||||||
|  |     command_list.append(u' '.join(command_parts)) | ||||||
|  |     return command_list | ||||||
							
								
								
									
										18
									
								
								thefuck/rules/git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								thefuck/rules/git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | from thefuck.shells import shell | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('stash' in command.script | ||||||
|  |             and 'pop' in command.script | ||||||
|  |             and 'Your local changes to the following files would be overwritten by merge' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     return shell.and_('git add .', 'git stash pop', 'git reset .') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # make it come before the other applicable rules | ||||||
|  | priority = 900 | ||||||
							
								
								
									
										13
									
								
								thefuck/rules/git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								thefuck/rules/git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | from thefuck.utils import replace_argument | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('tag' in command.script_parts | ||||||
|  |             and 'already exists' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     return replace_argument(command.script, 'tag', 'tag --force') | ||||||
							
								
								
									
										25
									
								
								thefuck/rules/ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								thefuck/rules/ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import subprocess | ||||||
|  | from thefuck.utils import for_app, replace_command, eager | ||||||
|  | import sys | ||||||
|  |  | ||||||
|  | @for_app('ifconfig') | ||||||
|  | def match(command): | ||||||
|  |     return 'error fetching interface information: Device not found' \ | ||||||
|  |            in command.stderr | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @eager | ||||||
|  | def _get_possible_interfaces(): | ||||||
|  |     proc = subprocess.Popen(['ifconfig', '-a'], stdout=subprocess.PIPE) | ||||||
|  |     for line in proc.stdout.readlines(): | ||||||
|  |         line = line.decode() | ||||||
|  |         if line and line != '\n' and not line.startswith(' '): | ||||||
|  |             yield line.split(' ')[0] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     interface = command.stderr.split(' ')[0][:-1] | ||||||
|  |     possible_interfaces = _get_possible_interfaces() | ||||||
|  |     return replace_command(command, interface, possible_interfaces) | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								thefuck/rules/ls_all.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								thefuck/rules/ls_all.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | from thefuck.utils import for_app | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('ls') | ||||||
|  | def match(command): | ||||||
|  |     return command.stdout.strip() == '' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     return ' '.join(['ls', '-A'] + command.script_parts[1:]) | ||||||
| @@ -12,10 +12,22 @@ def get_new_command(command): | |||||||
|     if '2' in command.script: |     if '2' in command.script: | ||||||
|         return command.script.replace("2", "3") |         return command.script.replace("2", "3") | ||||||
|  |  | ||||||
|  |     last_arg = command.script_parts[-1] | ||||||
|  |     help_command = last_arg + ' --help' | ||||||
|  |  | ||||||
|  |     # If there are no man pages for last_arg, suggest `last_arg --help` instead. | ||||||
|  |     # Otherwise, suggest `--help` after suggesting other man page sections. | ||||||
|  |     if command.stderr.strip() == 'No manual entry for ' + last_arg: | ||||||
|  |         return [help_command] | ||||||
|  |  | ||||||
|     split_cmd2 = command.script_parts |     split_cmd2 = command.script_parts | ||||||
|     split_cmd3 = split_cmd2[:] |     split_cmd3 = split_cmd2[:] | ||||||
|  |  | ||||||
|     split_cmd2.insert(1, ' 2 ') |     split_cmd2.insert(1, ' 2 ') | ||||||
|     split_cmd3.insert(1, ' 3 ') |     split_cmd3.insert(1, ' 3 ') | ||||||
|  |  | ||||||
|     return ["".join(split_cmd3), "".join(split_cmd2)] |     return [ | ||||||
|  |         "".join(split_cmd3), | ||||||
|  |         "".join(split_cmd2), | ||||||
|  |         help_command, | ||||||
|  |     ] | ||||||
|   | |||||||
| @@ -6,9 +6,8 @@ from thefuck.specific.sudo import sudo_support | |||||||
|  |  | ||||||
| @sudo_support | @sudo_support | ||||||
| def match(command): | def match(command): | ||||||
|     toks = command.script_parts |     return (command.script_parts | ||||||
|     return (toks |             and command.script_parts[0].endswith('.py') | ||||||
|             and toks[0].endswith('.py') |  | ||||||
|             and ('Permission denied' in command.stderr or |             and ('Permission denied' in command.stderr or | ||||||
|                  'command not found' in command.stderr)) |                  'command not found' in command.stderr)) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								thefuck/rules/scm_correction.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								thefuck/rules/scm_correction.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | from thefuck.utils import for_app, memoize | ||||||
|  | from thefuck.system import Path | ||||||
|  |  | ||||||
|  | path_to_scm = { | ||||||
|  |     '.git': 'git', | ||||||
|  |     '.hg': 'hg', | ||||||
|  | } | ||||||
|  |  | ||||||
|  | wrong_scm_patterns = { | ||||||
|  |     'git': 'fatal: Not a git repository', | ||||||
|  |     'hg': 'abort: no repository found', | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @memoize | ||||||
|  | def _get_actual_scm(): | ||||||
|  |     for path, scm in path_to_scm.items(): | ||||||
|  |         if Path(path).is_dir(): | ||||||
|  |             return scm | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app(*wrong_scm_patterns.keys()) | ||||||
|  | def match(command): | ||||||
|  |     scm = command.script_parts[0] | ||||||
|  |     pattern = wrong_scm_patterns[scm] | ||||||
|  |  | ||||||
|  |     return pattern in command.stderr and _get_actual_scm() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     scm = _get_actual_scm() | ||||||
|  |     return u' '.join([scm] + command.script_parts[1:]) | ||||||
							
								
								
									
										21
									
								
								thefuck/rules/sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								thefuck/rules/sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | import re | ||||||
|  | from thefuck.utils import for_app, which, replace_argument | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _get_command_name(command): | ||||||
|  |     found = re.findall(r'sudo: (.*): command not found', command.stderr) | ||||||
|  |     if found: | ||||||
|  |         return found[0] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('sudo') | ||||||
|  | def match(command): | ||||||
|  |     if 'command not found' in command.stderr: | ||||||
|  |         command_name = _get_command_name(command) | ||||||
|  |         return which(command_name) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     command_name = _get_command_name(command) | ||||||
|  |     return replace_argument(command.script, command_name, | ||||||
|  |                             u'env "PATH=$PATH" {}'.format(command_name)) | ||||||
| @@ -17,6 +17,6 @@ def match(command): | |||||||
|  |  | ||||||
| @sudo_support | @sudo_support | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     cmd = command.script_parts |     cmd = command.script_parts[:] | ||||||
|     cmd[-1], cmd[-2] = cmd[-2], cmd[-1] |     cmd[-1], cmd[-2] = cmd[-2], cmd[-1] | ||||||
|     return ' '.join(cmd) |     return ' '.join(cmd) | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								thefuck/rules/yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								thefuck/rules/yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | import re | ||||||
|  | from thefuck.utils import replace_argument, for_app | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('yarn', at_least=1) | ||||||
|  | def match(command): | ||||||
|  |     return ('Did you mean' in command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     broken = command.script_parts[1] | ||||||
|  |     fix = re.findall(r'Did you mean `yarn ([^`]*)`', command.stderr)[0] | ||||||
|  |  | ||||||
|  |     return replace_argument(command.script, broken, fix) | ||||||
							
								
								
									
										31
									
								
								thefuck/rules/yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								thefuck/rules/yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import re | ||||||
|  | from subprocess import Popen, PIPE | ||||||
|  | from thefuck.utils import for_app, eager, replace_command | ||||||
|  |  | ||||||
|  | regex = re.compile(r'error Command "(.*)" not found.') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @for_app('yarn') | ||||||
|  | def match(command): | ||||||
|  |     return regex.findall(command.stderr) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @eager | ||||||
|  | def _get_all_tasks(): | ||||||
|  |     proc = Popen(['yarn', '--help'], stdout=PIPE) | ||||||
|  |     should_yield = False | ||||||
|  |     for line in proc.stdout.readlines(): | ||||||
|  |         line = line.decode().strip() | ||||||
|  |  | ||||||
|  |         if 'Commands:' in line: | ||||||
|  |             should_yield = True | ||||||
|  |             continue | ||||||
|  |  | ||||||
|  |         if should_yield and '- ' in line: | ||||||
|  |             yield line.split(' ')[-1] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     misspelled_task = regex.findall(command.stderr)[0] | ||||||
|  |     tasks = _get_all_tasks() | ||||||
|  |     return replace_command(command, misspelled_task, tasks) | ||||||
| @@ -14,7 +14,7 @@ class Bash(Generic): | |||||||
|                 " eval $TF_CMD".format(fuck) |                 " eval $TF_CMD".format(fuck) | ||||||
|  |  | ||||||
|         if settings.alter_history: |         if settings.alter_history: | ||||||
|             return alias + " && history -s $TF_CMD'" |             return alias + "; history -s $TF_CMD'" | ||||||
|         else: |         else: | ||||||
|             return alias + "'" |             return alias + "'" | ||||||
|  |  | ||||||
| @@ -44,4 +44,9 @@ class Bash(Generic): | |||||||
|             config = '~/.bashrc' |             config = '~/.bashrc' | ||||||
|         else: |         else: | ||||||
|             config = 'bash config' |             config = 'bash config' | ||||||
|         return 'eval $(thefuck --alias)', config |  | ||||||
|  |         return { | ||||||
|  |             'content': 'eval $(thefuck --alias)', | ||||||
|  |             'path': config, | ||||||
|  |             'reload': u'source {}'.format(config), | ||||||
|  |         } | ||||||
|   | |||||||
| @@ -20,8 +20,9 @@ class Fish(Generic): | |||||||
|  |  | ||||||
|     def app_alias(self, fuck): |     def app_alias(self, fuck): | ||||||
|         if settings.alter_history: |         if settings.alter_history: | ||||||
|             alter_history = ('    history --delete $fucked_up_command\n' |             alter_history = ('    builtin history delete --exact' | ||||||
|                              '    history --merge ^ /dev/null\n') |                              ' --case-sensitive -- $fucked_up_command\n' | ||||||
|  |                              '    builtin history merge ^ /dev/null\n') | ||||||
|         else: |         else: | ||||||
|             alter_history = '' |             alter_history = '' | ||||||
|         # It is VERY important to have the variables declared WITHIN the alias |         # It is VERY important to have the variables declared WITHIN the alias | ||||||
| @@ -66,8 +67,11 @@ class Fish(Generic): | |||||||
|         return u'; and '.join(commands) |         return u'; and '.join(commands) | ||||||
|  |  | ||||||
|     def how_to_configure(self): |     def how_to_configure(self): | ||||||
|         return (r"eval (thefuck --alias | tr '\n' ';')", |         return { | ||||||
|                 '~/.config/fish/config.fish') |             'content': r"eval (thefuck --alias | tr '\n' ';')", | ||||||
|  |             'path': '~/.config/fish/config.fish', | ||||||
|  |             'reload': 'fish', | ||||||
|  |         } | ||||||
|  |  | ||||||
|     def put_to_history(self, command): |     def put_to_history(self, command): | ||||||
|         try: |         try: | ||||||
|   | |||||||
| @@ -65,9 +65,19 @@ class Generic(object): | |||||||
|  |  | ||||||
|     def split_command(self, command): |     def split_command(self, command): | ||||||
|         """Split the command using shell-like syntax.""" |         """Split the command using shell-like syntax.""" | ||||||
|  |         encoded = self.encode_utf8(command) | ||||||
|  |         splitted = shlex.split(encoded) | ||||||
|  |         return self.decode_utf8(splitted) | ||||||
|  |  | ||||||
|  |     def encode_utf8(self, command): | ||||||
|         if six.PY2: |         if six.PY2: | ||||||
|             return [s.decode('utf8') for s in shlex.split(command.encode('utf8'))] |             return command.encode('utf8') | ||||||
|         return shlex.split(command) |         return command | ||||||
|  |  | ||||||
|  |     def decode_utf8(self, command_parts): | ||||||
|  |         if six.PY2: | ||||||
|  |             return [s.decode('utf8') for s in command_parts] | ||||||
|  |         return command_parts | ||||||
|  |  | ||||||
|     def quote(self, s): |     def quote(self, s): | ||||||
|         """Return a shell-escaped version of the string s.""" |         """Return a shell-escaped version of the string s.""" | ||||||
|   | |||||||
| @@ -3,11 +3,14 @@ from .generic import Generic | |||||||
|  |  | ||||||
| class Powershell(Generic): | class Powershell(Generic): | ||||||
|     def app_alias(self, fuck): |     def app_alias(self, fuck): | ||||||
|         return 'function ' + fuck + ' { \n' \ |         return 'function ' + fuck + ' {\n' \ | ||||||
|                '    $fuck = $(thefuck (Get-History -Count 1).CommandLine);\n' \ |                '    $history = (Get-History -Count 1).CommandLine;\n' \ | ||||||
|                '    if (-not [string]::IsNullOrWhiteSpace($fuck)) {\n' \ |                '    if (-not [string]::IsNullOrWhiteSpace($history)) {\n' \ | ||||||
|                '        if ($fuck.StartsWith("echo")) { $fuck = $fuck.Substring(5); }\n' \ |                '        $fuck = $(thefuck $history);\n' \ | ||||||
|                '        else { iex "$fuck"; }\n' \ |                '        if (-not [string]::IsNullOrWhiteSpace($fuck)) {\n' \ | ||||||
|  |                '            if ($fuck.StartsWith("echo")) { $fuck = $fuck.Substring(5); }\n' \ | ||||||
|  |                '            else { iex "$fuck"; }\n' \ | ||||||
|  |                '        }\n' \ | ||||||
|                '    }\n' \ |                '    }\n' \ | ||||||
|                '}\n' |                '}\n' | ||||||
|  |  | ||||||
| @@ -15,4 +18,8 @@ class Powershell(Generic): | |||||||
|         return u' -and '.join('({0})'.format(c) for c in commands) |         return u' -and '.join('({0})'.format(c) for c in commands) | ||||||
|  |  | ||||||
|     def how_to_configure(self): |     def how_to_configure(self): | ||||||
|         return 'iex "thefuck --alias"', '$profile' |         return { | ||||||
|  |             'content': 'iex "thefuck --alias"', | ||||||
|  |             'path': '$profile', | ||||||
|  |             'reload': '& $profile', | ||||||
|  |         } | ||||||
|   | |||||||
| @@ -31,4 +31,8 @@ class Tcsh(Generic): | |||||||
|         return u'#+{}\n{}\n'.format(int(time()), command_script) |         return u'#+{}\n{}\n'.format(int(time()), command_script) | ||||||
|  |  | ||||||
|     def how_to_configure(self): |     def how_to_configure(self): | ||||||
|         return 'eval `thefuck --alias`', '~/.tcshrc' |         return { | ||||||
|  |             'content': 'eval `thefuck --alias`', | ||||||
|  |             'path': '~/.tcshrc', | ||||||
|  |             'reload': 'tcsh', | ||||||
|  |         } | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ class Zsh(Generic): | |||||||
|                 " eval $TF_CMD".format(alias_name) |                 " eval $TF_CMD".format(alias_name) | ||||||
|  |  | ||||||
|         if settings.alter_history: |         if settings.alter_history: | ||||||
|             return alias + " && print -s $TF_CMD'" |             return alias + " ; test -n \"$TF_CMD\" && print -s $TF_CMD'" | ||||||
|         else: |         else: | ||||||
|             return alias + "'" |             return alias + "'" | ||||||
|  |  | ||||||
| @@ -45,4 +45,8 @@ class Zsh(Generic): | |||||||
|             return '' |             return '' | ||||||
|  |  | ||||||
|     def how_to_configure(self): |     def how_to_configure(self): | ||||||
|         return 'eval $(thefuck --alias)', '~/.zshrc' |         return { | ||||||
|  |             'content': 'eval $(thefuck --alias)', | ||||||
|  |             'path': '~/.zshrc', | ||||||
|  |             'reload': 'source ~/.zshrc', | ||||||
|  |         } | ||||||
|   | |||||||
| @@ -34,7 +34,8 @@ class Command(object): | |||||||
|             except Exception: |             except Exception: | ||||||
|                 logs.debug(u"Can't split command script {} because:\n {}".format( |                 logs.debug(u"Can't split command script {} because:\n {}".format( | ||||||
|                     self, sys.exc_info())) |                     self, sys.exc_info())) | ||||||
|                 self._script_parts = None |                 self._script_parts = [] | ||||||
|  |  | ||||||
|         return self._script_parts |         return self._script_parts | ||||||
|  |  | ||||||
|     def __eq__(self, other): |     def __eq__(self, other): | ||||||
|   | |||||||
| @@ -12,9 +12,10 @@ def read_actions(): | |||||||
|     while True: |     while True: | ||||||
|         key = get_key() |         key = get_key() | ||||||
|  |  | ||||||
|         if key in (const.KEY_UP, 'k'): |         # Handle arrows, j/k (qwerty), and n/e (colemak) | ||||||
|  |         if key in (const.KEY_UP, 'k', 'e'): | ||||||
|             yield const.ACTION_PREVIOUS |             yield const.ACTION_PREVIOUS | ||||||
|         elif key in (const.KEY_DOWN, 'j'): |         elif key in (const.KEY_DOWN, 'j', 'n'): | ||||||
|             yield const.ACTION_NEXT |             yield const.ACTION_NEXT | ||||||
|         elif key in (const.KEY_CTRL_C, 'q'): |         elif key in (const.KEY_CTRL_C, 'q'): | ||||||
|             yield const.ACTION_ABORT |             yield const.ACTION_ABORT | ||||||
|   | |||||||
| @@ -159,7 +159,7 @@ def is_app(command, *app_names, **kwargs): | |||||||
|     if kwargs: |     if kwargs: | ||||||
|         raise TypeError("got an unexpected keyword argument '{}'".format(kwargs.keys())) |         raise TypeError("got an unexpected keyword argument '{}'".format(kwargs.keys())) | ||||||
|  |  | ||||||
|     if command.script_parts is not None and len(command.script_parts) > at_least: |     if len(command.script_parts) > at_least: | ||||||
|         return command.script_parts[0] in app_names |         return command.script_parts[0] in app_names | ||||||
|  |  | ||||||
|     return False |     return False | ||||||
| @@ -264,7 +264,7 @@ def get_valid_history_without_current(command): | |||||||
|     from thefuck.shells import shell |     from thefuck.shells import shell | ||||||
|     history = shell.get_history() |     history = shell.get_history() | ||||||
|     tf_alias = get_alias() |     tf_alias = get_alias() | ||||||
|     executables = get_all_executables() |     executables = set(get_all_executables()) | ||||||
|     return [line for line in _not_corrected(history, tf_alias) |     return [line for line in _not_corrected(history, tf_alias) | ||||||
|             if not line.startswith(tf_alias) and not line == command.script |             if not line.startswith(tf_alias) and not line == command.script | ||||||
|             and line.split(' ')[0] in executables] |             and line.split(' ')[0] in executables] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user