1#!/usr/local/bin/python3.8 2# vim:fileencoding=utf-8 3# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> 4 5 6from typing import TYPE_CHECKING, Optional, Tuple, Union 7 8from .base import ( 9 MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, 10 PayloadType, RCOptions, RemoteCommand, ResponseType, Window 11) 12 13if TYPE_CHECKING: 14 from kitty.cli_stub import ScrollWindowRCOptions as CLIOptions 15 16 17class ScrollWindow(RemoteCommand): 18 19 ''' 20 amount+: The amount to scroll, a two item list with the first item being \ 21 either a number or the keywords, start and end. \ 22 And the second item being either 'p' for pages or 'l' for lines or 'u' 23 for unscrolling by lines. 24 match: The window to scroll 25 ''' 26 27 short_desc = 'Scroll the specified window' 28 desc = ( 29 'Scroll the specified window, if no window is specified, scroll the window this command is run inside.' 30 ' SCROLL_AMOUNT can be either the keywords :code:`start` or :code:`end` or an' 31 ' argument of the form <number>[unit][+-]. For example, 30 will scroll down 30 lines and 2p- will' 32 ' scroll up 2 pages. 3u will *unscroll* by 3 lines, which means that 3 lines will move from the' 33 ' scrollback buffer onto the top of the screen.' 34 ) 35 argspec = 'SCROLL_AMOUNT' 36 options_spec = MATCH_WINDOW_OPTION 37 38 def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: 39 amt = args[0] 40 amount: Tuple[Union[str, int], Optional[str]] = (amt, None) 41 if amt not in ('start', 'end'): 42 pages = 'p' in amt 43 unscroll = 'u' in amt 44 amt = amt.replace('p', '') 45 mult = -1 if amt.endswith('-') and not unscroll else 1 46 q = int(amt.replace('-', '')) 47 amount = q * mult, 'p' if pages else ('u' if unscroll else 'l') 48 49 return {'match': opts.match, 'amount': amount} 50 51 def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType: 52 windows = [window or boss.active_window] 53 match = payload_get('match') 54 amt = payload_get('amount') 55 if match: 56 windows = list(boss.match_windows(match)) 57 if not windows: 58 raise MatchError(match) 59 for window in windows: 60 if window: 61 if amt[0] in ('start', 'end'): 62 getattr(window, {'start': 'scroll_home'}.get(amt[0], 'scroll_end'))() 63 else: 64 amt, unit = amt 65 if unit == 'u': 66 window.screen.reverse_scroll(abs(amt), True) 67 else: 68 unit = 'page' if unit == 'p' else 'line' 69 direction = 'up' if amt < 0 else 'down' 70 func = getattr(window, 'scroll_{}_{}'.format(unit, direction)) 71 for i in range(abs(amt)): 72 func() 73 74 75scroll_window = ScrollWindow() 76