Exemplo n.º 1
0
def get_ui(position=None):
    """
    Returns user interface (lightbar, pager).
    Optional argument position is tuple position of prior lightbar instance.
    """
    from x84.bbs import getterminal, Lightbar, Pager
    term = getterminal()
    assert term.height > 10 and term.width >= 40
    # +-+ +----+
    # |lb |pager
    # +-+ +----+
    height = term.height - 7
    lb_width = int(term.width * .3)
    pg_width = term.width - (lb_width)
    lb_xloc = (term.width / 2) - (term.width / 2)
    pg_xloc = lb_xloc + lb_width
    lightbar = Lightbar(height, lb_width, (term.height - height - 1), lb_xloc)
    pager = Pager(height, pg_width, (term.height - height - 1), pg_xloc)
    pager.ypadding = 2
    pager.xpadding = 2
    lightbar.update(get_bbslist(max_len=lightbar.visible_width))
    ## pressing Return is same as 't'elnet
    lightbar.keyset['enter'].extend((u't', u'T'))
    ## re-select previous selection
    if position is not None:
        lightbar.position = position
    return (pager, lightbar)
Exemplo n.º 2
0
def get_ui(position=None):
    """
    Returns user interface (lightbar, pager).
    Optional argument position is tuple position of prior lightbar instance.
    """
    from x84.bbs import getterminal, Lightbar, Pager
    term = getterminal()
    assert term.height > 10 and term.width >= 40
    # +-+ +----+
    # |lb |pager
    # +-+ +----+
    height = term.height - 7
    lb_width = int(term.width * .3)
    pg_width = term.width - (lb_width)
    lb_xloc = (term.width / 2) - (term.width / 2)
    pg_xloc = lb_xloc + lb_width
    lightbar = Lightbar(height, lb_width, (term.height - height - 1), lb_xloc)
    pager = Pager(height, pg_width, (term.height - height - 1), pg_xloc)
    pager.ypadding = 2
    pager.xpadding = 2
    lightbar.update(get_bbslist(max_len=lightbar.visible_width))
    ## pressing Return is same as 't'elnet
    lightbar.keyset['enter'].extend((u't', u'T'))
    ## re-select previous selection
    if position is not None:
        lightbar.position = position
    return (pager, lightbar)
Exemplo n.º 3
0
Arquivo: ol.py Projeto: hick/x84
def get_pager():
    """ Returns pager window for oneliners content. """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    xloc = max(0, (term.width / 2) - 50)
    width = min(term.width - 0, 100)
    pager = Pager(yloc=7, xloc=xloc, height=term.height - 10, width=width)
    pager.colors['border'] = term.blue
    return pager
Exemplo n.º 4
0
Arquivo: ol.py Projeto: hick/x84
def get_pager():
    """ Returns pager window for oneliners content. """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    xloc = max(0, (term.width / 2) - 50)
    width = min(term.width - 0, 100)
    pager = Pager(yloc=7, xloc=xloc, height=term.height - 10, width=width)
    pager.colors['border'] = term.blue
    return pager
Exemplo n.º 5
0
def get_pager(pager=None):
    """ Return Pager for use as chat window. """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    height = (term.height - 4)
    width = int(term.width * .9)
    yloc = term.height - height - 1
    xloc = int(term.width / 2) - (width / 2)
    new_pager = Pager(height, width, yloc, xloc)
    if pager is not None:
        content = pager.content
        # little hack to keep empty lines from re-importing
        for row in range(len(content)):
            ucs = content[row]
            if ucs.startswith(u'\x1b(B'):
                ucs = ucs[len(u'\x1b(B'):]
            if ucs.endswith(u'\x1b[m'):
                ucs = ucs[len(u'\x1b[m'):]
            content[row] = ucs
        new_pager.update('\r\n'.join(content))
    new_pager.enable_scrolling = True
    new_pager.colors['border'] = term.cyan
    new_pager.glyphs['right-vert'] = u'|'
    new_pager.glyphs['left-vert'] = u'|'
    new_pager.glyphs['bot-horiz'] = u''
    return new_pager
Exemplo n.º 6
0
Arquivo: ircchat.py Projeto: hick/x84
def get_pager(pager=None):
    """ Return Pager for use as chat window. """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    height = (term.height - 4)
    width = int(term.width * .9)
    yloc = term.height - height - 1
    xloc = int(term.width / 2) - (width / 2)
    new_pager = Pager(height, width, yloc, xloc)
    if pager is not None:
        content = pager.content
        # little hack to keep empty lines from re-importing
        for row in range(len(content)):
            ucs = content[row]
            if ucs.startswith(u'\x1b(B'):
                ucs = ucs[len(u'\x1b(B'):]
            if ucs.endswith(u'\x1b[m'):
                ucs = ucs[len(u'\x1b[m'):]
            content[row] = ucs
        new_pager.update('\r\n'.join(content))
    new_pager.enable_scrolling = True
    new_pager.colors['border'] = term.blue
    new_pager.glyphs['right-vert'] = u'|'
    new_pager.glyphs['left-vert'] = u'|'
    new_pager.glyphs['bot-horiz'] = u''
    return new_pager
Exemplo n.º 7
0
 def get_reader():
     """
     Provide Pager UI element for message reading.
     """
     reader_height = (term.height - (term.height / 3) - 2)
     reader_indent = 2
     reader_width = min(term.width - 1, min(term.width - reader_indent, 80))
     reader_ypos = ((term.height - 1 ) - reader_height if
                   (term.width - reader_width) < len_preview else 2)
     reader_height = term.height - reader_ypos - 1
     msg_reader = Pager(
         height=reader_height,
         width=reader_width,
         yloc=reader_ypos,
         xloc=min(len_preview + 2, term.width - reader_width))
     msg_reader.glyphs['top-horiz'] = u''
     msg_reader.glyphs['right-vert'] = u''
     return msg_reader
Exemplo n.º 8
0
def prompt_resize_term(session, term, name):
    want_cols = get_ini('sesame', '{0}_cols'.format(name), getter='getint')
    want_rows = get_ini('sesame', '{0}_rows'.format(name), getter='getint')

    if want_cols and want_rows and not term.kind.startswith('ansi'):
        while not (term.width == want_cols and term.height == want_rows):
            resize_msg = (u'Please resize your window to {0} x {1} '
                          u'current size is {term.width} x {term.height} '
                          u'or press return.  Press escape to cancel.'.format(
                              want_cols, want_rows, term=term))
            echo(term.normal + term.home + term.clear_eos + term.home)
            pager = Pager(yloc=0,
                          xloc=0,
                          width=want_cols,
                          height=want_rows,
                          colors={'border': term.bold_red})
            echo(term.move(term.height - 1, term.width))

            echo(pager.refresh() + pager.border())

            width = min(70, term.width - 5)
            for yoff, line in enumerate(term.wrap(resize_msg, width)):
                echo(u''.join((term.move(yoff + 1, 5), line.rstrip())))

            event, data = session.read_events(('input', 'refresh'))
            if event == 'refresh':
                continue

            if event == 'input':
                session.buffer_input(data, pushback=True)
                inp = term.inkey(0)
                while inp:
                    if inp.code == term.KEY_ENTER:
                        echo(term.normal + term.home + term.clear_eos)
                        return True
                    if inp.code == term.KEY_ESCAPE:
                        return False
                    inp = term.inkey(0)
        return True
    # if terminal type is 'ansi', just pass-through
    return True
Exemplo n.º 9
0
def prompt_resize_term(session, term, name):
    want_cols = get_ini('sesame', '{0}_cols'.format(name), getter='getint')
    want_rows = get_ini('sesame', '{0}_rows'.format(name), getter='getint')

    if want_cols and want_rows and not term.kind.startswith('ansi'):
        while not (term.width == want_cols and
                   term.height == want_rows):
            resize_msg = (u'Please resize your window to {0} x {1} '
                          u'current size is {term.width} x {term.height} '
                          u'or press return.  Press escape to cancel.'
                          .format(want_cols, want_rows, term=term))
            echo(term.normal + term.home + term.clear_eos + term.home)
            pager = Pager(yloc=0, xloc=0, width=want_cols, height=want_rows,
                          colors={'border': term.bold_red})
            echo(term.move(term.height - 1, term.width))

            echo(pager.refresh() + pager.border())

            width = min(70, term.width - 5)
            for yoff, line in enumerate(term.wrap(resize_msg, width)):
                echo(u''.join((term.move(yoff + 1, 5), line.rstrip())))

            event, data = session.read_events(('input', 'refresh'))
            if event == 'refresh':
                continue

            if event == 'input':
                session.buffer_input(data, pushback=True)
                inp = term.inkey(0)
                while inp:
                    if inp.code == term.KEY_ENTER:
                        echo(term.normal + term.home + term.clear_eos)
                        return True
                    if inp.code == term.KEY_ESCAPE:
                        return False
                    inp = term.inkey(0)
        return True
    # if terminal type is 'ansi', just pass-through
    return True
Exemplo n.º 10
0
def get_pager(news_txt, position=None):
    """
    Return Pager instance with content ``news_txt``.
    """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    width = min(130, (term.width - 2))
    height = term.height - len(redraw(None).splitlines())
    yloc = term.height - height
    xloc = (term.width / 2) - (width / 2)
    pager = Pager(height, width, yloc, xloc)
    pager.colors['border'] = term.blue
    pager.glyphs['left-vert'] = u''
    pager.glyphs['right-vert'] = u''
    pager.update('\n'.join(news_txt))
    if position is not None:
        pager.position = position
    return pager
Exemplo n.º 11
0
def get_pager(news_txt, position=None):
    """
    Return Pager instance with content ``news_txt``.
    """
    from x84.bbs import getterminal, Pager
    term = getterminal()
    width = min(130, (term.width - 2))
    height = term.height - len(redraw(None).splitlines())
    yloc = term.height - height
    xloc = (term.width / 2) - (width / 2)
    pager = Pager(height, width, yloc, xloc)
    pager.colors['border'] = term.blue
    pager.glyphs['left-vert'] = u''
    pager.glyphs['right-vert'] = u''
    pager.update('\n'.join(news_txt))
    if position is not None:
        pager.position = position
    return pager
Exemplo n.º 12
0
def show_scores():
    from x84.bbs import DBProxy, Pager, getterminal
    from x84.bbs import echo, getsession, ini
    session, term = getsession(), getterminal()
    allscores = DBProxy('tetris').items()
    if 0 == len(allscores):
        return
    # line up over tetris game, but logo & 'made by jojo' in view
    # -- since we have so much screen width, columize the scores,
    # the math brings it out to 2 columns, but fmt is adjustable
    pager_title = term.blue_reverse_underline('- hiGh SCOREs -')
    len_handle = ini.CFG.getint('nua', 'max_user')
    score_fmt = u'%s %s %s %s'
    len_pos = 2
    len_score = 10
    len_level = 3
    height, width = 11, 73
    yloc, xloc = 10, 3
    pager = Pager(height=height, width=width, yloc=yloc, xloc=xloc)
    pager.xpadding = 1
    pager.glyphs['left-vert'] = u''
    pager.glyphs['right-vert'] = u''
    pager.colors['border'] = term.blue_reverse
    pager.alignment = 'center'
    # pre-fesh pager border before fetch
    echo(pager.border() + pager.title(pager_title) + pager.clear())
    highscores = sorted(
        [(_score, _level, _handle.decode('utf8'))
         for (_handle, (_score, _level, _)) in allscores],
        reverse=True)
    pager.append(score_fmt % (
        term.bold_blue_underline('No'.ljust(len_pos)),
        term.bold_blue_underline('SCORE'.ljust(len_score)),
        term.bold_blue_underline('lVl'.ljust(len_level)),
        term.bold_blue_underline('hANdlE'.rjust(len_handle),)))
    pos = 0
    for pos, (_score, _level, _handle) in enumerate(highscores):
        if _handle == session.user.handle:
            pager.append(score_fmt % (
                term.blue_reverse(str(pos + 1).ljust(len_pos)),
                term.blue_reverse(str(_score).ljust(len_score)),
                term.blue_reverse(str(_level).ljust(len_level)),
                term.blue_reverse(_handle.rjust(len_handle)),))
        else:
            pager.append(score_fmt % (
                term.bold_blue(str(pos + 1).ljust(len_pos)),
                term.blue(str(_score).ljust(len_score)),
                term.blue(str(_level).ljust(len_level)),
                _handle.rjust(len_handle),))
    # append additional empty slot rows
    while len(pager.content) < pager.visible_height:
        pos += 1
        pager.append(score_fmt % (
            term.bold_blue(str(pos + 1).ljust(len_pos)),
            term.bold_black(u'.'.ljust(len_score)),
            term.bold_black(u'.'.ljust(len_level)),
            term.bold_black(u'.'.rjust(len_handle)),))

    dirty = 2  # 2=do not refresh border & title
    pager.move_home()
    while not pager.quit:
        # 1=full refresh
        dirty = 1 if session.poll_event('refresh') else dirty
        if dirty:
            echo(u''.join((
                term.normal,
                ((pager.border() + pager.title(pager_title))
                    if dirty != 2 else u''),
                pager.refresh(),
                pager.footer(u''.join((
                    term.underline_blue('q'),
                    term.bold_blue('uit')))),
            )))
            dirty = 0
        echo(pager.process_keystroke(term.inkey(1)))
Exemplo n.º 13
0
def show_scores():
    from x84.bbs import DBProxy, Pager, getterminal
    from x84.bbs import getch, echo, getsession, ini
    session, term = getsession(), getterminal()
    allscores = DBProxy('tetris').items()
    if 0 == len(allscores):
        return
    # line up over tetris game, but logo & 'made by jojo' in view
    # -- since we have so much screen width, columize the scores,
    # the math brings it out to 2 columns, but fmt is adjustable
    pager_title = term.blue_reverse_underline('- hiGh SCOREs -')
    len_handle = ini.CFG.getint('nua', 'max_user')
    score_fmt = u'%s %s %s %s'
    len_pos = 2
    len_score = 10
    len_level = 3
    height, width = 11, 73
    yloc, xloc = 10, 3
    pager = Pager(height=height, width=width, yloc=yloc, xloc=xloc)
    pager.xpadding = 1
    pager.glyphs['left-vert'] = u''
    pager.glyphs['right-vert'] = u''
    pager.colors['border'] = term.blue_reverse
    pager.alignment = 'center'
    # pre-fesh pager border before fetch
    echo(pager.border() + pager.title(pager_title) + pager.clear())
    highscores = sorted(
        [(_score, _level, _handle.decode('utf8'))
         for (_handle, (_score, _level, _)) in allscores],
        reverse=True)
    pager.append(score_fmt % (
        term.bold_blue_underline('No'.ljust(len_pos)),
        term.bold_blue_underline('SCORE'.ljust(len_score)),
        term.bold_blue_underline('lVl'.ljust(len_level)),
        term.bold_blue_underline('hANdlE'.rjust(len_handle),)))
    pos = 0
    for pos, (_score, _level, _handle) in enumerate(highscores):
        if _handle == session.user.handle:
            pager.append(score_fmt % (
                term.blue_reverse(str(pos + 1).ljust(len_pos)),
                term.blue_reverse(str(_score).ljust(len_score)),
                term.blue_reverse(str(_level).ljust(len_level)),
                term.blue_reverse(_handle.rjust(len_handle)),))
        else:
            pager.append(score_fmt % (
                term.bold_blue(str(pos + 1).ljust(len_pos)),
                term.blue(str(_score).ljust(len_score)),
                term.blue(str(_level).ljust(len_level)),
                _handle.rjust(len_handle),))
    # append additional empty slot rows
    while len(pager.content) < pager.visible_height:
        pos += 1
        pager.append(score_fmt % (
            term.bold_blue(str(pos + 1).ljust(len_pos)),
            term.bold_black(u'.'.ljust(len_score)),
            term.bold_black(u'.'.ljust(len_level)),
            term.bold_black(u'.'.rjust(len_handle)),))

    dirty = 2  # 2=do not refresh border & title
    pager.move_home()
    while not pager.quit:
        # 1=full refresh
        dirty = 1 if session.poll_event('refresh') else dirty
        if dirty:
            echo(u''.join((
                term.normal,
                ((pager.border() + pager.title(pager_title))
                    if dirty != 2 else u''),
                pager.refresh(),
                pager.footer(u''.join((
                    term.underline_blue('q'),
                    term.bold_blue('uit')))),
            )))
            dirty = 0
        echo(pager.process_keystroke(getch(1)))
Exemplo n.º 14
0
def main(save_key=u'draft'):
    """ Main procedure. """
    # pylint: disable=R0914,R0912,R0915
    #         Too many local variables
    #         Too many branches
    #         Too many statements
    from x84.bbs import getsession, getterminal, echo, getch, Ansi, Pager
    session, term = getsession(), getterminal()

    movement = (term.KEY_UP, term.KEY_DOWN, term.KEY_NPAGE,
                term.KEY_PPAGE, term.KEY_HOME, term.KEY_END,
                u'\r', term.KEY_ENTER)
    keyset = {'edit': (term.KEY_ENTER,),
              'command': (unichr(27), term.KEY_ESCAPE),
              'kill': (u'K',),
              'undo': (u'u', 'U',),
              'goto': (u'G',),
              'insert': (u'I',),
              'insert-before': (u'O',),
              'insert-after': (u'o',),
              'join': (u'J',),
              'rubout': (unichr(8), unichr(127),
                         unichr(23), term.KEY_BACKSPACE,),
              }

    def merge():
        """
        Merges line editor content as a replacement for the currently
        selected lightbar row. Returns True if text inserted caused
        additional rows to be appended, which is meaningful in a window
        refresh context.
        """
        lightbar.content[lightbar.index] = [
            lightbar.selection[0],
            softwrap_join(wrap_rstrip(lneditor.content))
            + HARDWRAP]
        prior_length = len(lightbar.content)
        prior_position = lightbar.position
        set_lbcontent(lightbar, get_lbcontent(lightbar))
        if len(lightbar.content) - prior_length == 0:
            echo(lightbar.refresh_row(prior_position[0]))
            return False
        while len(lightbar.content) - prior_length > 0:
            # hidden move-down for each appended line
            lightbar.move_down()
            prior_length += 1
        return True

    def statusline(lightbar):
        """
        Display status line and command help on ``lightbar`` borders
        """
        lightbar.colors['border'] = term.red if edit else term.yellow
        keyset_cmd = u''
        if not edit:
            keyset_cmd = u''.join((
                term.yellow(u'-( '),
                term.yellow_underline(u'S'), u':', term.bold(u'ave'),
                u' ',
                term.yellow_underline(u'A'), u':', term.bold(u'bort'),
                u' ',
                term.yellow_underline(u'?'), u':', term.bold(u'help'),
                term.yellow(u' )-'),))
            keyset_cmd = lightbar.pos(lightbar.height - 1,
                    max(0, lightbar.width - (len(Ansi(keyset_cmd)) + 3))
                    ) + keyset_cmd
        return u''.join((
            lightbar.border(),
            keyset_cmd,
            lightbar.pos(lightbar.height, lightbar.xpadding),
            u''.join((
                term.red(u'-[ '),
                u'EditiNG liNE ',
                term.reverse_red('%d' % (lightbar.index + 1,)),
                term.red(u' ]-'),)) if edit else u''.join((
                    term.yellow(u'-( '),
                    u'liNE ',
                    term.yellow('%d/%d ' % (
                        lightbar.index + 1,
                        len(lightbar.content),)),
                    '%d%% ' % (
                        int((float(lightbar.index + 1)
                            / max(1, len(lightbar.content))) * 100)),
                    term.yellow(u' )-'),)),
            lightbar.title(u''.join((
            term.red('-] '),
            term.bold(u'Escape'),
            u':', term.bold_red(u'command mode'),
            term.red(' [-'),)
            ) if edit else u''.join((
                                    term.yellow('-( '),
                                    term.bold(u'Enter'),
                                    u':', term.bold_yellow(u'edit mode'),
                                    term.yellow(' )-'),))),))

    def redraw_lneditor(lightbar, lneditor):
        """
        Return ucs suitable for refreshing line editor.
        """
        return ''.join((
            term.normal,
            statusline(lightbar),
            lneditor.border(),
            lneditor.refresh()))

    def get_ui(ucs, lightbar=None):
        """
        Returns Lightbar and ScrollingEditor instance.
        """
        lbr = get_lightbar(ucs)
        lbr.position = (lightbar.position
                        if lightbar is not None else (0, 0))
        lne = get_lneditor(lbr)
        return lbr, lne

    def banner():
        """
        Returns string suitable clearing screen
        """
        return u''.join((
            term.move(0, 0),
            term.normal,
            term.clear))

    def redraw(lightbar, lneditor):
        """
        Returns ucs suitable for redrawing Lightbar
        and ScrollingEditor UI elements.
        """
        return u''.join((
            term.normal,
            redraw_lightbar(lightbar),
            redraw_lneditor(lightbar, lneditor) if edit else u'',
        ))

    def redraw_lightbar(lightbar):
        """ Returns ucs suitable for redrawing Lightbar. """
        return u''.join((
            statusline(lightbar),
            lightbar.refresh(),))

    def resize(lightbar):
        """ Resize Lightbar. """
        if edit:
            # always re-merge current line on resize,
            merge()
        lbr, lne = get_ui(get_lbcontent(lightbar), lightbar)
        echo(redraw(lbr, lne))
        return lbr, lne

    ucs = session.user.get(save_key, u'')
    lightbar, lneditor = get_ui(ucs, None)
    echo(banner())
    dirty = True
    edit = False
    digbuf, num_repeat = u'', -1
    count_repeat = lambda: range(max(num_repeat, 1))
    while True:
        # poll for refresh
        if session.poll_event('refresh'):
            echo(banner())
            lightbar, lneditor = resize(lightbar)
            dirty = True
        if dirty:
            session.activity = 'editing %s' % (save_key,)
            echo(redraw(lightbar, lneditor))
            dirty = False
        # poll for input
        inp = getch(1)

        # buffer keystrokes for repeat
        if (not edit and inp is not None
                and type(inp) is not int
                and inp.isdigit()):
            digbuf += inp
            if len(digbuf) > 10:
                # overflow,
                echo(u'\a')
                digbuf = inp
            try:
                num_repeat = int(digbuf)
            except ValueError:
                try:
                    num_repeat = int(inp)
                except ValueError:
                    pass
            continue
        else:
            digbuf = u''

        # toggle edit mode,
        if inp in keyset['command'] or not edit and inp in keyset['edit']:
            edit = not edit  # toggle
            if not edit:
                # switched to command mode, merge our lines

                echo(term.normal + lneditor.erase_border())

                merge()
                lightbar.colors['highlight'] = term.yellow_reverse
            else:
                # switched to edit mode, save draft,
                # instantiate new line editor
                save_draft(save_key, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                lightbar.colors['highlight'] = term.red_reverse
            dirty = True

        # command mode, kill line
        elif not edit and inp in keyset['kill']:
            # when 'killing' a line, make accomidations to clear
            # bottom-most row, otherwise a ghosting effect occurs
            for _ in count_repeat():
                del lightbar.content[lightbar.index]
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            if lightbar.visible_bottom > len(lightbar.content):
                echo(lightbar.refresh_row(lightbar.visible_bottom + 1))
            else:
                dirty = True
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, insert line
        elif not edit and inp in keyset['insert']:
            for _ in count_repeat():
                lightbar.content.insert(lightbar.index,
                                       (lightbar.index, HARDWRAP,))
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            save_draft(save_key, get_lbcontent(lightbar))
            dirty = True

        # command mode; goto line
        elif not edit and inp in keyset['goto']:
            if num_repeat == -1:
                # 'G' alone goes to end of file,
                num_repeat = len(lightbar.content)
            echo(lightbar.goto((num_repeat or 1) - 1))
            echo(statusline(lightbar))

        # command mode; insert-before (switch to edit mode)
        elif not edit and inp in keyset['insert-before']:
            lightbar.content.insert(lightbar.index,
                                   (lightbar.index, HARDWRAP,))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode; insert-after (switch to edit mode)
        elif not edit and inp in keyset['insert-after']:
            lightbar.content.insert(lightbar.index + 1,
                                   (lightbar.index + 1, HARDWRAP,))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lightbar.move_down()
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, undo
        elif not edit and inp in keyset['undo']:
            for _ in count_repeat():
                if len(UNDO):
                    set_lbcontent(lightbar, UNDO.pop())
                    dirty = True
                else:
                    echo(u'\a')
                    break

        # command mode, join line
        elif not edit and inp in keyset['join']:
            for _ in count_repeat():
                if lightbar.index + 1 < len(lightbar.content):
                    idx = lightbar.index
                    lightbar.content[idx] = (idx,
                            WHITESPACE.join((
                                lightbar.content[idx][1].rstrip(),
                                lightbar.content[idx + 1][1].lstrip(),)))
                    del lightbar.content[idx + 1]
                    prior_length = len(lightbar.content)
                    set_lbcontent(lightbar, get_lbcontent(lightbar))
                    if len(lightbar.content) - prior_length > 0:
                        lightbar.move_down()
                    dirty = True
                else:
                    echo(u'\a')
                    break
            if dirty:
                save_draft(save_key, get_lbcontent(lightbar))

        # command mode, basic cmds & movement
        elif not edit and inp is not None:
            if inp in (u'a', u'A',):
                if yes_no(lightbar, term.yellow(u'- ')
                          + term.bold_red(u'AbORt')
                          + term.yellow(u' -')):
                    return False
                dirty = True
            elif inp in (u's', u'S',):
                if yes_no(lightbar, term.yellow(u'- ')
                          + term.bold_green(u'SAVE')
                          + term.yellow(u' -'), term.reverse_green):
                    save(save_key, get_lbcontent(lightbar))
                    return True
                dirty = True
            elif inp in (u'?',):
                pager = Pager(lightbar.height, lightbar.width,
                              lightbar.yloc, lightbar.xloc)
                pager.update(get_help())
                pager.colors['border'] = term.bold_blue
                echo(pager.border() + pager.title(u''.join((
                    term.bold_blue(u'-( '),
                    term.white_on_blue(u'r'), u':', term.bold(u'eturn'),
                    u' ',
                    term.bold_blue(u' )-'),))))
                pager.keyset['exit'].extend([u'r', u'R'])
                pager.read()
                echo(pager.erase_border())
                dirty = True
            else:
                moved = False
                for _ in count_repeat():
                    echo(lightbar.process_keystroke(inp))
                    moved = lightbar.moved or moved
                if moved:
                    echo(statusline(lightbar))

        # edit mode; movement
        elif edit and inp in movement:
            dirty = merge()
            if inp in (u'\r', term.KEY_ENTER,):
                lightbar.content.insert(lightbar.index + 1,
                                        [lightbar.selection[0] + 1, u''])
                inp = term.KEY_DOWN
                dirty = True
            ucs = lightbar.process_keystroke(inp)
            if lightbar.moved:
                echo(term.normal + lneditor.erase_border())
                echo(ucs)
                lneditor = get_lneditor(lightbar)
                save_draft(save_key, get_lbcontent(lightbar))
                echo(lneditor.refresh())
            else:
                dirty = True

        # edit mode -- append character / backspace
        elif edit and inp is not None:
            if (inp in keyset['rubout']
                    and len(lneditor.content) == 0
                    and lightbar.index > 0):
                # erase past margin,
                echo(term.normal + lneditor.erase_border())
                del lightbar.content[lightbar.index]
                lightbar.move_up()
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                dirty = True
            else:
                # edit mode, add/delete ch
                echo(lneditor.process_keystroke(inp))
                if lneditor.moved:
                    echo(statusline(lightbar))

        if inp is not None and type(inp) is not int and not inp.isdigit():
            # commands were processed, reset num_repeat to 1
            num_repeat = -1
Exemplo n.º 15
0
def main(save_key=u'draft'):
    """ Main procedure. """
    # pylint: disable=R0914,R0912,R0915
    #         Too many local variables
    #         Too many branches
    #         Too many statements
    from x84.bbs import getsession, getterminal, echo, getch, Ansi, Pager
    session, term = getsession(), getterminal()

    movement = (term.KEY_UP, term.KEY_DOWN, term.KEY_NPAGE, term.KEY_PPAGE,
                term.KEY_HOME, term.KEY_END, u'\r', term.KEY_ENTER)
    keyset = {
        'edit': (term.KEY_ENTER, ),
        'command': (unichr(27), term.KEY_ESCAPE),
        'kill': (u'K', ),
        'undo': (
            u'u',
            'U',
        ),
        'goto': (u'G', ),
        'insert': (u'I', ),
        'insert-before': (u'O', ),
        'insert-after': (u'o', ),
        'join': (u'J', ),
        'rubout': (
            unichr(8),
            unichr(127),
            unichr(23),
            term.KEY_BACKSPACE,
        ),
    }

    def merge():
        """
        Merges line editor content as a replacement for the currently
        selected lightbar row. Returns True if text inserted caused
        additional rows to be appended, which is meaningful in a window
        refresh context.
        """
        lightbar.content[lightbar.index] = [
            lightbar.selection[0],
            softwrap_join(wrap_rstrip(lneditor.content)) + HARDWRAP
        ]
        prior_length = len(lightbar.content)
        prior_position = lightbar.position
        set_lbcontent(lightbar, get_lbcontent(lightbar))
        if len(lightbar.content) - prior_length == 0:
            echo(lightbar.refresh_row(prior_position[0]))
            return False
        while len(lightbar.content) - prior_length > 0:
            # hidden move-down for each appended line
            lightbar.move_down()
            prior_length += 1
        return True

    def statusline(lightbar):
        """
        Display status line and command help on ``lightbar`` borders
        """
        lightbar.colors['border'] = term.red if edit else term.yellow
        keyset_cmd = u''
        if not edit:
            keyset_cmd = u''.join((
                term.yellow(u'-( '),
                term.yellow_underline(u'S'),
                u':',
                term.bold(u'ave'),
                u' ',
                term.yellow_underline(u'A'),
                u':',
                term.bold(u'bort'),
                u' ',
                term.yellow_underline(u'?'),
                u':',
                term.bold(u'help'),
                term.yellow(u' )-'),
            ))
            keyset_cmd = lightbar.pos(
                lightbar.height - 1,
                max(0, lightbar.width -
                    (len(Ansi(keyset_cmd)) + 3))) + keyset_cmd
        return u''.join((
            lightbar.border(),
            keyset_cmd,
            lightbar.pos(lightbar.height, lightbar.xpadding),
            u''.join((
                term.red(u'-[ '),
                u'EditiNG liNE ',
                term.reverse_red('%d' % (lightbar.index + 1, )),
                term.red(u' ]-'),
            )) if edit else u''.join((
                term.yellow(u'-( '),
                u'liNE ',
                term.yellow('%d/%d ' % (
                    lightbar.index + 1,
                    len(lightbar.content),
                )),
                '%d%% ' % (int((float(lightbar.index + 1) /
                                max(1, len(lightbar.content))) * 100)),
                term.yellow(u' )-'),
            )),
            lightbar.title(u''.join((
                term.red('-] '),
                term.bold(u'Escape'),
                u':',
                term.bold_red(u'command mode'),
                term.red(' [-'),
            )) if edit else u''.join((
                term.yellow('-( '),
                term.bold(u'Enter'),
                u':',
                term.bold_yellow(u'edit mode'),
                term.yellow(' )-'),
            ))),
        ))

    def redraw_lneditor(lightbar, lneditor):
        """
        Return ucs suitable for refreshing line editor.
        """
        return ''.join((term.normal, statusline(lightbar), lneditor.border(),
                        lneditor.refresh()))

    def get_ui(ucs, lightbar=None):
        """
        Returns Lightbar and ScrollingEditor instance.
        """
        lbr = get_lightbar(ucs)
        lbr.position = (lightbar.position if lightbar is not None else (0, 0))
        lne = get_lneditor(lbr)
        return lbr, lne

    def banner():
        """
        Returns string suitable clearing screen
        """
        return u''.join((term.move(0, 0), term.normal, term.clear))

    def redraw(lightbar, lneditor):
        """
        Returns ucs suitable for redrawing Lightbar
        and ScrollingEditor UI elements.
        """
        return u''.join((
            term.normal,
            redraw_lightbar(lightbar),
            redraw_lneditor(lightbar, lneditor) if edit else u'',
        ))

    def redraw_lightbar(lightbar):
        """ Returns ucs suitable for redrawing Lightbar. """
        return u''.join((
            statusline(lightbar),
            lightbar.refresh(),
        ))

    def resize(lightbar):
        """ Resize Lightbar. """
        if edit:
            # always re-merge current line on resize,
            merge()
        lbr, lne = get_ui(get_lbcontent(lightbar), lightbar)
        echo(redraw(lbr, lne))
        return lbr, lne

    ucs = session.user.get(save_key, u'')
    lightbar, lneditor = get_ui(ucs, None)
    echo(banner())
    dirty = True
    edit = False
    digbuf, num_repeat = u'', -1
    count_repeat = lambda: range(num_repeat if num_repeat != -1 else 1)
    while True:
        # poll for refresh
        if session.poll_event('refresh'):
            echo(banner())
            lightbar, lneditor = resize(lightbar)
            dirty = True
        if dirty:
            session.activity = 'editing %s' % (save_key, )
            echo(redraw(lightbar, lneditor))
            dirty = False
        # poll for input
        inp = getch(1)

        # buffer keystrokes for repeat
        if (not edit and inp is not None and type(inp) is not int
                and inp.isdigit()):
            digbuf += inp
            if len(digbuf) > 10:
                # overflow,
                echo(u'\a')
                digbuf = inp
            try:
                num_repeat = int(digbuf)
            except ValueError:
                try:
                    num_repeat = int(inp)
                except ValueError:
                    pass
            continue
        else:
            digbuf = u''

        # toggle edit mode,
        if inp in keyset['command'] or not edit and inp in keyset['edit']:
            edit = not edit  # toggle
            if not edit:
                # switched to command mode, merge our lines

                echo(term.normal + lneditor.erase_border())

                merge()
                lightbar.colors['highlight'] = term.yellow_reverse
            else:
                # switched to edit mode, save draft,
                # instantiate new line editor
                save_draft(save_key, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                lightbar.colors['highlight'] = term.red_reverse
            dirty = True

        # command mode, kill line
        elif not edit and inp in keyset['kill']:
            # when 'killing' a line, make accomidations to clear
            # bottom-most row, otherwise a ghosting effect occurs
            for _count in count_repeat():
                del lightbar.content[lightbar.index]
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                if lightbar.visible_bottom > len(lightbar.content):
                    echo(lightbar.refresh_row(lightbar.visible_bottom + 1))
                else:
                    dirty = True
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, insert line
        elif not edit and inp in keyset['insert']:
            for _count in count_repeat():
                lightbar.content.insert(lightbar.index, (
                    lightbar.index,
                    HARDWRAP,
                ))
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            save_draft(save_key, get_lbcontent(lightbar))
            dirty = True

        # command mode; goto line
        elif not edit and inp in keyset['goto']:
            if num_repeat == -1:
                # 'G' alone goes to end of file,
                num_repeat = len(lightbar.content)
            echo(lightbar.goto((num_repeat or 1) - 1))
            echo(statusline(lightbar))

        # command mode; insert-before (switch to edit mode)
        elif not edit and inp in keyset['insert-before']:
            lightbar.content.insert(lightbar.index, (
                lightbar.index,
                HARDWRAP,
            ))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode; insert-after (switch to edit mode)
        elif not edit and inp in keyset['insert-after']:
            lightbar.content.insert(lightbar.index + 1, (
                lightbar.index + 1,
                HARDWRAP,
            ))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lightbar.move_down()
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, undo
        elif not edit and inp in keyset['undo']:
            for _count in count_repeat():
                if len(UNDO):
                    set_lbcontent(lightbar, UNDO.pop())
                    dirty = True
                else:
                    echo(u'\a')
                    break

        # command mode, join line
        elif not edit and inp in keyset['join']:
            for _count in count_repeat():
                if lightbar.index + 1 < len(lightbar.content):
                    idx = lightbar.index
                    lightbar.content[idx] = (
                        idx,
                        WHITESPACE.join((
                            lightbar.content[idx][1].rstrip(),
                            lightbar.content[idx + 1][1].lstrip(),
                        )))
                    del lightbar.content[idx + 1]
                    prior_length = len(lightbar.content)
                    set_lbcontent(lightbar, get_lbcontent(lightbar))
                    if len(lightbar.content) - prior_length > 0:
                        lightbar.move_down()
                    dirty = True
                else:
                    echo(u'\a')
                    break
            if dirty:
                save_draft(save_key, get_lbcontent(lightbar))

        # command mode, basic cmds & movement
        elif not edit and inp is not None:
            if inp in (
                    u'a',
                    u'A',
            ):
                if yes_no(
                        lightbar,
                        term.yellow(u'- ') + term.bold_red(u'AbORt') +
                        term.yellow(u' -')):
                    return False
                dirty = True
            elif inp in (
                    u's',
                    u'S',
            ):
                if yes_no(
                        lightbar,
                        term.yellow(u'- ') + term.bold_green(u'SAVE') +
                        term.yellow(u' -'), term.reverse_green):
                    save(save_key, get_lbcontent(lightbar))
                    return True
                dirty = True
            elif inp in (u'?', ):
                pager = Pager(lightbar.height, lightbar.width, lightbar.yloc,
                              lightbar.xloc)
                pager.update(get_help())
                pager.colors['border'] = term.bold_blue
                echo(pager.border() + pager.title(u''.join((
                    term.bold_blue(u'-( '),
                    term.white_on_blue(u'r'),
                    u':',
                    term.bold(u'eturn'),
                    u' ',
                    term.bold_blue(u' )-'),
                ))))
                pager.keyset['exit'].extend([u'r', u'R'])
                pager.read()
                echo(pager.erase_border())
                dirty = True
            else:
                moved = False
                for _count in count_repeat():
                    echo(lightbar.process_keystroke(inp))
                    moved = lightbar.moved or moved
                if moved:
                    echo(statusline(lightbar))

        # edit mode; movement
        elif edit and inp in movement:
            dirty = merge()
            if inp in (
                    u'\r',
                    term.KEY_ENTER,
            ):
                lightbar.content.insert(lightbar.index + 1,
                                        [lightbar.selection[0] + 1, u''])
                inp = term.KEY_DOWN
                dirty = True
            ucs = lightbar.process_keystroke(inp)
            if lightbar.moved:
                echo(term.normal + lneditor.erase_border())
                echo(ucs)
                lneditor = get_lneditor(lightbar)
                save_draft(save_key, get_lbcontent(lightbar))
                echo(lneditor.refresh())
            else:
                dirty = True

        # edit mode -- append character / backspace
        elif edit and inp is not None:
            if (inp in keyset['rubout'] and len(lneditor.content) == 0
                    and lightbar.index > 0):
                # erase past margin,
                echo(term.normal + lneditor.erase_border())
                del lightbar.content[lightbar.index]
                lightbar.move_up()
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                dirty = True
            else:
                # edit mode, add/delete ch
                echo(lneditor.process_keystroke(inp))
                if lneditor.moved:
                    echo(statusline(lightbar))

        if inp is not None and type(inp) is not int and not inp.isdigit():
            # commands were processed, reset num_repeat to 1
            num_repeat = -1