Skip to content

Commit 3d57456

Browse files
committed
During live config, render a scrollbar on demand
1 parent aff0136 commit 3d57456

File tree

1 file changed

+52
-16
lines changed

1 file changed

+52
-16
lines changed

git_delete_merged_branches/_multiselect.py

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
from prompt_toolkit.formatted_text.base import StyleAndTextTuples
1313
from prompt_toolkit.key_binding import KeyBindings
1414
from prompt_toolkit.layout import HSplit, Layout, Window
15-
from prompt_toolkit.layout.containers import VerticalAlign
15+
from prompt_toolkit.layout.containers import Container, VerticalAlign
1616
from prompt_toolkit.layout.controls import BufferControl
1717
from prompt_toolkit.layout.dimension import Dimension
18+
from prompt_toolkit.layout.mouse_handlers import MouseHandlers
1819
from prompt_toolkit.layout.processors import Processor, Transformation, TransformationInput
20+
from prompt_toolkit.layout.screen import Screen, WritePosition
21+
from prompt_toolkit.layout.scrollable_pane import ScrollablePane, ScrollOffsets
1922
from prompt_toolkit.search import SearchState
2023
from prompt_toolkit.widgets import SearchToolbar
2124

@@ -114,6 +117,33 @@ def apply_search(
114117
previous_line_index = current_line_index
115118

116119

120+
class _HeightTrackingScrollablePane(ScrollablePane):
121+
"""
122+
A copy of ``ScrollablePane`` that remembers the latest rendering height.
123+
"""
124+
125+
def __init__(self, content: Container, **kwargs):
126+
super().__init__(content=content, **kwargs)
127+
self.current_height = None
128+
129+
def write_to_screen(
130+
self,
131+
screen: Screen,
132+
mouse_handlers: MouseHandlers,
133+
write_position: WritePosition,
134+
parent_style: str,
135+
erase_bg: bool,
136+
z_index: Optional[int],
137+
) -> None:
138+
self.current_height = write_position.height
139+
super().write_to_screen(screen=screen,
140+
mouse_handlers=mouse_handlers,
141+
write_position=write_position,
142+
parent_style=parent_style,
143+
erase_bg=erase_bg,
144+
z_index=z_index)
145+
146+
117147
class _MultiSelectPrompt:
118148
"""
119149
An interactive multi-select using the terminal, based on Prompt Toolkit.
@@ -153,14 +183,15 @@ def __init__(self,
153183
self._header_lines: [_MultiSelectPrompt.HeaderLine] = []
154184
self._footer_lines: [_MultiSelectPrompt.PlainLine] = []
155185

156-
self._item_selection_window: Optional[Window] = None
186+
self._item_selection_pane: Optional[_HeightTrackingScrollablePane] = None
157187
self._buffer: Optional[Buffer] = None
158188
self._document: Optional[Document] = None
159189
self._accepted_selection: List[Any] = None
160190

161191
def _move_cursor_one_page_vertically(self, upwards: bool):
162-
render_cursor_line = self._item_selection_window.render_info.cursor_position.y
163-
page_height_in_lines = self._item_selection_window.render_info.window_height
192+
render_cursor_line = (self._item_selection_pane.content.render_info.cursor_position.y
193+
- self._item_selection_pane.vertical_scroll)
194+
page_height_in_lines = self._item_selection_pane.current_height
164195

165196
if upwards and render_cursor_line > 0:
166197
new_line_index = self.get_cursor_line() - render_cursor_line
@@ -279,7 +310,7 @@ def _create_text_display_window_for(self, lines: List[_LineBase]) -> Window:
279310
wrap_lines=True,
280311
height=Dimension(min=len(lines), max=len(lines)))
281312

282-
def _create_layout(self) -> Tuple[Layout, Window]:
313+
def _create_layout(self) -> Tuple[Layout, _HeightTrackingScrollablePane]:
283314
header = self._create_text_display_window_for(self._header_lines)
284315
footer = self._create_text_display_window_for(self._footer_lines)
285316

@@ -288,26 +319,31 @@ def _create_layout(self) -> Tuple[Layout, Window]:
288319
input_processors=[_ItemRenderProcessor(prompt=self)],
289320
preview_search=True,
290321
search_buffer_control=search.control)
291-
window_height = Dimension(min=1,
292-
max=self._document.line_count,
293-
preferred=self._document.line_count)
294-
item_selection_window = Window(buffer_control,
295-
always_hide_cursor=True,
296-
wrap_lines=True,
297-
height=window_height)
298-
item_selection_window_plus_search = HSplit([item_selection_window, search])
299-
hsplit = HSplit([header, item_selection_window_plus_search, footer],
322+
item_selection_window = Window(buffer_control, always_hide_cursor=True, wrap_lines=True)
323+
324+
pane_scroll_offsets = ScrollOffsets(top=0, bottom=0)
325+
pane_height = Dimension(min=1,
326+
max=self._document.line_count,
327+
preferred=self._document.line_count)
328+
item_selection_pane = _HeightTrackingScrollablePane(item_selection_window,
329+
height=pane_height,
330+
scroll_offsets=pane_scroll_offsets)
331+
item_selection_pane.show_scrollbar = lambda: (item_selection_pane.current_height or 0
332+
) < self._document.line_count
333+
334+
item_selection_pane_plus_search = HSplit([item_selection_pane, search])
335+
hsplit = HSplit([header, item_selection_pane_plus_search, footer],
300336
padding=1,
301337
align=VerticalAlign.TOP)
302-
return Layout(hsplit, focused_element=item_selection_window), item_selection_window
338+
return Layout(hsplit, focused_element=item_selection_pane), item_selection_pane
303339

304340
def _collect_selected_values(self):
305341
return [item.value for item in self.item_lines if item.selected]
306342

307343
def get_selected_values(self) -> List[Any]:
308344
self._document = Document(text='\n'.join(line.text for line in self.item_lines))
309345
self._buffer = _LineJumpingBuffer(read_only=True, document=self._document)
310-
layout, self._item_selection_window = self._create_layout()
346+
layout, self._item_selection_pane = self._create_layout()
311347
app = Application(key_bindings=self._create_key_bindings(), layout=layout)
312348

313349
self._move_cursor_to_line(self._initial_cursor_item_index)

0 commit comments

Comments
 (0)