1""" 2Key bindings, for scrolling up and down through pages. 3 4This are separate bindings, because GNU readline doesn't have them, but 5they are very useful for navigating through long multiline buffers, like in 6Vi, Emacs, etc... 7""" 8from __future__ import unicode_literals 9 10from six.moves import range 11 12__all__ = [ 13 'scroll_forward', 14 'scroll_backward', 15 'scroll_half_page_up', 16 'scroll_half_page_down', 17 'scroll_one_line_up', 18 'scroll_one_line_down', 19] 20 21 22def scroll_forward(event, half=False): 23 """ 24 Scroll window down. 25 """ 26 w = event.app.layout.current_window 27 b = event.app.current_buffer 28 29 if w and w.render_info: 30 info = w.render_info 31 ui_content = info.ui_content 32 33 # Height to scroll. 34 scroll_height = info.window_height 35 if half: 36 scroll_height //= 2 37 38 # Calculate how many lines is equivalent to that vertical space. 39 y = b.document.cursor_position_row + 1 40 height = 0 41 while y < ui_content.line_count: 42 line_height = info.get_height_for_line(y) 43 44 if height + line_height < scroll_height: 45 height += line_height 46 y += 1 47 else: 48 break 49 50 b.cursor_position = b.document.translate_row_col_to_index(y, 0) 51 52 53def scroll_backward(event, half=False): 54 """ 55 Scroll window up. 56 """ 57 w = event.app.layout.current_window 58 b = event.app.current_buffer 59 60 if w and w.render_info: 61 info = w.render_info 62 63 # Height to scroll. 64 scroll_height = info.window_height 65 if half: 66 scroll_height //= 2 67 68 # Calculate how many lines is equivalent to that vertical space. 69 y = max(0, b.document.cursor_position_row - 1) 70 height = 0 71 while y > 0: 72 line_height = info.get_height_for_line(y) 73 74 if height + line_height < scroll_height: 75 height += line_height 76 y -= 1 77 else: 78 break 79 80 b.cursor_position = b.document.translate_row_col_to_index(y, 0) 81 82 83def scroll_half_page_down(event): 84 """ 85 Same as ControlF, but only scroll half a page. 86 """ 87 scroll_forward(event, half=True) 88 89 90def scroll_half_page_up(event): 91 """ 92 Same as ControlB, but only scroll half a page. 93 """ 94 scroll_backward(event, half=True) 95 96 97def scroll_one_line_down(event): 98 """ 99 scroll_offset += 1 100 """ 101 w = event.app.layout.current_window 102 b = event.app.current_buffer 103 104 if w: 105 # When the cursor is at the top, move to the next line. (Otherwise, only scroll.) 106 if w.render_info: 107 info = w.render_info 108 109 if w.vertical_scroll < info.content_height - info.window_height: 110 if info.cursor_position.y <= info.configured_scroll_offsets.top: 111 b.cursor_position += b.document.get_cursor_down_position() 112 113 w.vertical_scroll += 1 114 115 116def scroll_one_line_up(event): 117 """ 118 scroll_offset -= 1 119 """ 120 w = event.app.layout.current_window 121 b = event.app.current_buffer 122 123 if w: 124 # When the cursor is at the bottom, move to the previous line. (Otherwise, only scroll.) 125 if w.render_info: 126 info = w.render_info 127 128 if w.vertical_scroll > 0: 129 first_line_height = info.get_height_for_line(info.first_visible_line()) 130 131 cursor_up = info.cursor_position.y - (info.window_height - 1 - first_line_height - 132 info.configured_scroll_offsets.bottom) 133 134 # Move cursor up, as many steps as the height of the first line. 135 # TODO: not entirely correct yet, in case of line wrapping and many long lines. 136 for _ in range(max(0, cursor_up)): 137 b.cursor_position += b.document.get_cursor_up_position() 138 139 # Scroll window 140 w.vertical_scroll -= 1 141 142 143def scroll_page_down(event): 144 """ 145 Scroll page down. (Prefer the cursor at the top of the page, after scrolling.) 146 """ 147 w = event.app.layout.current_window 148 b = event.app.current_buffer 149 150 if w and w.render_info: 151 # Scroll down one page. 152 line_index = max(w.render_info.last_visible_line(), w.vertical_scroll + 1) 153 w.vertical_scroll = line_index 154 155 b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) 156 b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True) 157 158 159def scroll_page_up(event): 160 """ 161 Scroll page up. (Prefer the cursor at the bottom of the page, after scrolling.) 162 """ 163 w = event.app.layout.current_window 164 b = event.app.current_buffer 165 166 if w and w.render_info: 167 # Put cursor at the first visible line. (But make sure that the cursor 168 # moves at least one line up.) 169 line_index = max(0, min(w.render_info.first_visible_line(), 170 b.document.cursor_position_row - 1)) 171 172 b.cursor_position = b.document.translate_row_col_to_index(line_index, 0) 173 b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True) 174 175 # Set the scroll offset. We can safely set it to zero; the Window will 176 # make sure that it scrolls at least until the cursor becomes visible. 177 w.vertical_scroll = 0 178