ai-bot-test
/
venv
/lib
/python3.11
/site-packages
/prompt_toolkit
/key_binding
/bindings
/scroll.py
""" | |
Key bindings, for scrolling up and down through pages. | |
This are separate bindings, because GNU readline doesn't have them, but | |
they are very useful for navigating through long multiline buffers, like in | |
Vi, Emacs, etc... | |
""" | |
from __future__ import annotations | |
from prompt_toolkit.key_binding.key_processor import KeyPressEvent | |
__all__ = [ | |
"scroll_forward", | |
"scroll_backward", | |
"scroll_half_page_up", | |
"scroll_half_page_down", | |
"scroll_one_line_up", | |
"scroll_one_line_down", | |
] | |
E = KeyPressEvent | |
def scroll_forward(event: E, half: bool = False) -> None: | |
""" | |
Scroll window down. | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w and w.render_info: | |
info = w.render_info | |
ui_content = info.ui_content | |
# Height to scroll. | |
scroll_height = info.window_height | |
if half: | |
scroll_height //= 2 | |
# Calculate how many lines is equivalent to that vertical space. | |
y = b.document.cursor_position_row + 1 | |
height = 0 | |
while y < ui_content.line_count: | |
line_height = info.get_height_for_line(y) | |
if height + line_height < scroll_height: | |
height += line_height | |
y += 1 | |
else: | |
break | |
b.cursor_position = b.document.translate_row_col_to_index(y, 0) | |
def scroll_backward(event: E, half: bool = False) -> None: | |
""" | |
Scroll window up. | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w and w.render_info: | |
info = w.render_info | |
# Height to scroll. | |
scroll_height = info.window_height | |
if half: | |
scroll_height //= 2 | |
# Calculate how many lines is equivalent to that vertical space. | |
y = max(0, b.document.cursor_position_row - 1) | |
height = 0 | |
while y > 0: | |
line_height = info.get_height_for_line(y) | |
if height + line_height < scroll_height: | |
height += line_height | |
y -= 1 | |
else: | |
break | |
b.cursor_position = b.document.translate_row_col_to_index(y, 0) | |
def scroll_half_page_down(event: E) -> None: | |
""" | |
Same as ControlF, but only scroll half a page. | |
""" | |
scroll_forward(event, half=True) | |
def scroll_half_page_up(event: E) -> None: | |
""" | |
Same as ControlB, but only scroll half a page. | |
""" | |
scroll_backward(event, half=True) | |
def scroll_one_line_down(event: E) -> None: | |
""" | |
scroll_offset += 1 | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w: | |
# When the cursor is at the top, move to the next line. (Otherwise, only scroll.) | |
if w.render_info: | |
info = w.render_info | |
if w.vertical_scroll < info.content_height - info.window_height: | |
if info.cursor_position.y <= info.configured_scroll_offsets.top: | |
b.cursor_position += b.document.get_cursor_down_position() | |
w.vertical_scroll += 1 | |
def scroll_one_line_up(event: E) -> None: | |
""" | |
scroll_offset -= 1 | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w: | |
# When the cursor is at the bottom, move to the previous line. (Otherwise, only scroll.) | |
if w.render_info: | |
info = w.render_info | |
if w.vertical_scroll > 0: | |
first_line_height = info.get_height_for_line(info.first_visible_line()) | |
cursor_up = info.cursor_position.y - ( | |
info.window_height | |
- 1 | |
- first_line_height | |
- info.configured_scroll_offsets.bottom | |
) | |
# Move cursor up, as many steps as the height of the first line. | |
# TODO: not entirely correct yet, in case of line wrapping and many long lines. | |
for _ in range(max(0, cursor_up)): | |
b.cursor_position += b.document.get_cursor_up_position() | |
# Scroll window | |
w.vertical_scroll -= 1 | |
def scroll_page_down(event: E) -> None: | |
""" | |
Scroll page down. (Prefer the cursor at the top of the page, after scrolling.) | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w and w.render_info: | |
# Scroll down one page. | |
line_index = max(w.render_info.last_visible_line(), w.vertical_scroll + 1) | |
w.vertical_scroll = line_index | |
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) | |
b.cursor_position += b.document.get_start_of_line_position( | |
after_whitespace=True | |
) | |
def scroll_page_up(event: E) -> None: | |
""" | |
Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.) | |
""" | |
w = event.app.layout.current_window | |
b = event.app.current_buffer | |
if w and w.render_info: | |
# Put cursor at the first visible line. (But make sure that the cursor | |
# moves at least one line up.) | |
line_index = max( | |
0, | |
min(w.render_info.first_visible_line(), b.document.cursor_position_row - 1), | |
) | |
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) | |
b.cursor_position += b.document.get_start_of_line_position( | |
after_whitespace=True | |
) | |
# Set the scroll offset. We can safely set it to zero; the Window will | |
# make sure that it scrolls at least until the cursor becomes visible. | |
w.vertical_scroll = 0 | |