<s> import curses <EOL> __all__ = [ '<STR_LIT>' , '<STR_LIT>' ] <EOL> KEYS_ENTER = ( curses . KEY_ENTER , ord ( '<STR_LIT:\n>' ) , ord ( '<STR_LIT:\r>' ) ) <EOL> KEYS_UP = ( curses . KEY_UP , ord ( '<STR_LIT:k>' ) ) <EOL> KEYS_DOWN = ( curses . KEY_DOWN , ord ( '<STR_LIT>' ) ) <EOL> class Picker ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , options , title = None , indicator = '<STR_LIT:*>' , default_index = <NUM_LIT:0> ) : <EOL> if len ( options ) == <NUM_LIT:0> : <EOL> raise ValueError ( '<STR_LIT>' ) <EOL> self . options = options <EOL> self . title = title <EOL> self . indicator = indicator <EOL> if default_index >= len ( options ) : <EOL> raise ValueError ( '<STR_LIT>' ) <EOL> self . index = default_index <EOL> self . custom_handlers = { } <EOL> def register_custom_handler ( self , key , func ) : <EOL> self . custom_handlers [ key ] = func <EOL> def move_up ( self ) : <EOL> self . index -= <NUM_LIT:1> <EOL> if self . index < <NUM_LIT:0> : <EOL> self . index = len ( self . options ) - <NUM_LIT:1> <EOL> def move_down ( self ) : <EOL> self . index += <NUM_LIT:1> <EOL> if self . index >= len ( self . options ) : <EOL> self . index = <NUM_LIT:0> <EOL> def get_selected ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . options [ self . index ] , self . index <EOL> def get_title_lines ( self ) : <EOL> if self . title : <EOL> return self . title . split ( '<STR_LIT:\n>' ) + [ '<STR_LIT>' ] <EOL> return [ ] <EOL> def get_option_lines ( self ) : <EOL> lines = [ ] <EOL> for index , option in enumerate ( self . options ) : <EOL> if index == self . index : <EOL> prefix = self . indicator <EOL> else : <EOL> prefix = len ( self . indicator ) * '<STR_LIT:U+0020>' <EOL> line = '<STR_LIT>' . format ( prefix , option ) <EOL> lines . append ( line ) <EOL> return lines <EOL> def get_lines ( self ) : <EOL> title_lines = self . get_title_lines ( ) <EOL> option_lines = self . get_option_lines ( ) <EOL> lines = title_lines + option_lines <EOL> current_line = self . index + len ( title_lines ) + <NUM_LIT:1> <EOL> return lines , current_line <EOL> def draw ( self ) : <EOL> """<STR_LIT>""" <EOL> self . screen . clear ( ) <EOL> x , y = <NUM_LIT:1> , <NUM_LIT:1> <EOL> max_y , max_x = self . screen . getmaxyx ( ) <EOL> max_rows = max_y - y <EOL> lines , current_line = self . get_lines ( ) <EOL> scroll_top = getattr ( self , '<STR_LIT>' , <NUM_LIT:0> ) <EOL> if current_line <= scroll_top : <EOL> scroll_top = <NUM_LIT:0> <EOL> elif current_line - scroll_top > max_rows : <EOL> scroll_top = current_line - max_rows <EOL> self . scroll_top = scroll_top <EOL> lines_to_draw = lines [ scroll_top : scroll_top + max_rows ] <EOL> for line in lines_to_draw : <EOL> self . screen . addstr ( y , x , line ) <EOL> y += <NUM_LIT:1> <EOL> self . screen . refresh ( ) <EOL> def run_loop ( self ) : <EOL> while True : <EOL> self . draw ( ) <EOL> c = self . screen . getch ( ) <EOL> if c in KEYS_UP : <EOL> self . move_up ( ) <EOL> elif c in KEYS_DOWN : <EOL> self . move_down ( ) <EOL> elif c in KEYS_ENTER : <EOL> return self . get_selected ( ) <EOL> elif c in self . custom_handlers : <EOL> ret = self . custom_handlers [ c ] ( self ) <EOL> if ret : <EOL> return ret <EOL> def config_curses ( self ) : <EOL> curses . use_default_colors ( ) <EOL> curses . curs_set ( <NUM_LIT:0> ) <EOL> def _start ( self , screen ) : <EOL> self . screen = screen <EOL> self . config_curses ( ) <EOL> return self . run_loop ( ) <EOL> def start ( self ) : <EOL> return curses . wrapper ( self . _start ) <EOL> def pick ( options , title = None , indicator = '<STR_LIT:*>' , default_index = <NUM_LIT:0> ) : <EOL> """<STR_LIT>""" <EOL> picker = Picker ( options , title , indicator , default_index ) <EOL> return picker . start ( ) </s>
