Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c184468843 | ||
|
|
c5653976c7 | ||
|
|
d81bb12ff7 | ||
|
|
afe461372e | ||
|
|
b486047e90 | ||
|
|
f3401a46c7 | ||
|
|
fbf5fc6ba2 | ||
|
|
60b0a77f05 | ||
|
|
28a73a1a8c | ||
|
|
432640eaf1 | ||
|
|
71e67a6349 | ||
|
|
a5caa9d746 | ||
|
|
599dfa1d0e |
@@ -11,16 +11,16 @@ repos:
|
||||
- id: name-tests-test
|
||||
- id: requirements-txt-fixer
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.7.9
|
||||
rev: 3.8.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [flake8-typing-imports==1.7.0]
|
||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||
rev: v1.5
|
||||
rev: v1.5.2
|
||||
hooks:
|
||||
- id: autopep8
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v2.1.0
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: [--py3-plus]
|
||||
@@ -30,12 +30,12 @@ repos:
|
||||
- id: add-trailing-comma
|
||||
args: [--py36-plus]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.1.0
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py36-plus]
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.7.0
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
|
||||
@@ -45,7 +45,7 @@ these are all of the current key bindings in babi
|
||||
- <kbd>tab</kbd> / <kbd>shift-tab</kbd>: indent or dedent current line (or
|
||||
selection)
|
||||
- <kbd>^K</kbd> / <kbd>^U</kbd>: cut and uncut the current line (or selection)
|
||||
- <kbd>M-u</kbd> / <kbd>M-U</kbd>: undo / redo
|
||||
- <kbd>M-u</kbd> / <kbd>M-U</kbd> or <kbd>M-e</kbd>: undo / redo
|
||||
- <kbd>^W</kbd>: search
|
||||
- <kbd>^\\</kbd>: search and replace
|
||||
- <kbd>^C</kbd>: show the current position in the file
|
||||
|
||||
12
babi/file.py
12
babi/file.py
@@ -641,9 +641,9 @@ class File:
|
||||
self.buf[self.buf.y] += self.buf.pop(self.buf.y + 1)
|
||||
self.buf.restore_eof_invariant()
|
||||
|
||||
def _sort(self, margin: Margin, s_y: int, e_y: int) -> None:
|
||||
def _sort(self, margin: Margin, s_y: int, e_y: int, reverse: bool) -> None:
|
||||
# self.buf intentionally does not support slicing so we use islice
|
||||
lines = sorted(itertools.islice(self.buf, s_y, e_y))
|
||||
lines = sorted(itertools.islice(self.buf, s_y, e_y), reverse=reverse)
|
||||
for i, line in zip(range(s_y, e_y), lines):
|
||||
self.buf[i] = line
|
||||
|
||||
@@ -652,17 +652,17 @@ class File:
|
||||
self.buf.scroll_screen_if_needed(margin)
|
||||
|
||||
@edit_action('sort', final=True)
|
||||
def sort(self, margin: Margin) -> None:
|
||||
self._sort(margin, 0, len(self.buf) - 1)
|
||||
def sort(self, margin: Margin, reverse: bool = False) -> None:
|
||||
self._sort(margin, 0, len(self.buf) - 1, reverse=reverse)
|
||||
|
||||
@edit_action('sort selection', final=True)
|
||||
@clear_selection
|
||||
def sort_selection(self, margin: Margin) -> None:
|
||||
def sort_selection(self, margin: Margin, reverse: bool = False) -> None:
|
||||
(s_y, _), (e_y, _) = self.selection.get()
|
||||
e_y = min(e_y + 1, len(self.buf) - 1)
|
||||
if self.buf[e_y - 1] == '':
|
||||
e_y -= 1
|
||||
self._sort(margin, s_y, e_y)
|
||||
self._sort(margin, s_y, e_y, reverse=reverse)
|
||||
|
||||
DISPATCH = {
|
||||
# movement
|
||||
|
||||
@@ -85,6 +85,7 @@ KEYNAME_REWRITE = {
|
||||
b'CTL_END': b'kEND5',
|
||||
b'ALT_RIGHT': b'kRIT3',
|
||||
b'ALT_LEFT': b'kLFT3',
|
||||
b'ALT_E': b'M-e',
|
||||
# windows-curses: idk why these are different
|
||||
b'KEY_SUP': b'KEY_SR',
|
||||
b'KEY_SDOWN': b'KEY_SF',
|
||||
@@ -92,6 +93,7 @@ KEYNAME_REWRITE = {
|
||||
b'^?': b'KEY_BACKSPACE',
|
||||
# linux, perhaps others
|
||||
b'^H': b'KEY_BACKSPACE', # ^Backspace on my keyboard
|
||||
b'PADENTER': b'^M', # Enter on numpad
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +226,10 @@ class Screen:
|
||||
if self._buffered_input is not None:
|
||||
wch, self._buffered_input = self._buffered_input, None
|
||||
else:
|
||||
wch = self.stdscr.get_wch()
|
||||
try:
|
||||
wch = self.stdscr.get_wch()
|
||||
except curses.error: # pragma: no cover (macos bug?)
|
||||
wch = self.stdscr.get_wch()
|
||||
if isinstance(wch, str) and wch == '\x1b':
|
||||
wch = self._get_sequence(wch)
|
||||
if len(wch) == 2:
|
||||
@@ -431,6 +436,12 @@ class Screen:
|
||||
else:
|
||||
self.file.sort(self.margin)
|
||||
self.status.update('sorted!')
|
||||
elif response == ':sort!':
|
||||
if self.file.selection.start:
|
||||
self.file.sort_selection(self.margin, reverse=True)
|
||||
else:
|
||||
self.file.sort(self.margin, reverse=True)
|
||||
self.status.update('sorted!')
|
||||
elif response is not PromptResult.CANCELLED:
|
||||
self.status.update(f'invalid command: {response}')
|
||||
return None
|
||||
@@ -516,10 +527,13 @@ class Screen:
|
||||
return EditResult.EXIT
|
||||
|
||||
def background(self) -> None:
|
||||
curses.endwin()
|
||||
os.kill(os.getpid(), signal.SIGSTOP)
|
||||
self.stdscr = _init_screen()
|
||||
self.resize()
|
||||
if sys.platform == 'win32': # pragma: win32 cover
|
||||
self.status.update('cannot run babi in background on Windows')
|
||||
else: # pragma: win32 no cover
|
||||
curses.endwin()
|
||||
os.kill(os.getpid(), signal.SIGSTOP)
|
||||
self.stdscr = _init_screen()
|
||||
self.resize()
|
||||
|
||||
DISPATCH = {
|
||||
b'KEY_RESIZE': resize,
|
||||
@@ -529,6 +543,7 @@ class Screen:
|
||||
b'^U': uncut,
|
||||
b'M-u': undo,
|
||||
b'M-U': redo,
|
||||
b'M-e': redo,
|
||||
b'^W': search,
|
||||
b'^\\': replace,
|
||||
b'^[': command,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = babi
|
||||
version = 0.0.8
|
||||
version = 0.0.10
|
||||
description = a text editor
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
|
||||
@@ -133,7 +133,7 @@ def test_save_via_ctrl_o(run, tmpdir):
|
||||
with run(str(f)) as h, and_exit(h):
|
||||
h.press('hello world')
|
||||
h.press('^O')
|
||||
h.await_text(f'enter filename: ')
|
||||
h.await_text('enter filename: ')
|
||||
h.press('Enter')
|
||||
h.await_text('saved! (1 line written)')
|
||||
assert f.read() == 'hello world\n'
|
||||
@@ -237,7 +237,7 @@ def test_vim_save_on_exit(run, tmpdir):
|
||||
h.press_and_enter(':q')
|
||||
h.await_text('file is modified - save [yes, no]?')
|
||||
h.press('y')
|
||||
h.await_text(f'enter filename: ')
|
||||
h.await_text('enter filename: ')
|
||||
h.press('Enter')
|
||||
h.await_exit()
|
||||
|
||||
|
||||
@@ -21,6 +21,16 @@ def test_sort_entire_file(run, unsorted):
|
||||
assert unsorted.read() == 'a\nb\nc\nd\n'
|
||||
|
||||
|
||||
def test_reverse_sort_entire_file(run, unsorted):
|
||||
with run(str(unsorted)) as h, and_exit(h):
|
||||
trigger_command_mode(h)
|
||||
h.press_and_enter(':sort!')
|
||||
h.await_text('sorted!')
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
h.press('^S')
|
||||
assert unsorted.read() == 'd\nc\nb\na\n'
|
||||
|
||||
|
||||
def test_sort_selection(run, unsorted):
|
||||
with run(str(unsorted)) as h, and_exit(h):
|
||||
h.press('S-Down')
|
||||
@@ -32,6 +42,18 @@ def test_sort_selection(run, unsorted):
|
||||
assert unsorted.read() == 'b\nd\nc\na\n'
|
||||
|
||||
|
||||
def test_reverse_sort_selection(run, unsorted):
|
||||
with run(str(unsorted)) as h, and_exit(h):
|
||||
h.press('Down')
|
||||
h.press('S-Down')
|
||||
trigger_command_mode(h)
|
||||
h.press_and_enter(':sort!')
|
||||
h.await_text('sorted!')
|
||||
h.await_cursor_position(x=0, y=2)
|
||||
h.press('^S')
|
||||
assert unsorted.read() == 'd\nc\nb\na\n'
|
||||
|
||||
|
||||
def test_sort_selection_does_not_include_eof(run, unsorted):
|
||||
with run(str(unsorted)) as h, and_exit(h):
|
||||
for _ in range(5):
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import pytest
|
||||
|
||||
from testing.runner import and_exit
|
||||
|
||||
|
||||
@@ -9,7 +11,8 @@ def test_nothing_to_undo_redo(run):
|
||||
h.await_text('nothing to redo!')
|
||||
|
||||
|
||||
def test_undo_redo(run):
|
||||
@pytest.mark.parametrize('r', ('M-U', 'M-e'))
|
||||
def test_undo_redo(run, r):
|
||||
with run() as h, and_exit(h):
|
||||
h.press('hello')
|
||||
h.await_text('hello')
|
||||
@@ -17,7 +20,7 @@ def test_undo_redo(run):
|
||||
h.await_text('undo: text')
|
||||
h.await_text_missing('hello')
|
||||
h.await_text_missing(' *')
|
||||
h.press('M-U')
|
||||
h.press(r)
|
||||
h.await_text('redo: text')
|
||||
h.await_text('hello')
|
||||
h.await_text(' *')
|
||||
|
||||
Reference in New Issue
Block a user