mirror of
https://github.com/nvbn/thefuck.git
synced 2025-02-20 20:09:07 +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 thefuck import ui
|
||||
from thefuck.types import CorrectedCommand
|
||||
from thefuck import const
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_getch(monkeypatch):
|
||||
def patch_get_key(monkeypatch):
|
||||
def patch(vals):
|
||||
def getch():
|
||||
for val in vals:
|
||||
if val == KeyboardInterrupt:
|
||||
raise val
|
||||
else:
|
||||
yield val
|
||||
|
||||
getch_gen = getch()
|
||||
monkeypatch.setattr('thefuck.ui.getch', lambda: next(getch_gen))
|
||||
vals = iter(vals)
|
||||
monkeypatch.setattr('thefuck.ui.get_key', lambda: next(vals))
|
||||
|
||||
return patch
|
||||
|
||||
|
||||
def test_read_actions(patch_getch):
|
||||
patch_getch([ # Enter:
|
||||
'\n',
|
||||
# Enter:
|
||||
'\r',
|
||||
# Ignored:
|
||||
'x', 'y',
|
||||
# Up:
|
||||
'\x1b', '[', 'A',
|
||||
# Down:
|
||||
'\x1b', '[', 'B',
|
||||
# Ctrl+C:
|
||||
KeyboardInterrupt], )
|
||||
def test_read_actions(patch_get_key):
|
||||
patch_get_key([
|
||||
# Enter:
|
||||
'\n',
|
||||
# Enter:
|
||||
'\r',
|
||||
# Ignored:
|
||||
'x', 'y',
|
||||
# Up:
|
||||
const.KEY_UP,
|
||||
# Down:
|
||||
const.KEY_DOWN,
|
||||
# Ctrl+C:
|
||||
const.KEY_CTRL_C])
|
||||
assert list(islice(ui.read_actions(), 5)) \
|
||||
== [ui.SELECT, ui.SELECT, ui.PREVIOUS, ui.NEXT, ui.ABORT]
|
||||
|
||||
@ -80,25 +75,25 @@ class TestSelectCommand(object):
|
||||
== commands_with_side_effect[0]
|
||||
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
|
||||
|
||||
def test_with_confirmation(self, capsys, patch_getch, commands):
|
||||
patch_getch(['\n'])
|
||||
def test_with_confirmation(self, capsys, patch_get_key, commands):
|
||||
patch_get_key(['\n'])
|
||||
assert ui.select_command(iter(commands)) == commands[0]
|
||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
|
||||
|
||||
def test_with_confirmation_abort(self, capsys, patch_getch, commands):
|
||||
patch_getch([KeyboardInterrupt])
|
||||
def test_with_confirmation_abort(self, capsys, patch_get_key, commands):
|
||||
patch_get_key([const.KEY_CTRL_C])
|
||||
assert ui.select_command(iter(commands)) is None
|
||||
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):
|
||||
patch_getch(['\n'])
|
||||
assert ui.select_command(iter(commands_with_side_effect))\
|
||||
patch_get_key(['\n'])
|
||||
assert ui.select_command(iter(commands_with_side_effect)) \
|
||||
== commands_with_side_effect[0]
|
||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
|
||||
|
||||
def test_with_confirmation_select_second(self, capsys, patch_getch, commands):
|
||||
patch_getch(['\x1b', '[', 'B', '\n'])
|
||||
def test_with_confirmation_select_second(self, capsys, patch_get_key, commands):
|
||||
patch_get_key([const.KEY_DOWN, '\n'])
|
||||
assert ui.select_command(iter(commands)) == commands[1]
|
||||
assert capsys.readouterr() == (
|
||||
'', 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 pprint import pformat
|
||||
import sys
|
||||
import colorama
|
||||
from . import logs, types, shells
|
||||
from .conf import settings
|
||||
from .corrector import get_corrected_commands
|
||||
from .exceptions import EmptyCommand
|
||||
from .utils import get_installation_info
|
||||
from .ui import select_command
|
||||
|
||||
|
||||
def init_colorama():
|
||||
if sys.platform == 'win32':
|
||||
# https://github.com/tartley/colorama/issues/32
|
||||
import win_unicode_console
|
||||
|
||||
win_unicode_console.enable()
|
||||
colorama.init()
|
||||
from .system import init_output
|
||||
|
||||
|
||||
def fix_command():
|
||||
"""Fixes previous command. Used when `thefuck` called without arguments."""
|
||||
init_colorama()
|
||||
init_output()
|
||||
settings.init()
|
||||
with logs.debug_time('Total'):
|
||||
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.
|
||||
|
||||
"""
|
||||
init_colorama()
|
||||
init_output()
|
||||
settings.init()
|
||||
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
|
||||
from .conf import settings
|
||||
from .exceptions import NoRuleMatched
|
||||
from . import logs
|
||||
|
||||
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)
|
||||
from .system import get_key
|
||||
from . import logs, const
|
||||
|
||||
SELECT = 0
|
||||
ABORT = 1
|
||||
@ -44,23 +14,17 @@ NEXT = 3
|
||||
|
||||
def read_actions():
|
||||
"""Yields actions for pressed keys."""
|
||||
buffer = []
|
||||
while True:
|
||||
try:
|
||||
ch = getch()
|
||||
except KeyboardInterrupt: # Ctrl+C
|
||||
yield ABORT
|
||||
key = get_key()
|
||||
|
||||
if ch in ('\n', '\r'): # Enter
|
||||
yield SELECT
|
||||
|
||||
buffer.append(ch)
|
||||
buffer = buffer[-3:]
|
||||
|
||||
if buffer == ['\x1b', '[', 'A'] or ch == 'k': # ↑
|
||||
if key in (const.KEY_UP, 'k'):
|
||||
yield PREVIOUS
|
||||
elif buffer == ['\x1b', '[', 'B'] or ch == 'j': # ↓
|
||||
elif key in (const.KEY_DOWN, 'j'):
|
||||
yield NEXT
|
||||
elif key == const.KEY_CTRL_C:
|
||||
yield ABORT
|
||||
elif key in ('\n', '\r'):
|
||||
yield SELECT
|
||||
|
||||
|
||||
class CommandSelector(object):
|
||||
|
Loading…
x
Reference in New Issue
Block a user