mirror of
https://github.com/nvbn/thefuck.git
synced 2025-02-22 12:58:33 +00:00
#414: Move system-dependent utils in system
module
This commit is contained in:
parent
0560f4ba8e
commit
29c1d1efcf
@ -4,37 +4,32 @@ import pytest
|
|||||||
from itertools import islice
|
from itertools import islice
|
||||||
from thefuck import ui
|
from thefuck import ui
|
||||||
from thefuck.types import CorrectedCommand
|
from thefuck.types import CorrectedCommand
|
||||||
|
from thefuck import const
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def patch_getch(monkeypatch):
|
def patch_get_key(monkeypatch):
|
||||||
def patch(vals):
|
def patch(vals):
|
||||||
def getch():
|
vals = iter(vals)
|
||||||
for val in vals:
|
monkeypatch.setattr('thefuck.ui.get_key', lambda: next(vals))
|
||||||
if val == KeyboardInterrupt:
|
|
||||||
raise val
|
|
||||||
else:
|
|
||||||
yield val
|
|
||||||
|
|
||||||
getch_gen = getch()
|
|
||||||
monkeypatch.setattr('thefuck.ui.getch', lambda: next(getch_gen))
|
|
||||||
|
|
||||||
return patch
|
return patch
|
||||||
|
|
||||||
|
|
||||||
def test_read_actions(patch_getch):
|
def test_read_actions(patch_get_key):
|
||||||
patch_getch([ # Enter:
|
patch_get_key([
|
||||||
'\n',
|
# Enter:
|
||||||
# Enter:
|
'\n',
|
||||||
'\r',
|
# Enter:
|
||||||
# Ignored:
|
'\r',
|
||||||
'x', 'y',
|
# Ignored:
|
||||||
# Up:
|
'x', 'y',
|
||||||
'\x1b', '[', 'A',
|
# Up:
|
||||||
# Down:
|
const.KEY_UP,
|
||||||
'\x1b', '[', 'B',
|
# Down:
|
||||||
# Ctrl+C:
|
const.KEY_DOWN,
|
||||||
KeyboardInterrupt], )
|
# Ctrl+C:
|
||||||
|
const.KEY_CTRL_C])
|
||||||
assert list(islice(ui.read_actions(), 5)) \
|
assert list(islice(ui.read_actions(), 5)) \
|
||||||
== [ui.SELECT, ui.SELECT, ui.PREVIOUS, ui.NEXT, ui.ABORT]
|
== [ui.SELECT, ui.SELECT, ui.PREVIOUS, ui.NEXT, ui.ABORT]
|
||||||
|
|
||||||
@ -80,25 +75,25 @@ class TestSelectCommand(object):
|
|||||||
== commands_with_side_effect[0]
|
== commands_with_side_effect[0]
|
||||||
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
|
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
|
||||||
|
|
||||||
def test_with_confirmation(self, capsys, patch_getch, commands):
|
def test_with_confirmation(self, capsys, patch_get_key, commands):
|
||||||
patch_getch(['\n'])
|
patch_get_key(['\n'])
|
||||||
assert ui.select_command(iter(commands)) == commands[0]
|
assert ui.select_command(iter(commands)) == commands[0]
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
|
||||||
|
|
||||||
def test_with_confirmation_abort(self, capsys, patch_getch, commands):
|
def test_with_confirmation_abort(self, capsys, patch_get_key, commands):
|
||||||
patch_getch([KeyboardInterrupt])
|
patch_get_key([const.KEY_CTRL_C])
|
||||||
assert ui.select_command(iter(commands)) is None
|
assert ui.select_command(iter(commands)) is None
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\nAborted\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\nAborted\n')
|
||||||
|
|
||||||
def test_with_confirmation_with_side_effct(self, capsys, patch_getch,
|
def test_with_confirmation_with_side_effct(self, capsys, patch_get_key,
|
||||||
commands_with_side_effect):
|
commands_with_side_effect):
|
||||||
patch_getch(['\n'])
|
patch_get_key(['\n'])
|
||||||
assert ui.select_command(iter(commands_with_side_effect))\
|
assert ui.select_command(iter(commands_with_side_effect)) \
|
||||||
== commands_with_side_effect[0]
|
== commands_with_side_effect[0]
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
|
||||||
|
|
||||||
def test_with_confirmation_select_second(self, capsys, patch_getch, commands):
|
def test_with_confirmation_select_second(self, capsys, patch_get_key, commands):
|
||||||
patch_getch(['\x1b', '[', 'B', '\n'])
|
patch_get_key([const.KEY_DOWN, '\n'])
|
||||||
assert ui.select_command(iter(commands)) == commands[1]
|
assert ui.select_command(iter(commands)) == commands[1]
|
||||||
assert capsys.readouterr() == (
|
assert capsys.readouterr() == (
|
||||||
'', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\x1b[1K\rcd [enter/↑/↓/ctrl+c]\n')
|
'', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\x1b[1K\rcd [enter/↑/↓/ctrl+c]\n')
|
||||||
|
14
thefuck/const.py
Normal file
14
thefuck/const.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
class _GenConst(object):
|
||||||
|
def __init__(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return u'<const: {}>'.format(self._name)
|
||||||
|
|
||||||
|
|
||||||
|
KEY_UP = _GenConst('↑')
|
||||||
|
KEY_DOWN = _GenConst('↓')
|
||||||
|
KEY_CTRL_C = _GenConst('Ctrl+C')
|
@ -2,27 +2,18 @@ from argparse import ArgumentParser
|
|||||||
from warnings import warn
|
from warnings import warn
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import sys
|
import sys
|
||||||
import colorama
|
|
||||||
from . import logs, types, shells
|
from . import logs, types, shells
|
||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .corrector import get_corrected_commands
|
from .corrector import get_corrected_commands
|
||||||
from .exceptions import EmptyCommand
|
from .exceptions import EmptyCommand
|
||||||
from .utils import get_installation_info
|
from .utils import get_installation_info
|
||||||
from .ui import select_command
|
from .ui import select_command
|
||||||
|
from .system import init_output
|
||||||
|
|
||||||
def init_colorama():
|
|
||||||
if sys.platform == 'win32':
|
|
||||||
# https://github.com/tartley/colorama/issues/32
|
|
||||||
import win_unicode_console
|
|
||||||
|
|
||||||
win_unicode_console.enable()
|
|
||||||
colorama.init()
|
|
||||||
|
|
||||||
|
|
||||||
def fix_command():
|
def fix_command():
|
||||||
"""Fixes previous command. Used when `thefuck` called without arguments."""
|
"""Fixes previous command. Used when `thefuck` called without arguments."""
|
||||||
init_colorama()
|
init_output()
|
||||||
settings.init()
|
settings.init()
|
||||||
with logs.debug_time('Total'):
|
with logs.debug_time('Total'):
|
||||||
logs.debug(u'Run with settings: {}'.format(pformat(settings)))
|
logs.debug(u'Run with settings: {}'.format(pformat(settings)))
|
||||||
@ -60,7 +51,7 @@ def how_to_configure_alias():
|
|||||||
It'll be only visible when user type fuck and when alias isn't configured.
|
It'll be only visible when user type fuck and when alias isn't configured.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
init_colorama()
|
init_output()
|
||||||
settings.init()
|
settings.init()
|
||||||
logs.how_to_configure_alias(shells.how_to_configure())
|
logs.how_to_configure_alias(shells.how_to_configure())
|
||||||
|
|
||||||
|
7
thefuck/system/__init__.py
Normal file
7
thefuck/system/__init__.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
from .win32 import *
|
||||||
|
else:
|
||||||
|
from .unix import *
|
35
thefuck/system/unix.py
Normal file
35
thefuck/system/unix.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import sys
|
||||||
|
import tty
|
||||||
|
import termios
|
||||||
|
import colorama
|
||||||
|
from .. import const
|
||||||
|
|
||||||
|
init_output = colorama.init
|
||||||
|
|
||||||
|
|
||||||
|
def getch():
|
||||||
|
fd = sys.stdin.fileno()
|
||||||
|
old = termios.tcgetattr(fd)
|
||||||
|
try:
|
||||||
|
tty.setraw(fd)
|
||||||
|
return sys.stdin.read(1)
|
||||||
|
finally:
|
||||||
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||||
|
|
||||||
|
|
||||||
|
def get_key():
|
||||||
|
ch = getch()
|
||||||
|
|
||||||
|
if ch == '\x03':
|
||||||
|
return const.KEY_CTRL_C
|
||||||
|
elif ch == '\x1b':
|
||||||
|
next_ch = getch()
|
||||||
|
if next_ch == '[':
|
||||||
|
last_ch = getch()
|
||||||
|
|
||||||
|
if last_ch == 'A':
|
||||||
|
return const.KEY_UP
|
||||||
|
elif last_ch == 'B':
|
||||||
|
return const.KEY_DOWN
|
||||||
|
|
||||||
|
return ch
|
25
thefuck/system/win32.py
Normal file
25
thefuck/system/win32.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import sys
|
||||||
|
import msvcrt
|
||||||
|
import colorama
|
||||||
|
import win_unicode_console
|
||||||
|
from .. import const
|
||||||
|
|
||||||
|
|
||||||
|
def init_output():
|
||||||
|
win_unicode_console.enable()
|
||||||
|
colorama.init()
|
||||||
|
|
||||||
|
|
||||||
|
def get_key():
|
||||||
|
ch = msvcrt.getch()
|
||||||
|
if ch in (b'\x00', b'\xe0'): # arrow or function key prefix?
|
||||||
|
ch = msvcrt.getch() # second call returns the actual key code
|
||||||
|
|
||||||
|
if ch == b'\x03':
|
||||||
|
raise 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)
|
@ -3,38 +3,8 @@
|
|||||||
import sys
|
import sys
|
||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .exceptions import NoRuleMatched
|
from .exceptions import NoRuleMatched
|
||||||
from . import logs
|
from .system import get_key
|
||||||
|
from . import logs, const
|
||||||
try:
|
|
||||||
import msvcrt
|
|
||||||
|
|
||||||
def getch():
|
|
||||||
ch = msvcrt.getch()
|
|
||||||
if ch in (b'\x00', b'\xe0'): # arrow or function key prefix?
|
|
||||||
ch = msvcrt.getch() # second call returns the actual key code
|
|
||||||
|
|
||||||
if ch == b'\x03':
|
|
||||||
raise KeyboardInterrupt
|
|
||||||
if ch == b'H':
|
|
||||||
return 'k'
|
|
||||||
if ch == b'P':
|
|
||||||
return 'j'
|
|
||||||
return ch.decode(sys.stdout.encoding)
|
|
||||||
except ImportError:
|
|
||||||
def getch():
|
|
||||||
import tty
|
|
||||||
import termios
|
|
||||||
|
|
||||||
fd = sys.stdin.fileno()
|
|
||||||
old = termios.tcgetattr(fd)
|
|
||||||
try:
|
|
||||||
tty.setraw(fd)
|
|
||||||
ch = sys.stdin.read(1)
|
|
||||||
if ch == '\x03': # For compatibility with msvcrt.getch
|
|
||||||
raise KeyboardInterrupt
|
|
||||||
return ch
|
|
||||||
finally:
|
|
||||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
|
||||||
|
|
||||||
SELECT = 0
|
SELECT = 0
|
||||||
ABORT = 1
|
ABORT = 1
|
||||||
@ -44,23 +14,17 @@ NEXT = 3
|
|||||||
|
|
||||||
def read_actions():
|
def read_actions():
|
||||||
"""Yields actions for pressed keys."""
|
"""Yields actions for pressed keys."""
|
||||||
buffer = []
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
key = get_key()
|
||||||
ch = getch()
|
|
||||||
except KeyboardInterrupt: # Ctrl+C
|
|
||||||
yield ABORT
|
|
||||||
|
|
||||||
if ch in ('\n', '\r'): # Enter
|
if key in (const.KEY_UP, 'k'):
|
||||||
yield SELECT
|
|
||||||
|
|
||||||
buffer.append(ch)
|
|
||||||
buffer = buffer[-3:]
|
|
||||||
|
|
||||||
if buffer == ['\x1b', '[', 'A'] or ch == 'k': # ↑
|
|
||||||
yield PREVIOUS
|
yield PREVIOUS
|
||||||
elif buffer == ['\x1b', '[', 'B'] or ch == 'j': # ↓
|
elif key in (const.KEY_DOWN, 'j'):
|
||||||
yield NEXT
|
yield NEXT
|
||||||
|
elif key == const.KEY_CTRL_C:
|
||||||
|
yield ABORT
|
||||||
|
elif key in ('\n', '\r'):
|
||||||
|
yield SELECT
|
||||||
|
|
||||||
|
|
||||||
class CommandSelector(object):
|
class CommandSelector(object):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user