mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-11-04 00:52:04 +00:00 
			
		
		
		
	Compare commits
	
		
			35 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c6af8409d9 | ||
| 
						 | 
					95e7d00aec | ||
| 
						 | 
					cdccf1881e | ||
| 
						 | 
					db6053b301 | ||
| 
						 | 
					183b70c8b8 | ||
| 
						 | 
					5e0cc8c703 | ||
| 
						 | 
					1aa2ec1795 | ||
| 
						 | 
					0c98053f74 | ||
| 
						 | 
					17b2fba48d | ||
| 
						 | 
					43886c38ff | ||
| 
						 | 
					9070748a86 | ||
| 
						 | 
					61de6f4a51 | ||
| 
						 | 
					d102af41d9 | ||
| 
						 | 
					b7002bb9f9 | ||
| 
						 | 
					18b4f5df6a | ||
| 
						 | 
					28153db4a8 | ||
| 
						 | 
					047a1a6072 | ||
| 
						 | 
					69db5c70e6 | ||
| 
						 | 
					fa1edd4bae | ||
| 
						 | 
					333c4b2a3f | ||
| 
						 | 
					b1f10642fa | ||
| 
						 | 
					047efd5575 | ||
| 
						 | 
					f604756cb7 | ||
| 
						 | 
					a27115bff1 | ||
| 
						 | 
					5d00b3bc25 | ||
| 
						 | 
					0cf4f5e8b0 | ||
| 
						 | 
					41707b80c6 | ||
| 
						 | 
					3a39deb485 | ||
| 
						 | 
					d4bc8cebf1 | ||
| 
						 | 
					6daf687237 | ||
| 
						 | 
					2207dd2668 | ||
| 
						 | 
					d1ab08a797 | ||
| 
						 | 
					51e89a36ef | ||
| 
						 | 
					39f7cc37eb | ||
| 
						 | 
					251b69b5a0 | 
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
								
							@@ -1,10 +1,10 @@
 | 
			
		||||
# The Fuck [](https://travis-ci.org/nvbn/thefuck) 
 | 
			
		||||
# The Fuck [![Version][version-badge]][version-link] [![Build Status][travis-badge]][travis-link] [![Windows Build Status][appveyor-badge]][appveyor-link] [![Coverage][coverage-badge]][coverage-link] [![MIT License][license-badge]](LICENSE.md)
 | 
			
		||||
 | 
			
		||||
Magnificent app which corrects your previous console command,
 | 
			
		||||
inspired by a [@liamosaur](https://twitter.com/liamosaur/)
 | 
			
		||||
[tweet](https://twitter.com/liamosaur/status/506975850596536320).
 | 
			
		||||
 | 
			
		||||
[](https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif)
 | 
			
		||||
[![gif with examples][examples-link]][examples-link]
 | 
			
		||||
 | 
			
		||||
Few more examples:
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +52,7 @@ Python 3.4.2 (default, Oct  8 2014, 13:08:17)
 | 
			
		||||
git: 'brnch' is not a git command. See 'git --help'.
 | 
			
		||||
 | 
			
		||||
Did you mean this?
 | 
			
		||||
	branch
 | 
			
		||||
    branch
 | 
			
		||||
 | 
			
		||||
➜ fuck
 | 
			
		||||
git branch [enter/↑/↓/ctrl+c]
 | 
			
		||||
@@ -97,7 +97,7 @@ Reading package lists... Done
 | 
			
		||||
## Installation [*experimental*]
 | 
			
		||||
 | 
			
		||||
On Ubuntu and OS X you can install `The Fuck` with installation script:
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
wget -O - https://raw.githubusercontent.com/nvbn/thefuck/master/install.sh | sh - && $0
 | 
			
		||||
```
 | 
			
		||||
@@ -107,7 +107,7 @@ wget -O - https://raw.githubusercontent.com/nvbn/thefuck/master/install.sh | sh
 | 
			
		||||
Install `The Fuck` with `pip`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo pip install thefuck
 | 
			
		||||
sudo -H pip install thefuck
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
 | 
			
		||||
@@ -155,8 +155,9 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `dry` – fixes repetitions like `git git push`;
 | 
			
		||||
* `fix_alt_space` – replaces Alt+Space with Space character;
 | 
			
		||||
* `fix_file` – opens a file with an error in your `$EDITOR`;
 | 
			
		||||
* `git_add` – fixes *"Did you forget to 'git add'?"*;
 | 
			
		||||
* `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*;
 | 
			
		||||
* `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_list` – catches `git branch list` in place of `git branch` and removes created branch;
 | 
			
		||||
* `git_checkout` – fixes branch name or creates new branch;
 | 
			
		||||
* `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output;
 | 
			
		||||
@@ -167,6 +168,7 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
 | 
			
		||||
* `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`;
 | 
			
		||||
* `git_push_pull` – runs `git pull` when `push` was rejected;
 | 
			
		||||
* `git_rm_recursive` – adds `-r` when you try to `rm` a directory;
 | 
			
		||||
* `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_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
 | 
			
		||||
@@ -305,7 +307,7 @@ debug = False
 | 
			
		||||
Or via environment variables:
 | 
			
		||||
 | 
			
		||||
* `THEFUCK_RULES` – list of enabled rules, like `DEFAULT_RULES:rm_root` or `sudo:no_command`;
 | 
			
		||||
* `THEFUCK_EXCLUDE_RULES` – list of disabled rules, like `git_pull:git_push`; 
 | 
			
		||||
* `THEFUCK_EXCLUDE_RULES` – list of disabled rules, like `git_pull:git_push`;
 | 
			
		||||
* `THEFUCK_REQUIRE_CONFIRMATION` – require confirmation before running new command, `true/false`;
 | 
			
		||||
* `THEFUCK_WAIT_COMMAND` – max amount of time in seconds for getting previous command output;
 | 
			
		||||
* `THEFUCK_NO_COLORS` – disable colored output, `true/false`;
 | 
			
		||||
@@ -357,3 +359,15 @@ sudo apt-get install pandoc
 | 
			
		||||
 | 
			
		||||
## License MIT
 | 
			
		||||
Project License can be found [here](LICENSE.md).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[version-badge]:   https://img.shields.io/pypi/v/thefuck.svg?label=version
 | 
			
		||||
[version-link]:    https://pypi.python.org/pypi/thefuck/
 | 
			
		||||
[travis-badge]:    https://img.shields.io/travis/nvbn/thefuck.svg
 | 
			
		||||
[travis-link]:     https://travis-ci.org/nvbn/thefuck
 | 
			
		||||
[appveyor-badge]:  https://img.shields.io/appveyor/ci/nvbn/thefuck.svg?label=windows%20build
 | 
			
		||||
[appveyor-link]:   https://ci.appveyor.com/project/nvbn/thefuck
 | 
			
		||||
[coverage-badge]:  https://img.shields.io/coveralls/nvbn/thefuck.svg
 | 
			
		||||
[coverage-link]:   https://coveralls.io/github/nvbn/thefuck
 | 
			
		||||
[license-badge]:   https://img.shields.io/badge/license-MIT-007EC7.svg
 | 
			
		||||
[examples-link]:   https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
build: false
 | 
			
		||||
 | 
			
		||||
environment:
 | 
			
		||||
  matrix:
 | 
			
		||||
    - PYTHON: "C:/Python27"
 | 
			
		||||
    - PYTHON: "C:/Python33"
 | 
			
		||||
    - PYTHON: "C:/Python34"
 | 
			
		||||
    - PYTHON: "C:/Python35"
 | 
			
		||||
 | 
			
		||||
init:
 | 
			
		||||
  - "ECHO %PYTHON%"
 | 
			
		||||
  - ps: "ls C:/Python*"
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py')
 | 
			
		||||
  - "%PYTHON%/python.exe C:/get-pip.py"
 | 
			
		||||
  - "%PYTHON%/Scripts/pip.exe install -U setuptools"
 | 
			
		||||
  - "%PYTHON%/python.exe setup.py develop"
 | 
			
		||||
  - "%PYTHON%/Scripts/pip.exe install -U -r requirements.txt"
 | 
			
		||||
 | 
			
		||||
test_script:
 | 
			
		||||
  - "%PYTHON%/Scripts/py.test.exe -sv"
 | 
			
		||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							@@ -26,7 +26,7 @@ elif (3, 0) < version < (3, 3):
 | 
			
		||||
          ' ({}.{} detected).'.format(*version))
 | 
			
		||||
    sys.exit(-1)
 | 
			
		||||
 | 
			
		||||
VERSION = '3.5'
 | 
			
		||||
VERSION = '3.8'
 | 
			
		||||
 | 
			
		||||
install_requires = ['psutil', 'colorama', 'six', 'decorator']
 | 
			
		||||
extras_require = {':python_version<"3.4"': ['pathlib'],
 | 
			
		||||
 
 | 
			
		||||
@@ -4,36 +4,28 @@ from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def did_not_match(target, did_you_forget=True):
 | 
			
		||||
    error = ("error: pathspec '{}' did not match any "
 | 
			
		||||
             "file(s) known to git.".format(target))
 | 
			
		||||
    if did_you_forget:
 | 
			
		||||
        error = ("{}\nDid you forget to 'git add'?'".format(error))
 | 
			
		||||
    return error
 | 
			
		||||
def stderr(target):
 | 
			
		||||
    return ("error: pathspec '{}' did not match any "
 | 
			
		||||
            'file(s) known to git.'.format(target))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git submodule update unknown',
 | 
			
		||||
            stderr=did_not_match('unknown')),
 | 
			
		||||
    Command(script='git commit unknown',
 | 
			
		||||
            stderr=did_not_match('unknown'))])  # Older versions of Git
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
@pytest.mark.parametrize('script, target', [
 | 
			
		||||
    ('git submodule update unknown', 'unknown'),
 | 
			
		||||
    ('git commit unknown', 'unknown')])
 | 
			
		||||
def test_match(stderr, script, target):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git submodule update known', stderr=('')),
 | 
			
		||||
    Command(script='git commit known', stderr=('')),
 | 
			
		||||
    Command(script='git commit unknown',  # Newer versions of Git
 | 
			
		||||
            stderr=did_not_match('unknown', False))])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'git submodule update known', 'git commit known'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('git submodule update unknown', stderr=did_not_match('unknown')),
 | 
			
		||||
@pytest.mark.parametrize('script, target, new_command', [
 | 
			
		||||
    ('git submodule update unknown', 'unknown',
 | 
			
		||||
     'git add -- unknown && git submodule update unknown'),
 | 
			
		||||
    (Command('git commit unknown', stderr=did_not_match('unknown')),  # Old Git
 | 
			
		||||
    ('git commit unknown', 'unknown',
 | 
			
		||||
     'git add -- unknown && git commit unknown')])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
def test_get_new_command(stderr, script, target, new_command):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								tests/rules/test_git_branch_exists.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/rules/test_git_branch_exists.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_branch_exists import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr(branch_name):
 | 
			
		||||
    return "fatal: A branch named '{}' already exists.".format(branch_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def new_command(branch_name):
 | 
			
		||||
    return [cmd.format(branch_name) for cmd in [
 | 
			
		||||
        'git branch -d {0} && git branch {0}',
 | 
			
		||||
        'git branch -D {0} && git branch {0}', 'git checkout {0}']]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, branch_name', [
 | 
			
		||||
    ('git branch foo', 'foo'),
 | 
			
		||||
    ('git branch bar', 'bar')])
 | 
			
		||||
def test_match(stderr, script, branch_name):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['git branch foo', 'git branch bar'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, branch_name, ', [
 | 
			
		||||
    ('git branch foo', 'foo'), ('git branch bar', 'bar')])
 | 
			
		||||
def test_get_new_command(stderr, new_command, script, branch_name):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
							
								
								
									
										27
									
								
								tests/rules/test_git_rm_recursive.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/rules/test_git_rm_recursive.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_rm_recursive import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr(target):
 | 
			
		||||
    return "fatal: not removing '{}' recursively without -r".format(target)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target', [
 | 
			
		||||
    ('git rm foo', 'foo'),
 | 
			
		||||
    ('git rm foo bar', 'foo 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'])
 | 
			
		||||
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 -r foo'),
 | 
			
		||||
    ('git rm foo bar', 'foo bar', 'git rm -r foo bar')])
 | 
			
		||||
def test_get_new_command(stderr, script, target, new_command):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
@@ -3,38 +3,23 @@ from thefuck.rules.history import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def history(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.shells.shell.get_history',
 | 
			
		||||
                        return_value=['le cat', 'fuck', 'ls cat',
 | 
			
		||||
                                      'diff x', 'nocommand x'])
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def history_without_current(mocker):
 | 
			
		||||
    return mocker.patch(
 | 
			
		||||
        'thefuck.rules.history.get_valid_history_without_current',
 | 
			
		||||
        return_value=['ls cat', 'diff x'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def alias(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.rules.history.get_alias',
 | 
			
		||||
                        return_value='fuck')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def callables(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.rules.history.get_all_executables',
 | 
			
		||||
                        return_value=['diff', 'ls'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
 | 
			
		||||
@pytest.mark.parametrize('script', ['ls cet', 'daff x'])
 | 
			
		||||
def test_match(script):
 | 
			
		||||
    assert match(Command(script=script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
 | 
			
		||||
@pytest.mark.parametrize('script', ['apt-get', 'nocommand y'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('history', 'callables', 'no_memoize', 'alias')
 | 
			
		||||
@pytest.mark.parametrize('script, result', [
 | 
			
		||||
    ('ls cet', 'ls cat'),
 | 
			
		||||
    ('daff x', 'diff x')])
 | 
			
		||||
 
 | 
			
		||||
@@ -6,22 +6,37 @@ from tests.utils import Command
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def get_all_executables(mocker):
 | 
			
		||||
    mocker.patch('thefuck.rules.no_command.get_all_executables',
 | 
			
		||||
                 return_value=['vim', 'apt-get', 'fsck'])
 | 
			
		||||
                 return_value=['vim', 'fsck', 'git', 'go'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def history_without_current(mocker):
 | 
			
		||||
    return mocker.patch(
 | 
			
		||||
        'thefuck.rules.no_command.get_valid_history_without_current',
 | 
			
		||||
        return_value=['git commit'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('no_memoize')
 | 
			
		||||
def test_match():
 | 
			
		||||
    assert match(Command(stderr='vom: not found', script='vom file.py'))
 | 
			
		||||
    assert match(Command(stderr='fucck: not found', script='fucck'))
 | 
			
		||||
    assert not match(Command(stderr='qweqwe: not found', script='qweqwe'))
 | 
			
		||||
    assert not match(Command(stderr='some text', script='vom file.py'))
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('vom file.py', 'vom: not found'),
 | 
			
		||||
    ('fucck', 'fucck: not found'),
 | 
			
		||||
    ('got commit', 'got: command not found')])
 | 
			
		||||
def test_match(script, stderr):
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('no_memoize')
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    assert get_new_command(
 | 
			
		||||
        Command(stderr='vom: not found',
 | 
			
		||||
                script='vom file.py')) == ['vim file.py']
 | 
			
		||||
    assert get_new_command(
 | 
			
		||||
        Command(stderr='fucck: not found',
 | 
			
		||||
                script='fucck')) == ['fsck']
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('qweqwe', 'qweqwe: not found'),
 | 
			
		||||
    ('vom file.py', 'some text')])
 | 
			
		||||
def test_not_match(script, stderr):
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('no_memoize')
 | 
			
		||||
@pytest.mark.parametrize('script, result', [
 | 
			
		||||
    ('vom file.py', ['vim file.py']),
 | 
			
		||||
    ('fucck', ['fsck']),
 | 
			
		||||
    ('got commit', ['git commit', 'go commit'])])
 | 
			
		||||
def test_get_new_command(script, result):
 | 
			
		||||
    assert get_new_command(Command(script)) == result
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,7 @@ def test_match(ssh_error):
 | 
			
		||||
    assert not match(Command('ssh'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(os.name == 'nt', reason='Skip if testing on Windows')
 | 
			
		||||
def test_side_effect(ssh_error):
 | 
			
		||||
    errormsg, path, reset, known_hosts = ssh_error
 | 
			
		||||
    command = Command('ssh user@host', stderr=errormsg)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,14 +19,18 @@ class TestFish(object):
 | 
			
		||||
        return mock
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def environ(self, monkeypatch):
 | 
			
		||||
        data = {'TF_OVERRIDDEN_ALIASES': 'cd, ls, man, open'}
 | 
			
		||||
        monkeypatch.setattr('thefuck.shells.fish.os.environ', data)
 | 
			
		||||
        return data
 | 
			
		||||
    def os_environ(self, monkeypatch, key, value):
 | 
			
		||||
        monkeypatch.setattr('os.environ', {key: value})
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.usefixture('environ')
 | 
			
		||||
    def test_get_overridden_aliases(self, shell, environ):
 | 
			
		||||
        assert shell._get_overridden_aliases() == ['cd', 'ls', 'man', 'open']
 | 
			
		||||
    @pytest.mark.parametrize('key, value', [
 | 
			
		||||
        ('TF_OVERRIDDEN_ALIASES', 'cut,git,sed'),  # legacy
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', 'cut,git,sed'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', 'cut, git, sed'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', ' cut,\tgit,sed\n'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
 | 
			
		||||
    def test_get_overridden_aliases(self, shell, os_environ):
 | 
			
		||||
        assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep',
 | 
			
		||||
                                                   'ls', 'man', 'open', 'sed'}
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('before, after', [
 | 
			
		||||
        ('cd', 'cd'),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								tests/shells/test_powershell.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/shells/test_powershell.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.shells import Powershell
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('isfile', 'no_memoize', 'no_cache')
 | 
			
		||||
class TestPowershell(object):
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def shell(self):
 | 
			
		||||
        return Powershell()
 | 
			
		||||
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('ls', 'cd') == '(ls) -and (cd)'
 | 
			
		||||
 | 
			
		||||
    def test_app_alias(self, shell):
 | 
			
		||||
        assert 'function fuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'function FUCK' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'thefuck' in shell.app_alias('fuck')
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from pathlib import PosixPath
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from thefuck import corrector, const
 | 
			
		||||
from tests.utils import Rule, Command, CorrectedCommand
 | 
			
		||||
from thefuck.corrector import get_corrected_commands, organize_commands
 | 
			
		||||
@@ -30,7 +30,7 @@ class TestGetRules(object):
 | 
			
		||||
        (['git.py', 'bash.py'], ['git'], ['git'], [])])
 | 
			
		||||
    def test_get_rules(self, glob, settings, paths, conf_rules, exclude_rules,
 | 
			
		||||
                       loaded_rules):
 | 
			
		||||
        glob([PosixPath(path) for path in paths])
 | 
			
		||||
        glob([Path(path) for path in paths])
 | 
			
		||||
        settings.update(rules=conf_rules,
 | 
			
		||||
                        priority={},
 | 
			
		||||
                        exclude_rules=exclude_rules)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
from subprocess import PIPE
 | 
			
		||||
from mock import Mock
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
@@ -39,9 +40,10 @@ class TestRule(object):
 | 
			
		||||
                              enabled_by_default=True,
 | 
			
		||||
                              priority=900,
 | 
			
		||||
                              requires_output=True))
 | 
			
		||||
        assert Rule.from_path(Path('/rules/bash.py')) \
 | 
			
		||||
        rule_path = os.path.join(os.sep, 'rules', 'bash.py')
 | 
			
		||||
        assert Rule.from_path(Path(rule_path)) \
 | 
			
		||||
               == Rule('bash', match, get_new_command, priority=900)
 | 
			
		||||
        load_source.assert_called_once_with('bash', '/rules/bash.py')
 | 
			
		||||
        load_source.assert_called_once_with('bash', rule_path)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
 | 
			
		||||
        (const.DEFAULT_RULES, [], Rule('git', enabled_by_default=True), True),
 | 
			
		||||
@@ -110,6 +112,7 @@ class TestCommand(object):
 | 
			
		||||
            'apt-get search vim', 'stdout', 'stderr')
 | 
			
		||||
        Popen.assert_called_once_with('apt-get search vim',
 | 
			
		||||
                                      shell=True,
 | 
			
		||||
                                      stdin=PIPE,
 | 
			
		||||
                                      stdout=PIPE,
 | 
			
		||||
                                      stderr=PIPE,
 | 
			
		||||
                                      env={})
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,8 @@ from mock import Mock
 | 
			
		||||
import six
 | 
			
		||||
from thefuck.utils import default_settings, \
 | 
			
		||||
    memoize, get_closest, get_all_executables, replace_argument, \
 | 
			
		||||
    get_all_matched_commands, is_app, for_app, cache, compatibility_call
 | 
			
		||||
    get_all_matched_commands, is_app, for_app, cache, compatibility_call, \
 | 
			
		||||
    get_valid_history_without_current
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -229,3 +230,29 @@ class TestCompatibilityCall(object):
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        assert compatibility_call(side_effect, Command(), Command())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGetValidHistoryWithoutCurrent(object):
 | 
			
		||||
    @pytest.fixture(autouse=True)
 | 
			
		||||
    def history(self, mocker):
 | 
			
		||||
        return mocker.patch('thefuck.shells.shell.get_history',
 | 
			
		||||
                            return_value=['le cat', 'fuck', 'ls cat',
 | 
			
		||||
                                          'diff x', 'nocommand x'])
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture(autouse=True)
 | 
			
		||||
    def alias(self, mocker):
 | 
			
		||||
        return mocker.patch('thefuck.utils.get_alias',
 | 
			
		||||
                            return_value='fuck')
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture(autouse=True)
 | 
			
		||||
    def callables(self, mocker):
 | 
			
		||||
        return mocker.patch('thefuck.utils.get_all_executables',
 | 
			
		||||
                            return_value=['diff', 'ls'])
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('script, result', [
 | 
			
		||||
        ('le cat', ['ls cat', 'diff x']),
 | 
			
		||||
        ('diff x', ['ls cat']),
 | 
			
		||||
        ('fuck', ['ls cat', 'diff x'])])
 | 
			
		||||
    def test_get_valid_history_without_current(self, script, result):
 | 
			
		||||
        command = Command(script=script)
 | 
			
		||||
        assert get_valid_history_without_current(command) == result
 | 
			
		||||
 
 | 
			
		||||
@@ -5,15 +5,14 @@ from thefuck.specific.git import git_support
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
def match(command):
 | 
			
		||||
    return ('did not match any file(s) known to git.' in command.stderr
 | 
			
		||||
            and "Did you forget to 'git add'?" in command.stderr)
 | 
			
		||||
    return 'did not match any file(s) known to git.' in command.stderr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    missing_file = re.findall(
 | 
			
		||||
            r"error: pathspec '([^']*)' "
 | 
			
		||||
            r"did not match any file\(s\) known to git.", command.stderr)[0]
 | 
			
		||||
        r"error: pathspec '([^']*)' "
 | 
			
		||||
        r'did not match any file\(s\) known to git.', command.stderr)[0]
 | 
			
		||||
 | 
			
		||||
    formatme = shell.and_('git add -- {}', '{}')
 | 
			
		||||
    return formatme.format(missing_file, command.script)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								thefuck/rules/git_branch_exists.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								thefuck/rules/git_branch_exists.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
import re
 | 
			
		||||
from thefuck.shells import shell
 | 
			
		||||
from thefuck.specific.git import git_support
 | 
			
		||||
from thefuck.utils import eager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
def match(command):
 | 
			
		||||
    return ('branch' in command.script
 | 
			
		||||
            and "fatal: A branch named '" in command.stderr
 | 
			
		||||
            and " already exists." in command.stderr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
@eager
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    branch_name = re.findall(
 | 
			
		||||
        r"fatal: A branch named '([^']*)' already exists.", command.stderr)[0]
 | 
			
		||||
    new_command_templates = [['git branch -d {0}', 'git branch {0}'],
 | 
			
		||||
                             ['git branch -D {0}', 'git branch {0}'],
 | 
			
		||||
                             ['git checkout {0}']]
 | 
			
		||||
    for new_command_template in new_command_templates:
 | 
			
		||||
        yield shell.and_(*new_command_template).format(branch_name)
 | 
			
		||||
							
								
								
									
										15
									
								
								thefuck/rules/git_rm_recursive.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/git_rm_recursive.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
from thefuck.specific.git import git_support
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
def match(command):
 | 
			
		||||
    return (' rm ' in command.script
 | 
			
		||||
            and "fatal: not removing '" in command.stderr
 | 
			
		||||
            and "' recursively without -r" in command.stderr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@git_support
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    index = command.script_parts.index('rm') + 1
 | 
			
		||||
    command.script_parts.insert(index, '-r')
 | 
			
		||||
    return u' '.join(command.script_parts)
 | 
			
		||||
@@ -1,37 +1,15 @@
 | 
			
		||||
from difflib import get_close_matches
 | 
			
		||||
from thefuck.shells import shell
 | 
			
		||||
from thefuck.utils import get_closest, memoize, get_all_executables, get_alias
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _not_corrected(history, tf_alias):
 | 
			
		||||
    """Returns all lines from history except that comes before `fuck`."""
 | 
			
		||||
    previous = None
 | 
			
		||||
    for line in history:
 | 
			
		||||
        if previous is not None and line != tf_alias:
 | 
			
		||||
            yield previous
 | 
			
		||||
        previous = line
 | 
			
		||||
    if history:
 | 
			
		||||
        yield history[-1]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@memoize
 | 
			
		||||
def _history_of_exists_without_current(command):
 | 
			
		||||
    history = shell.get_history()
 | 
			
		||||
    tf_alias = get_alias()
 | 
			
		||||
    executables = get_all_executables()
 | 
			
		||||
    return [line for line in _not_corrected(history, tf_alias)
 | 
			
		||||
            if not line.startswith(tf_alias) and not line == command.script
 | 
			
		||||
            and line.split(' ')[0] in executables]
 | 
			
		||||
from thefuck.utils import get_closest, get_valid_history_without_current
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match(command):
 | 
			
		||||
    return len(get_close_matches(command.script,
 | 
			
		||||
                                 _history_of_exists_without_current(command)))
 | 
			
		||||
                                 get_valid_history_without_current(command)))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    return get_closest(command.script,
 | 
			
		||||
                       _history_of_exists_without_current(command))
 | 
			
		||||
                       get_valid_history_without_current(command))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
priority = 9999
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
from difflib import get_close_matches
 | 
			
		||||
from thefuck.utils import get_all_executables
 | 
			
		||||
from thefuck.utils import get_all_executables, \
 | 
			
		||||
    get_valid_history_without_current, get_closest
 | 
			
		||||
from thefuck.specific.sudo import sudo_support
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -11,10 +12,29 @@ def match(command):
 | 
			
		||||
                                       get_all_executables())))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_used_executables(command):
 | 
			
		||||
    for script in get_valid_history_without_current(command):
 | 
			
		||||
        yield script.split(' ')[0]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@sudo_support
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    old_command = command.script_parts[0]
 | 
			
		||||
    new_cmds = get_close_matches(old_command, get_all_executables(), cutoff=0.1)
 | 
			
		||||
 | 
			
		||||
    # One from history:
 | 
			
		||||
    already_used = get_closest(
 | 
			
		||||
        old_command, _get_used_executables(command),
 | 
			
		||||
        fallback_to_first=False)
 | 
			
		||||
    if already_used:
 | 
			
		||||
        new_cmds = [already_used]
 | 
			
		||||
    else:
 | 
			
		||||
        new_cmds = []
 | 
			
		||||
 | 
			
		||||
    # Other from all executables:
 | 
			
		||||
    new_cmds += [cmd for cmd in get_close_matches(old_command,
 | 
			
		||||
                                                  get_all_executables())
 | 
			
		||||
                 if cmd not in new_cmds]
 | 
			
		||||
 | 
			
		||||
    return [' '.join([new_command] + command.script_parts[1:])
 | 
			
		||||
            for new_command in new_cmds]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,20 +9,37 @@ from .fish import Fish
 | 
			
		||||
from .generic import Generic
 | 
			
		||||
from .tcsh import Tcsh
 | 
			
		||||
from .zsh import Zsh
 | 
			
		||||
from .powershell import Powershell
 | 
			
		||||
 | 
			
		||||
shells = {'bash': Bash,
 | 
			
		||||
          'fish': Fish,
 | 
			
		||||
          'zsh': Zsh,
 | 
			
		||||
          'csh': Tcsh,
 | 
			
		||||
          'tcsh': Tcsh}
 | 
			
		||||
          'tcsh': Tcsh,
 | 
			
		||||
          'powershell': Powershell}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_shell():
 | 
			
		||||
    try:
 | 
			
		||||
        shell_name = Process(os.getpid()).parent().name()
 | 
			
		||||
    except TypeError:
 | 
			
		||||
        shell_name = Process(os.getpid()).parent.name
 | 
			
		||||
    return shells.get(shell_name, Generic)()
 | 
			
		||||
    proc = Process(os.getpid())
 | 
			
		||||
 | 
			
		||||
    while (proc is not None):
 | 
			
		||||
        name = None
 | 
			
		||||
        try:
 | 
			
		||||
            name = proc.name()
 | 
			
		||||
        except TypeError:
 | 
			
		||||
            name = proc.name
 | 
			
		||||
 | 
			
		||||
        name = os.path.splitext(name)[0]
 | 
			
		||||
 | 
			
		||||
        if name in shells:
 | 
			
		||||
            return shells[name]()
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            proc = proc.parent()
 | 
			
		||||
        except TypeError:
 | 
			
		||||
            proc = proc.parent
 | 
			
		||||
 | 
			
		||||
    return Generic()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
shell = _get_shell()
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,12 @@ from .generic import Generic
 | 
			
		||||
 | 
			
		||||
class Fish(Generic):
 | 
			
		||||
    def _get_overridden_aliases(self):
 | 
			
		||||
        overridden_aliases = os.environ.get('TF_OVERRIDDEN_ALIASES', '').strip()
 | 
			
		||||
        if overridden_aliases:
 | 
			
		||||
            return [alias.strip() for alias in overridden_aliases.split(',')]
 | 
			
		||||
        else:
 | 
			
		||||
            return ['cd', 'grep', 'ls', 'man', 'open']
 | 
			
		||||
        overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES',
 | 
			
		||||
                                    os.environ.get('TF_OVERRIDDEN_ALIASES', ''))
 | 
			
		||||
        default = {'cd', 'grep', 'ls', 'man', 'open'}
 | 
			
		||||
        for alias in overridden.split(','):
 | 
			
		||||
            default.add(alias.strip())
 | 
			
		||||
        return default
 | 
			
		||||
 | 
			
		||||
    def app_alias(self, fuck):
 | 
			
		||||
        # It is VERY important to have the variables declared WITHIN the alias
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								thefuck/shells/powershell.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								thefuck/shells/powershell.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
from .generic import Generic
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Powershell(Generic):
 | 
			
		||||
    def app_alias(self, fuck):
 | 
			
		||||
        return 'function ' + fuck + ' { \n' \
 | 
			
		||||
               '    $fuck = $(thefuck (Get-History -Count 1).CommandLine)\n' \
 | 
			
		||||
               '    if (-not [string]::IsNullOrWhiteSpace($fuck)) {\n' \
 | 
			
		||||
               '        if ($fuck.StartsWith("echo")) { $fuck = $fuck.Substring(5) }\n' \
 | 
			
		||||
               '        else { iex "$fuck" }\n' \
 | 
			
		||||
               '    }\n' \
 | 
			
		||||
               '}\n'
 | 
			
		||||
 | 
			
		||||
    def and_(self, *commands):
 | 
			
		||||
        return u' -and '.join('({0})'.format(c) for c in commands)
 | 
			
		||||
 | 
			
		||||
    def how_to_configure(self):
 | 
			
		||||
        return 'iex "thefuck --alias"', '$profile'
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import msvcrt
 | 
			
		||||
import win_unicode_console
 | 
			
		||||
@@ -16,10 +17,11 @@ def get_key():
 | 
			
		||||
        ch = msvcrt.getch()  # second call returns the actual key code
 | 
			
		||||
 | 
			
		||||
    if ch == b'\x03':
 | 
			
		||||
        raise const.KEY_CTRL_C
 | 
			
		||||
        return const.KEY_CTRL_C
 | 
			
		||||
    if ch == b'H':
 | 
			
		||||
        return const.KEY_UP
 | 
			
		||||
    if ch == b'P':
 | 
			
		||||
        return const.KEY_DOWN
 | 
			
		||||
 | 
			
		||||
    return ch.decode(sys.stdout.encoding)
 | 
			
		||||
    encoding = sys.stdout.encoding or os.environ.get('PYTHONIOENCODING', 'utf-8')
 | 
			
		||||
    return ch.decode(encoding)
 | 
			
		||||
 
 | 
			
		||||
@@ -114,7 +114,7 @@ class Command(object):
 | 
			
		||||
        env.update(settings.env)
 | 
			
		||||
 | 
			
		||||
        with logs.debug_time(u'Call: {}; with env: {};'.format(script, env)):
 | 
			
		||||
            result = Popen(script, shell=True, stdout=PIPE, stderr=PIPE, env=env)
 | 
			
		||||
            result = Popen(script, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
 | 
			
		||||
            if cls._wait_output(result):
 | 
			
		||||
                stdout = result.stdout.read().decode('utf-8')
 | 
			
		||||
                stderr = result.stderr.read().decode('utf-8')
 | 
			
		||||
 
 | 
			
		||||
@@ -269,3 +269,24 @@ def get_installation_info():
 | 
			
		||||
 | 
			
		||||
def get_alias():
 | 
			
		||||
    return os.environ.get('TF_ALIAS', 'fuck')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@memoize
 | 
			
		||||
def get_valid_history_without_current(command):
 | 
			
		||||
    def _not_corrected(history, tf_alias):
 | 
			
		||||
        """Returns all lines from history except that comes before `fuck`."""
 | 
			
		||||
        previous = None
 | 
			
		||||
        for line in history:
 | 
			
		||||
            if previous is not None and line != tf_alias:
 | 
			
		||||
                yield previous
 | 
			
		||||
            previous = line
 | 
			
		||||
        if history:
 | 
			
		||||
            yield history[-1]
 | 
			
		||||
 | 
			
		||||
    from thefuck.shells import shell
 | 
			
		||||
    history = shell.get_history()
 | 
			
		||||
    tf_alias = get_alias()
 | 
			
		||||
    executables = get_all_executables()
 | 
			
		||||
    return [line for line in _not_corrected(history, tf_alias)
 | 
			
		||||
            if not line.startswith(tf_alias) and not line == command.script
 | 
			
		||||
            and line.split(' ')[0] in executables]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user