Implement page up and page down
This commit is contained in:
29
babi.py
29
babi.py
@@ -24,6 +24,13 @@ class Margin(NamedTuple):
|
||||
def body_lines(self) -> int:
|
||||
return curses.LINES - self.header - self.footer
|
||||
|
||||
@property
|
||||
def page_size(self) -> int:
|
||||
if self.body_lines <= 2:
|
||||
return 1
|
||||
else:
|
||||
return self.body_lines - 2
|
||||
|
||||
@classmethod
|
||||
def from_screen(cls, screen: '_curses._CursesWindow') -> 'Margin':
|
||||
if curses.LINES == 1:
|
||||
@@ -95,6 +102,22 @@ class Position:
|
||||
def end(self, margin: Margin, lines: List[str]) -> None:
|
||||
self.x = self.x_hint = len(lines[self.cursor_line])
|
||||
|
||||
def page_up(self, margin: Margin, lines: List[str]) -> None:
|
||||
if self.cursor_line < margin.body_lines:
|
||||
self.cursor_line = self.file_line = 0
|
||||
else:
|
||||
pos = self.file_line - margin.page_size
|
||||
self.cursor_line = self.file_line = pos
|
||||
self._set_x_after_vertical_movement(lines)
|
||||
|
||||
def page_down(self, margin: Margin, lines: List[str]) -> None:
|
||||
if self.file_line + margin.body_lines >= len(lines):
|
||||
self.cursor_line = len(lines) - 1
|
||||
else:
|
||||
pos = self.file_line + margin.page_size
|
||||
self.cursor_line = self.file_line = pos
|
||||
self._set_x_after_vertical_movement(lines)
|
||||
|
||||
DISPATCH = {
|
||||
curses.KEY_DOWN: down,
|
||||
curses.KEY_UP: up,
|
||||
@@ -102,6 +125,8 @@ class Position:
|
||||
curses.KEY_RIGHT: right,
|
||||
curses.KEY_HOME: home,
|
||||
curses.KEY_END: end,
|
||||
curses.KEY_PPAGE: page_up,
|
||||
curses.KEY_NPAGE: page_down,
|
||||
}
|
||||
|
||||
def dispatch(self, key: int, margin: Margin, lines: List[str]) -> None:
|
||||
@@ -345,6 +370,10 @@ def c_main(stdscr: '_curses._CursesWindow', args: argparse.Namespace) -> None:
|
||||
pos.home(margin, lines)
|
||||
elif keyname == b'^E':
|
||||
pos.end(margin, lines)
|
||||
elif keyname == b'^Y':
|
||||
pos.page_up(margin, lines)
|
||||
elif keyname == b'^V':
|
||||
pos.page_down(margin, lines)
|
||||
elif keyname == b'^X':
|
||||
return
|
||||
elif keyname == b'^Z':
|
||||
|
||||
@@ -118,6 +118,13 @@ class PrintsErrorRunner(Runner):
|
||||
f'Last cursor position: {pos}',
|
||||
)
|
||||
|
||||
def get_screen_line(self, n):
|
||||
return self.screenshot().splitlines()[n]
|
||||
|
||||
def get_cursor_line(self):
|
||||
_, y = self._get_cursor_position()
|
||||
return self.get_screen_line(y)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def resize(self, width, height):
|
||||
current_w, current_h = self.get_pane_size()
|
||||
@@ -234,7 +241,7 @@ def test_status_clearing_behaviour():
|
||||
|
||||
def test_reacts_to_resize():
|
||||
with run() as h, and_exit(h):
|
||||
first_line = h.screenshot().splitlines()[0]
|
||||
first_line = h.get_screen_line(0)
|
||||
with h.resize(40, 20):
|
||||
# the first line should be different after resize
|
||||
h.await_text_missing(first_line)
|
||||
@@ -304,6 +311,56 @@ def test_arrow_key_movement(tmpdir):
|
||||
h.await_cursor_position(x=19, y=3)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
('page_up', 'page_down'),
|
||||
(('PageUp', 'PageDown'), ('^Y', '^V')),
|
||||
)
|
||||
def test_page_up_and_page_down(tmpdir, page_up, page_down):
|
||||
f = tmpdir.join('f')
|
||||
f.write('\n'.join(f'line_{i}' for i in range(10)))
|
||||
|
||||
with run(str(f), height=10) as h, and_exit(h):
|
||||
h.press('Down')
|
||||
h.press('Down')
|
||||
h.press(page_up)
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
|
||||
h.press(page_down)
|
||||
h.await_text('line_8')
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
assert h.get_cursor_line() == 'line_6'
|
||||
|
||||
h.press(page_up)
|
||||
h.await_text_missing('line_8')
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
assert h.get_cursor_line() == 'line_0'
|
||||
|
||||
h.press(page_down)
|
||||
h.press(page_down)
|
||||
h.await_cursor_position(x=0, y=5)
|
||||
assert h.get_cursor_line() == ''
|
||||
h.press('Up')
|
||||
h.await_cursor_position(x=0, y=4)
|
||||
assert h.get_cursor_line() == 'line_9'
|
||||
|
||||
|
||||
def test_page_up_page_down_size_small_window(tmpdir):
|
||||
f = tmpdir.join('f')
|
||||
f.write('\n'.join(f'line_{i}' for i in range(10)))
|
||||
|
||||
with run(str(f), height=4) as h, and_exit(h):
|
||||
h.press('PageDown')
|
||||
h.await_text('line_2')
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
assert h.get_cursor_line() == 'line_1'
|
||||
|
||||
h.press('Down')
|
||||
h.press('PageUp')
|
||||
h.await_text_missing('line_2')
|
||||
h.await_cursor_position(x=0, y=1)
|
||||
assert h.get_cursor_line() == 'line_0'
|
||||
|
||||
|
||||
def test_scrolling_arrow_key_movement(tmpdir):
|
||||
f = tmpdir.join('f')
|
||||
f.write('\n'.join(f'line_{i}' for i in range(10)))
|
||||
@@ -319,7 +376,7 @@ def test_scrolling_arrow_key_movement(tmpdir):
|
||||
h.press('Down')
|
||||
h.await_text('line_8')
|
||||
h.await_cursor_position(x=0, y=4)
|
||||
assert h.screenshot().splitlines()[4] == 'line_8'
|
||||
assert h.get_cursor_line() == 'line_8'
|
||||
# we should not have scrolled after 3 up presses
|
||||
for _ in range(3):
|
||||
h.press('Up')
|
||||
@@ -382,7 +439,7 @@ def test_resize_scrolls_up(tmpdir):
|
||||
h.await_text_missing('line_0')
|
||||
h.await_cursor_position(x=0, y=3)
|
||||
# make sure we're still on the same line
|
||||
assert h.screenshot().splitlines()[3] == 'line_7'
|
||||
assert h.get_cursor_line() == 'line_7'
|
||||
|
||||
|
||||
def test_resize_scroll_does_not_go_negative(tmpdir):
|
||||
@@ -401,7 +458,7 @@ def test_resize_scroll_does_not_go_negative(tmpdir):
|
||||
for _ in range(2):
|
||||
h.press('Up')
|
||||
|
||||
assert h.screenshot().splitlines()[1] == 'line_0'
|
||||
assert h.get_screen_line(1) == 'line_0'
|
||||
|
||||
|
||||
def test_very_narrow_window_status():
|
||||
|
||||
Reference in New Issue
Block a user