def main(): """ x/84 script launch point """ term, session = getterminal(), getsession() session.activity = u'Chatting on IRC' session.flush_event('irc') # move to bottom of screen, reset attribute echo(term.pos(term.height) + term.normal) # create a new, empty screen echo(u'\r\n' * (term.height + 1)) echo(term.home + term.clear) # set font if SYNCTERM_FONT and term.kind.startswith('ansi'): echo(syncterm_setfont(SYNCTERM_FONT)) try: client, scrollback = establish_connection(term, session) except EOFError: # connection failed, return clean_up(term) # ignore "not in view" warning for AnsiWindow with warnings.catch_warnings(): warnings.simplefilter("ignore") editor = ScrollingEditor( width=term.width + 1, xloc=-1, yloc=term.height, colors={'highlight': getattr(term, COLOR_INPUTBAR)}, max_length=MAX_INPUT ) refresh_event(term, scrollback, editor) while True: client.reactor.process_once() event, data = session.read_events( ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1) if event == 'refresh': refresh_event(term, scrollback, editor) continue elif event == 'irc': irc_event(term, data, scrollback, editor) elif event == 'input': session.buffer_input(data, pushback=True) if not input_event(term, client, editor): break elif event == 'irc-quit': time.sleep(0.5) break client.connection.disconnect() clean_up(term)
def get_inputbar(pager): """ Return ScrollingEditor for use as inputbar. """ from x84.bbs import getterminal, ScrollingEditor term = getterminal() width = pager.visible_width - 2 yloc = (pager.yloc + pager.height) - 2 xloc = pager.xloc + 2 ibar = ScrollingEditor(width, yloc, xloc) ibar.enable_scrolling = True ibar.max_length = 512 ibar.colors['highlight'] = term.cyan_reverse return ibar
def make_editor_series(winsize, editors): colors = {'highlight': u''} # prevent horizontal scrolling prior to final column margin_pct = 100 - (100 / (winsize.width - 3)) # scroll at final column scroll_pct = 100 / (winsize.width - 3) return [ ScrollingEditor( yloc=_yloc, xloc=winsize.xloc, width=winsize.width, colors=colors, margin_pct=margin_pct, scroll_pct=scroll_pct, content=(u'' if not editors or _idx >= len(editors) else editors[_idx].content), max_length=winsize.width ) for _idx, _yloc in enumerate(range( winsize.yloc, winsize.yloc + winsize.height + -2))]
def get_lneditor(lightbar): """ Returns editor positioned at location of current selection. """ term = getterminal() width = min(80, max(term.width, 40)) yloc = (lightbar.yloc + lightbar.ypadding + lightbar.position[0] - 1) xloc = max(0, (term.width / 2) - (width / 2)) lneditor = ScrollingEditor(width=width, yloc=yloc, xloc=xloc) lneditor.enable_scrolling = True lneditor.max_length = 65534 lneditor.glyphs['bot-horiz'] = u'' lneditor.glyphs['top-horiz'] = u'' lneditor.colors['highlight'] = term.red_reverse lneditor.colors['border'] = term.bold_red # converts u'xxxxxx\r\n' to 'xxxxxx', # or 'zzzz\nxxxxxx\n' to u'zzzz xxxxxx', lneditor.update(softwrap_join(wrap_rstrip(lightbar.selection[1]))) return lneditor
def do_command(term, session, inp, fields, tgt_user, point): """ Perform action by given input. """ _color1, _color2, _color3 = [ getattr(term, _color) for _color in (color_lowlight, color_highlight, color_field_edit) ] # discover edit field by matching command key field_name = None for _fname, field in fields.items(): if field.key == inp.lower(): field_name = _fname break if field_name is None: # return False if no field matches this key return False # only 'sysop' may edit user groups if field_name == 'groups' and not session.user.is_sysop: return False # pylint: disable=W0631 # Using possibly undefined loop variable 'field' # TODO: we could probably stand to do a bit of a better job of detecting # screen resizes and providing ^L full-screen refresh during the remainder # of this procedure ... It would require quite the refactor, though. # special case; ssh public keys and groups use scrolling editor if field_name in ('pubkey', 'groups'): editor = ScrollingEditor( # issue #161; because of a 'border' (that we don't draw), # y must be offset by 1 and height by 2. yloc=field.edit_location.y - 1, xloc=field.edit_location.x - 1, width=field.width + 2, colors={'highlight': _color3}) # limit input to 1K editor.max_length = 1024 else: editor = LineEditor(field.width, colors={'highlight': _color3}) # find width for displaying description text and validation errors width = term.width - (point.x * 2) # show field description and cancellation description = (field.description or u'') + ' Press escape to cancel.' description_text = term.wrap(description, width=width) for y_offset, txt in enumerate(description_text): echo(term.move(point.y + y_offset, point.x)) echo(_color1(txt) + term.clear_eol) echo(term.clear_eos) # edit input field (occludes display field). echo(term.move(*field.edit_location)) inp = editor.read() if inp is None: # escape was pressed echo(term.move(*point)) echo(_color2('Canceled !') + term.clear_eos) time.sleep(1) return True else: # validate input if field.validate_fn is not None: errmsg, _ = field.validate_fn(tgt_user, inp) if errmsg: # failed validation, display validation error errmsg += ' Press any key.' for y_offset, txt in enumerate(term.wrap(errmsg, width=width)): echo(term.move(point.y + y_offset, point.x)) echo(_color2(txt) + term.clear_eol) echo(term.clear_eos) term.inkey() return True # well, it has validated, shall we apply it, then? if field_name in ( 'password', 'location', 'email', ): # except for anonymous, if tgt_user.handle != 'anonymous': setattr(tgt_user, field_name, inp) elif field_name in ( 'timeout', 'pubkey', ): if field_name == 'timeout': # coerce to integer, set, and if tgt_user is our current # user, then send new value for as engine event try: timeout_val = int(inp) except ValueError: return True if tgt_user.handle != 'anonymous': tgt_user[field_name] = timeout_val if tgt_user.handle == session.user.handle: session.send_event('set-timeout', timeout_val) elif field_name == 'pubkey': if tgt_user.handle != 'anonymous': tgt_user[field_name] = inp elif field_name in ('groups'): new_groups = set( filter(None, set(map(unicode.strip, inp.split(','))))) for old_grp in tgt_user.groups.copy(): if old_grp not in new_groups: tgt_user.group_del(old_grp) for new_grp in new_groups: if new_grp not in tgt_user.groups: tgt_user.group_add(new_grp) else: raise ValueError('unknown field name: {0}'.format(field_name)) if tgt_user.handle != 'anonymous': tgt_user.save() return True
def prompt_subscription(session, term, yloc, subscription, colors): """ This function is called to assign a new set of subscription tags for a user. If escape is pressed, the existing value is used, or '*' is used if not previously set. This should be called for first-time users, and optionally at any later time to change a subscription. """ if session.user.get('msg_subscription', None) is None: # force-display introductory description for first-time users. yloc += do_describe_message_system(term, colors) echo(u'\r\n\r\n') yloc += 2 # remind ourselves of all available tags yloc += do_describe_available_tags(term, colors) + 2 # for small screens, scroll and leave room for prompt & errors if yloc > term.height + 3: echo(u'\r\n' * 3) yloc = term.height - 3 # and prompt for setting of message tags xloc = max(0, (term.width // 2) - 40) input_prefix = u':: subscription tags:' echo(u''.join((term.move(yloc, xloc), input_prefix))) xloc += len(input_prefix) wide = min(40, (term.width - xloc - 2)) while True: editor = ScrollingEditor(xloc=xloc, yloc=yloc - 1, width=wide, colors={'highlight': colors['backlight']}, content=u', '.join(subscription), max_length=100) # Prompt for and evaluate the given input, splitting by comma, # removing any empty items, and defaulting to ['*'] on escape. inp = editor.read() or u'' subscription = filter(None, set(map(unicode.strip, inp.split(',')))) or set([u'*']) # Then, reduce to only validate tag patterns, tracking those # that do not match any known tags, and display a warning and # re-prompt if any are removed. removed, subscription = validate_tag_patterns(subscription) # clear existing warning, if any echo(u''.join((term.normal, u'\r\n\r\n', term.clear_eos))) if removed: # and display any unmatched tags as a warning, re-prompt txt = ''.join( (term.bold_red(u"The following patterns are not matched: "), u', '.join(removed))) show_description(term, txt, color=None) continue # otherwise everything is fine, # return new subscription set return subscription