Пример #1
0
 def append(self, ucs):
     """
     Update content buffer with additional lines of ansi unicodes.
     """
     self.content.extend(Ansi(Ansi(ucs).decode_pipe())
                         .wrap(self.visible_width - 1).splitlines())
     return self.move_end() or self.refresh(self.bottom)
Пример #2
0
 def align(self, text, width=None):
     """
     justify Ansi text alignment property and width. When None (default),
     the visible width after padding is used.
     """
     return (Ansi(text).rjust if self.alignment == 'right' else
             Ansi(text).ljust if self.alignment == 'left' else Ansi(text).
             center)(width if width is not None else self.visible_width)
Пример #3
0
 def fit_row(ucs):
     """ Strip a unicode row to fit window boundry, if necessary """
     column = self.visible_width + 1
     wrapped = Ansi(ucs).wrap(column).splitlines()
     if len(wrapped) > 1:
         marker = self.glyphs.get('strip', u' $')
         marker_column = self.visible_width - len(marker)
         wrapped = Ansi(ucs).wrap(marker_column).splitlines()
         ucs = Ansi(wrapped[0].rstrip()).ljust(marker_column) + marker
         return ucs
     return (Ansi(ucs).ljust(column))
Пример #4
0
    def refresh_row(self, row):
        """
        Return unicode byte sequence suitable for moving to location ypos of
        window-relative row, and displaying any valid entry there, or using
        glyphs['erase'] if out of bounds. Strings are ansi color safe, and
        will be trimmed using glyphs['strip'] if their displayed width is
        wider than window.
        """
        import x84.bbs.session
        from x84.bbs.output import Ansi
        pos = self.pos(self.ypadding + row, self.xpadding)
        entry = self.vitem_shift + row
        if entry >= len(self.content):
            # out-of-bounds;
            return u''.join((pos,
                self.glyphs.get('erase', u' ') * self.visible_width,))

        def fit_row(ucs):
            """ Strip a unicode row to fit window boundry, if necessary """
            column = self.visible_width + 1
            wrapped = Ansi(ucs).wrap(column).splitlines()
            if len(wrapped) > 1:
                marker = self.glyphs.get('strip', u' $')
                marker_column = self.visible_width - len(marker)
                wrapped = Ansi(ucs).wrap(marker_column).splitlines()
                ucs = Ansi(wrapped[0].rstrip()).ljust(marker_column) + marker
                return ucs
            return (Ansi(ucs).ljust(column))

        term = x84.bbs.session.getterminal()
        # allow ucs data with '\r\n', to accomidate soft and hardbreaks; just
        # don't display them, really wrecks up cusor positioning.
        ucs = self.content[entry][1].strip(u'\r\n')

        # highlighted entry; strip of ansi sequences, use color 'highlight'
        # trim and append '$ ' if it cannot fit,
        if entry == self.index:
            ucs = Ansi(ucs).seqfill()
            if len(Ansi(ucs)) > self.visible_width:
                ucs = fit_row(ucs)
            return u''.join((pos,
                             self.colors.get('highlight', u''),
                             self.align(ucs),
                             term.normal,))
        # unselected entry; retain ansi sequences, decode any pipe characters,
        # trim and append '$ ' if it cannot fit
        ucs = Ansi(ucs).decode_pipe()
        if len(Ansi(ucs)) > self.visible_width:
            ucs = fit_row(ucs)
        return u''.join((pos,
                         self.colors.get('lowlight', u''),
                         self.align(ucs),
                         term.normal,))
Пример #5
0
 def update(self, ucs):
     """
     Update content buffer with '\n'-delimited lines of Ansi.
     """
     try:
         self.content = Ansi(Ansi(ucs).decode_pipe()).wrap(
             self.visible_width).splitlines()
     except AssertionError, err:
         # indeterminate length
         logger = logging.getLogger()
         logger.warn('%s in [%r]', err, ucs)
         self.content = ucs.split('\r\n')
Пример #6
0
 def footer(self, ansi_text):
     """
     Returns sequence that positions and displays unicode sequence
     'ansi_text' at the bottom edge of the window.
     """
     xloc = self.width / 2 - min(len(Ansi(ansi_text)) / 2, self.width / 2)
     return self.pos(max(0, self.height - 1), max(0, xloc)) + ansi_text
Пример #7
0
 def title(self, ansi_text):
     """
     Returns sequence that positions and displays unicode sequence
     'ansi_text' at the title location of the window.
     """
     xloc = self.width / 2 - min(len(Ansi(ansi_text)) / 2, self.width / 2)
     return self.pos(0, max(0, xloc)) + ansi_text
Пример #8
0
 def backspace(self):
     """
     Remove character from end of content buffer,
     scroll as necessary.
     """
     if 0 == len(self.content):
         return u''
     rstr = u''
     # measured backspace erases over double-wide
     len_toss = len(Ansi(self.content[-1]))
     len_move = len(self.content[-1])
     self.content = self.content[:-1]
     if (self.is_scrolled and (self._horiz_pos < self.scroll_amt)):
         # shift left,
         self._horiz_shift -= self.scroll_amt
         self._horiz_pos += self.scroll_amt
         rstr += self.refresh()
     else:
         rstr += u''.join((
             self.fixate(0),
             u'\b' * len_toss,
             u' ' * len_move,
             u'\b' * len_move,))
         self._horiz_pos -= 1
     return rstr
Пример #9
0
def dummy_pager():
    """
    Provide interface without pager/lightbar.
    """
    # pylint: disable=R0912
    #        Too many branches
    from x84.bbs import getterminal, echo, getch, Ansi
    term = getterminal()
    msg_header = u'// bbS liSt'
    hindent = 2
    vindent = 5
    nlines = 0
    bbslist = get_bbslist()
    echo(u'\r\n' + msg_header.center(term.width).rstrip() + '\r\n\r\n')
    if 0 == len(bbslist):
        echo(u'\r\n\r\nNO BBSS. a%sdd ONE, q%sUit' % (
            term.bold_blue(':'), term.bold_blue(':')))
        while True:
            inp = getch()
            if inp in (u'q', 'Q'):
                return  # quit
            elif inp in (u'a', 'A'):
                process_keystroke(inp)
                break
    while True:
        for (key, line) in bbslist:
            if key is None:  # bbs software
                echo(term.blue_reverse(line.rstrip()) + '\r\n')
                nlines += 1
            else:
                wrapd = Ansi(line).wrap(term.width - hindent)
                echo(term.bold_blue(key) + term.bold_black('. '))
                for num, line in enumerate(wrapd.split('\r\n')):
                    if num != 0:
                        echo(' ' * hindent)
                    echo(line + '\r\n')
                    nlines += 1
            if nlines and (nlines % (term.height - vindent) == 0):
                if more(True):
                    return
        # one final prompt before exit
        if more(False):
            return
    return
Пример #10
0
def dummy_pager():
    """
    Provide interface without pager/lightbar.
    """
    # pylint: disable=R0912
    #        Too many branches
    from x84.bbs import getterminal, echo, getch, Ansi
    term = getterminal()
    msg_header = u'// bbS liSt'
    hindent = 2
    vindent = 5
    nlines = 0
    bbslist = get_bbslist()
    echo(u'\r\n' + msg_header.center(term.width).rstrip() + '\r\n\r\n')
    if 0 == len(bbslist):
        echo(u'\r\n\r\nNO BBSS. a%sdd ONE, q%sUit' %
             (term.bold_blue(':'), term.bold_blue(':')))
        while True:
            inp = getch()
            if inp in (u'q', 'Q'):
                return  # quit
            elif inp in (u'a', 'A'):
                process_keystroke(inp)
                break
    while True:
        for (key, line) in bbslist:
            if key is None:  # bbs software
                echo(term.blue_reverse(line.rstrip()) + '\r\n')
                nlines += 1
            else:
                wrapd = Ansi(line).wrap(term.width - hindent)
                echo(term.bold_blue(key) + term.bold_black('. '))
                for num, line in enumerate(wrapd.split('\r\n')):
                    if num != 0:
                        echo(' ' * hindent)
                    echo(line + '\r\n')
                    nlines += 1
            if nlines and (nlines % (term.height - vindent) == 0):
                if more(True):
                    return
        # one final prompt before exit
        if more(False):
            return
    return
Пример #11
0
def more(cont=False):
    """
    Returns True if user 'q'uit; otherwise False
    when prompting is complete (moar/next/whatever)
    """
    from x84.bbs import echo, getch, Ansi, getterminal, LineEditor, DBProxy
    prompt_key = u'\r\n\r\nENtER BBS iD: '
    msg_badkey = u'\r\n\r\nbbS id iNVAliD!'
    term = getterminal()
    prompt = u', '.join(
        fancy_blue(char, blurb) for char, blurb in ((
            'i',
            'NfO',
        ), (
            'a',
            'dd',
        ), (
            'c',
            'OMMENt',
        ), (
            'r',
            'AtE',
        ), (
            't',
            'ElNEt',
        ), ('v', 'ANSi'), (
            'q',
            'Uit',
        )))
    if cont:
        prompt += u', ' + fancy_blue(' ', 'more')
    prompt += u': '
    while True:
        echo('\r\n' + Ansi(prompt).wrap(term.width - (term.width / 3)))
        inp = getch()
        if inp in (u'q', 'Q'):
            return True
        elif inp is not None and type(inp) is not int:
            if cont and inp == u' ':
                echo('\r\n\r\n')
                return False
            if inp.lower() in u'acrtviACRTVI':
                # these keystrokes require a bbs key argument,
                # prompt the user for one
                echo(prompt_key)
                key = LineEditor(5).read()
                if (key is None or 0 == len(key.strip())
                        or not key in DBProxy('bbslist')):
                    echo(msg_badkey)
                    continue
                process_keystroke(inp, key)
Пример #12
0
 def process_keystroke(self, keystroke):
     """
     Process the keystroke received by read method and take action.
     """
     self._quit = False
     if keystroke in self.keyset['refresh']:
         return u'\b' * len(Ansi(self.content)) + self.refresh()
     elif keystroke in self.keyset['backspace']:
         if len(self.content) != 0:
             len_toss = len(Ansi(self.content[-1]))
             self.content = self.content[:-1]
             return u''.join((
                 u'\b' * len_toss,
                 u' ' * len_toss,
                 u'\b',))
     elif keystroke in self.keyset['backword']:
         if len(self.content) != 0:
             ridx = self.content.rstrip().rfind(' ') + 1
             toss = len(Ansi(self.content[ridx:]))
             move = len(self.content[ridx:])
             self.content = self.content[:ridx]
             return u''.join((
                 u'\b' * toss,
                 u' ' * move,
                 u'\b' * move,))
     elif keystroke in self.keyset['enter']:
         self._carriage_returned = True
     elif keystroke in self.keyset['exit']:
         self._quit = True
     elif type(keystroke) is int:
         return u''
     elif (ord(keystroke) >= ord(' ') and
             (len(Ansi(self.content)) < self.width or self.width == 0)):
         self.content += keystroke
         return keystroke if not self.hidden else self.hidden
     return u''
Пример #13
0
 def refresh_row(self, row):
     """
     Return unicode string suitable for refreshing pager window at
     visible row.
     """
     import x84.bbs.session
     term = x84.bbs.session.getterminal()
     ucs = (Ansi(self.visible_content[row])
            if row < len(self.visible_content)
            else u'')
     return u''.join((
         term.normal,
         self.pos(row + self.ypadding, self.xpadding),
         self.align(ucs),
         term.normal))
Пример #14
0
 def refresh(self):
     """
     Returns unicode byts suitable for drawing line.
     No movement or positional sequences are returned.
     """
     from x84.bbs.session import getterminal
     term = getterminal()
     lightbar = u''.join((
         term.normal,
         self.colors.get('highlight', u''),
         ' ' * self.width,
         '\b' * self.width))
     content = (self.hidden * len(Ansi(self.content))
                if self.hidden else self.content)
     return u''.join((
         lightbar,
         content,
         term.cursor_visible))
Пример #15
0
    def refresh(self):
        """
        Return unicode sequence suitable for refreshing the entire
        line and placing the cursor.

        A strange by-product; if scrolling was not previously enabled,
        it is if wrapping must occur; this can happen if a
        non-scrolling editor was provided a very large .content
        buffer, then later .refresh()'d. -- essentially enabling
        infinate scrolling
        """
        # reset position and detect new position
        from x84.bbs import getterminal
        term = getterminal()
        self._horiz_lastshift = self._horiz_shift
        self._horiz_shift = 0
        self._horiz_pos = 0
        for _count in range(len(Ansi(self.content))):
            if (self._horiz_pos >
                    (self.visible_width - self.scroll_amt)):
                self._horiz_shift += self.scroll_amt
                self._horiz_pos -= self.scroll_amt
                self.enable_scrolling = True
            self._horiz_pos += 1
        if self._horiz_shift > 0:
            self._horiz_shift += len(self.glyphs['strip'])
            prnt = u''.join((
                    self.glyphs['strip'],
                    self.content[self._horiz_shift:],))
        else:
            prnt = self.content
        return u''.join((
            self.pos(self.ypadding, self.xpadding),
            term.normal,
            self.colors.get('highlight', u''),
            self.align(prnt),
            self.fixate(),))
Пример #16
0
def get_swinfo(entry, pager):
    """
    given a normalized bbs software name,
    fetch a description paragraph for use in pager
    """
    from x84.bbs import getterminal
    from x84.bbs.output import Ansi
    term = getterminal()
    output = pager.clear()
    if entry:
        entry = Ansi(entry).seqfill().strip()
    if entry and entry.strip().lower() == 'enthral':
        output += pager.update(
            "Enthral is a fresh look at the old school art of bbsing. "
            "It's a fresh face to an old favorite. Although Enthral is "
            "still in it's alpha stages, the system is quite stable and "
            "is already very feature rich. Currently available for "
            "Linux, BSD, and Apple's OS X.\r\n\r\n"
            "   " + term.bold_blue('http://enthralbbs.com/') + "\r\n\r\n"
            "Author: Mercyful Fate\n"
            "IRC: #enthral on irc.bbs-scene.org\r\n")
        output += pager.title(u'- about ' + term.blue('Enthral') + u' -')
    elif entry and entry.strip().lower() == 'citadel':
        output += pager.update(
            "Ancient history.\r\n\r\n")
        output += pager.title(u'- about ' + term.blue('Citadel') + u' -')
    elif entry and entry.strip().lower() == 'mystic':
        output += pager.update(
            "Mystic BBS is a bulletin board system (BBS) software in "
            "the vein of other \"forum hack\" style software such as "
            "Renegade, Oblivion/2, and Iniquity. Like many of its "
            "counterparts it features a high degree of relatively "
            "easy customization thanks to its ACS based menu system "
            "along with fully editable strings and ANSI themes. "
            "Mystic also includes its own Pascal like MPL scripting "
            "language for even further flexibility.\r\n\r\n"
            "  " + term.bold_blue('http://mysticbbs.com/') + "\r\n\r\n"
            "Author: g00r00\r\n"
            "IRC: #MysticBBS on irc.efnet.org\r\n")
        output += pager.title(u'- about ' + term.blue('Mystic') + u' -')
    elif entry and entry.strip().lower() == 'synchronet':
        output += pager.update(
            "Synchronet Bulletin Board System Software is a free "
            "software package that can turn your personal computer "
            "into your own custom online service supporting multiple "
            "simultaneous users with hierarchical message and file "
            "areas, multi-user chat, and the ever-popular BBS door "
            "games.\r\n\r\n"
            "Synchronet has since been substantially redesigned as "
            "an Internet-only BBS package for Win32 and Unix-x86 "
            "platforms and is an Open Source project under "
            "continuous development.\r\n\r\n"
            "  " + term.bold_blue('http://www.synchro.net/\r\n') + "\r\n\r\n"
            "Author: Deuce\r\n"
            "IRC: #synchronet on irc.bbs-scene.org")
        output += pager.title(u'- about ' + term.blue('Synchronet') + u' -')
    elif entry and entry.strip().lower() == 'progressive':
        output += pager.update(
            "This bbs features threading, intra-process communication, "
            "and easy scripting in python. X/84 is a continuation of "
            "this codebase.\r\n\r\n"
            + "Author: jojo\r\n"
            "IRC: #prsv on irc.efnet.org")
        output += pager.title(u'- about ' + term.blue('The Progressive -'))
    elif entry and entry.strip().lower() == 'x/84':
        output += pager.update(
            "X/84 is an open source python utf8 bsd-licensed telnet "
            "server specificly designed for BBS's, MUD's, and high "
            "scriptability. It is a Continuation of 'The Progressive' "
            "and is the only BBS software to support both CP437 and "
            "UTF8 encoding.\r\n\r\n"
            "  " + term.bold_blue('https://github.com/jquast/x84/\r\n')
            + "\r\n\r\nAuthor: dingo, jojo\r\n"
            "IRC: #prsv on irc.efnet.org")
        output += pager.title(u'- about ' + term.blue('X/84') + u' -')
    else:
        output += pager.update(u' no information about %s.'
                               % (entry or u'').title(),)
        output += pager.title(u'- about ' + term.blue(entry or u'') + u' -')
    return output
Пример #17
0
def get_swinfo(entry, pager):
    """
    given a normalized bbs software name,
    fetch a description paragraph for use in pager
    """
    from x84.bbs import getterminal
    from x84.bbs.output import Ansi
    term = getterminal()
    output = pager.clear()
    if entry:
        entry = Ansi(entry).seqfill().strip()
    if entry and entry.strip().lower() == 'enthral':
        output += pager.update(
            "Enthral is a fresh look at the old school art of bbsing. "
            "It's a fresh face to an old favorite. Although Enthral is "
            "still in it's alpha stages, the system is quite stable and "
            "is already very feature rich. Currently available for "
            "Linux, BSD, and Apple's OS X.\r\n\r\n"
            "   " + term.bold_blue('http://enthralbbs.com/') + "\r\n\r\n"
            "Author: Mercyful Fate\n"
            "IRC: #enthral on irc.bbs-scene.org\r\n")
        output += pager.title(u'- about ' + term.blue('Enthral') + u' -')
    elif entry and entry.strip().lower() == 'citadel':
        output += pager.update("Ancient history.\r\n\r\n")
        output += pager.title(u'- about ' + term.blue('Citadel') + u' -')
    elif entry and entry.strip().lower() == 'mystic':
        output += pager.update(
            "Mystic BBS is a bulletin board system (BBS) software in "
            "the vein of other \"forum hack\" style software such as "
            "Renegade, Oblivion/2, and Iniquity. Like many of its "
            "counterparts it features a high degree of relatively "
            "easy customization thanks to its ACS based menu system "
            "along with fully editable strings and ANSI themes. "
            "Mystic also includes its own Pascal like MPL scripting "
            "language for even further flexibility.\r\n\r\n"
            "  " + term.bold_blue('http://mysticbbs.com/') + "\r\n\r\n"
            "Author: g00r00\r\n"
            "IRC: #MysticBBS on irc.efnet.org\r\n")
        output += pager.title(u'- about ' + term.blue('Mystic') + u' -')
    elif entry and entry.strip().lower() == 'synchronet':
        output += pager.update(
            "Synchronet Bulletin Board System Software is a free "
            "software package that can turn your personal computer "
            "into your own custom online service supporting multiple "
            "simultaneous users with hierarchical message and file "
            "areas, multi-user chat, and the ever-popular BBS door "
            "games.\r\n\r\n"
            "Synchronet has since been substantially redesigned as "
            "an Internet-only BBS package for Win32 and Unix-x86 "
            "platforms and is an Open Source project under "
            "continuous development.\r\n\r\n"
            "  " + term.bold_blue('http://www.synchro.net/\r\n') + "\r\n\r\n"
            "Author: Deuce\r\n"
            "IRC: #synchronet on irc.bbs-scene.org")
        output += pager.title(u'- about ' + term.blue('Synchronet') + u' -')
    elif entry and entry.strip().lower() == 'progressive':
        output += pager.update(
            "This bbs features threading, intra-process communication, "
            "and easy scripting in python. X/84 is a continuation of "
            "this codebase.\r\n\r\n" + "Author: jojo\r\n"
            "IRC: #prsv on irc.efnet.org")
        output += pager.title(u'- about ' + term.blue('The Progressive -'))
    elif entry and entry.strip().lower() == 'x/84':
        output += pager.update(
            "X/84 is an open source python utf8 bsd-licensed telnet "
            "server specificly designed for BBS's, MUD's, and high "
            "scriptability. It is a Continuation of 'The Progressive' "
            "and is the only BBS software to support both CP437 and "
            "UTF8 encoding.\r\n\r\n"
            "  " + term.bold_blue('https://github.com/jquast/x84/\r\n') +
            "\r\n\r\nAuthor: dingo, jojo\r\n"
            "IRC: #prsv on irc.efnet.org")
        output += pager.title(u'- about ' + term.blue('X/84') + u' -')
    else:
        output += pager.update(
            u' no information about %s.' % (entry or u'').title(), )
        output += pager.title(u'- about ' + term.blue(entry or u'') + u' -')
    return output
Пример #18
0
 def eol(self):
     """
     Return True when no more input can be accepted (end of line).
     """
     return len(Ansi(self.content)) >= self.max_length