Example #1
0
    def _valid_char(self, ch):
        """
        Filter for text that may be entered into this widget by the user

        :param ch: character to be inserted
        :type ch: bytes or unicode

        This implementation returns True for all printable characters.
        """
        return is_wide_char(ch, 0) or (len(ch) == 1 and ord(ch) >= 32)
Example #2
0
    def calculate_text_segments(self, text, width, wrap):
        """
        Calculate the segments of text to display given width screen
        columns to display them.

        text - unicode text or byte string to display
        width - number of available screen columns
        wrap - wrapping mode used

        Returns a layout structure without alignment applied.
        """
        nl, nl_o, sp_o = "\n", "\n", " "
        if PYTHON3 and isinstance(text, bytes):
            nl = B(nl) # can only find bytes in python3 bytestrings
            nl_o = ord(nl_o) # + an item of a bytestring is the ordinal value
            sp_o = ord(sp_o)
        b = []
        p = 0
        if wrap == 'clip':
            # no wrapping to calculate, so it's easy.
            while p<=len(text):
                n_cr = text.find(nl, p)
                if n_cr == -1:
                    n_cr = len(text)
                sc = calc_width(text, p, n_cr)
                l = [(0,n_cr)]
                if p!=n_cr:
                    l = [(sc, p, n_cr)] + l
                b.append(l)
                p = n_cr+1
            return b


        while p<=len(text):
            # look for next eligible line break
            n_cr = text.find(nl, p)
            if n_cr == -1:
                n_cr = len(text)
            sc = calc_width(text, p, n_cr)
            if sc == 0:
                # removed character hint
                b.append([(0,n_cr)])
                p = n_cr+1
                continue
            if sc <= width:
                # this segment fits
                b.append([(sc,p,n_cr),
                    # removed character hint
                    (0,n_cr)])

                p = n_cr+1
                continue
            pos, sc = calc_text_pos( text, p, n_cr, width )
            if pos == p: # pathological width=1 double-byte case
                raise CanNotDisplayText(
                    "Wide character will not fit in 1-column width")
            if wrap == 'any':
                b.append([(sc,p,pos)])
                p = pos
                continue
            assert wrap == 'space'
            if text[pos] == sp_o:
                # perfect space wrap
                b.append([(sc,p,pos),
                    # removed character hint
                    (0,pos)])
                p = pos+1
                continue
            if is_wide_char(text, pos):
                # perfect next wide
                b.append([(sc,p,pos)])
                p = pos
                continue
            prev = pos
            while prev > p:
                prev = move_prev_char(text, p, prev)
                if text[prev] == sp_o:
                    sc = calc_width(text,p,prev)
                    l = [(0,prev)]
                    if p!=prev:
                        l = [(sc,p,prev)] + l
                    b.append(l)
                    p = prev+1
                    break
                if is_wide_char(text,prev):
                    # wrap after wide char
                    next = move_next_char(text, prev, pos)
                    sc = calc_width(text,p,next)
                    b.append([(sc,p,next)])
                    p = next
                    break
            else:
                # unwrap previous line space if possible to
                # fit more text (we're breaking a word anyway)
                if b and (len(b[-1]) == 2 or ( len(b[-1])==1
                        and len(b[-1][0])==2 )):
                    # look for removed space above
                    if len(b[-1]) == 1:
                        [(h_sc, h_off)] = b[-1]
                        p_sc = 0
                        p_off = p_end = h_off
                    else:
                        [(p_sc, p_off, p_end),
                               (h_sc, h_off)] = b[-1]
                    if (p_sc < width and h_sc==0 and
                        text[h_off] == sp_o):
                        # combine with previous line
                        del b[-1]
                        p = p_off
                        pos, sc = calc_text_pos(
                            text, p, n_cr, width )
                        b.append([(sc,p,pos)])
                        # check for trailing " " or "\n"
                        p = pos
                        if p < len(text) and (
                            text[p] in (sp_o, nl_o)):
                            # removed character hint
                            b[-1].append((0,p))
                            p += 1
                        continue


                # force any char wrap
                b.append([(sc,p,pos)])
                p = pos
        return b
Example #3
0
    def calculate_text_segments( self, text, width, wrap ):
        """
        Calculate the segments of text to display given width screen 
        columns to display them.  
        
        text - text to display
        width - number of available screen columns
        wrap - wrapping mode used
        
        Returns a layout structure without aligmnent applied.
        """
        b = []
        p = 0
        if wrap == 'clip':
            # no wrapping to calculate, so it's easy.
            while p<=len(text):
                n_cr = text.find("\n", p)
                if n_cr == -1: 
                    n_cr = len(text)
                sc = calc_width(text, p, n_cr)
                l = [(0,n_cr)]
                if p!=n_cr:
                    l = [(sc, p, n_cr)] + l
                b.append(l)
                p = n_cr+1
            return b

        
        while p<=len(text):
            # look for next eligible line break
            n_cr = text.find("\n", p)
            if n_cr == -1: 
                n_cr = len(text)
            sc = calc_width(text, p, n_cr)
            if sc == 0:
                # removed character hint
                b.append([(0,n_cr)])
                p = n_cr+1
                continue
            if sc <= width:
                # this segment fits
                b.append([(sc,p,n_cr),
                    # removed character hint
                    (0,n_cr)])
                
                p = n_cr+1
                continue
            pos, sc = calc_text_pos( text, p, n_cr, width )
            # FIXME: handle pathological width=1 double-byte case
            if wrap == 'any':
                b.append([(sc,p,pos)])
                p = pos
                continue
            assert wrap == 'space'
            if text[pos] == " ":
                # perfect space wrap
                b.append([(sc,p,pos),
                    # removed character hint
                    (0,pos)])
                p = pos+1
                continue
            if is_wide_char(text, pos):
                # perfect next wide
                b.append([(sc,p,pos)])
                p = pos
                continue
            prev = pos    
            while prev > p:
                prev = move_prev_char(text, p, prev)
                if text[prev] == " ":
                    sc = calc_width(text,p,prev)
                    l = [(0,prev)]
                    if p!=prev:
                        l = [(sc,p,prev)] + l
                    b.append(l)
                    p = prev+1 
                    break
                if is_wide_char(text,prev):
                    # wrap after wide char
                    next = move_next_char(text, prev, pos)
                    sc = calc_width(text,p,next)
                    b.append([(sc,p,next)])
                    p = next
                    break
            else:
                # unwrap previous line space if possible to
                # fit more text (we're breaking a word anyway)
                if b and (len(b[-1]) == 2 or ( len(b[-1])==1 
                        and len(b[-1][0])==2 )):
                    # look for removed space above
                    if len(b[-1]) == 1:
                        [(h_sc, h_off)] = b[-1]
                        p_sc = 0
                        p_off = p_end = h_off
                    else:
                        [(p_sc, p_off, p_end),
                               (h_sc, h_off)] = b[-1]
                    if (p_sc < width and h_sc==0 and
                        text[h_off] == " "):
                        # combine with previous line
                        del b[-1]
                        p = p_off
                        pos, sc = calc_text_pos( 
                            text, p, n_cr, width )
                        b.append([(sc,p,pos)])
                        # check for trailing " " or "\n"
                        p = pos
                        if p < len(text) and (
                            text[p] in (" ","\n")):
                            # removed character hint
                            b[-1].append((0,p))
                            p += 1
                        continue
                        
                        
                # force any char wrap
                b.append([(sc,p,pos)])
                p = pos
        return b
Example #4
0
    def calculate_text_segments(self, text, width, wrap):
        """
        Calculate the segments of text to display given width screen
        columns to display them.

        text - unicode text or byte string to display
        width - number of available screen columns
        wrap - wrapping mode used

        Returns a layout structure without alignment applied.
        """

        # TODO: This function is a horror and a mess, and really hard to
        # understand. It's based on urwids StandardLayout, which by itself
        # is overly complex, and I added tab handling, which made it worse.
        # It's a prime candidate for refacturing, making easier to understand
        # and as it is heavily used, profiling would be nice too.

        nl, nl_o, sp_o, tab_o = "\n", "\n", " ", "\t"
        if PYTHON3 and isinstance(text, bytes):
            nl = B(nl)  # can only find bytes in python3 bytestrings
            nl_o = ord(nl_o)  # + an item of a bytestring is the ordinal value
            sp_o = ord(sp_o)
            tab_o = ord(tab_o)
        b = []
        p = 0
        if wrap == 'clip':
            # no wrapping to calculate, so it's easy.
            l = []
            while p <= len(text):
                n_cr = find_newline(text, p)
                if p != n_cr:
                    line = text[p:n_cr]
                    pt = 0
                    while pt < len(line):
                        n_tab = line.find(tab_o, pt)
                        if n_tab == -1:
                            end = len(line)
                        else:
                            end = n_tab

                        sc = calc_width(line, pt, end)
                        if sc != 0:
                            l.append((sc, p + pt, p + end))

                        if end == n_tab:  # A tab was found
                            extra_space = (self.tab_width - (
                                sc % self.tab_width))
                            l.append((extra_space, p + n_tab))

                        pt = end + 1

                l.append((0, n_cr))
                b.append(l)
                l = []
                if text[n_cr:n_cr+2] in TWOCHAR_NEWLINES:
                    # Two char newline:
                    p = n_cr + 2
                else:
                    p = n_cr + 1
            return b

        while p <= len(text):
            # look for next eligible line break
            n_cr = find_newline(text, p)

            line = text[p:n_cr]
            l = []
            pt = 0
            lc = 0
            while pt < len(line):
                n_tab = line.find(tab_o, pt)
                if n_tab == -1:
                    end = len(line)
                else:
                    end = n_tab

                sc = calc_width(line, pt, end)

                if lc + sc <= width:
                    # this segment fits
                    if sc:
                        l.append((sc, p + pt, p + end))
                    if end == n_tab:  # A tab was found
                        extra_space = self.tab_width - (sc % self.tab_width)
                        l.append((extra_space, p + n_tab))
                        lc += extra_space
                    else:
                        # removed character hint
                        l.append((0, p + end))

                    pt = end + 1
                    lc += sc

                    if lc >= width:
                        # The tab can sometimes push line length to width, and
                        # then we adjust the line length and make a new line.
                        overshoot = lc - width
                        spaces, pos = l[-1]
                        l[-1] = (spaces - overshoot, pos)
                        b.append(l)
                        l = []
                        lc = 0
                    continue

                # This segment does not fit. Let's fit it.
                pos, sc = calc_text_pos(line, pt, end, width - lc)
                if pos == pt:  # pathological width=1 double-byte case
                    raise CanNotDisplayText(
                        "Wide character will not fit in 1-column width")

                if wrap == 'any':
                    l.append((sc, p + pt, p + pos))
                    l.append((0, p + pos))
                    b.append(l)
                    l = []
                    lc = 0
                    pt = pos
                    continue

                assert wrap == 'space'
                if line[pos] == sp_o:
                    # perfect space wrap
                    l.append((sc, p + pt, p + pos))
                    # removed character hint
                    l.append((0, p + pos))
                    b.append(l)
                    l = []
                    lc = 0
                    pt = pos + 1
                    continue

                if is_wide_char(line, pos):
                    # perfect next wide
                    l.append((sc, p + pt, p + pos))
                    b.append(l)
                    l = []
                    lc = 0
                    pt = pos
                    continue

                prev = pos
                while prev > pt:
                    prev = move_prev_char(line, pt, prev)
                    if line[prev] == sp_o:
                        sc = calc_width(line, pt, prev)
                        if prev != pt:
                            l.append((sc, p + pt, p + prev))
                        l.append((0, p + prev))
                        b.append(l)
                        l = []
                        lc = 0
                        pt = prev + 1
                        break

                    if is_wide_char(line, prev):
                        # wrap after wide char
                        nextc = move_next_char(line, prev, pos)
                        sc = calc_width(line, pt, nextc)
                        l.append((sc, p + pt, p + nextc))
                        b.append(l)
                        l = []
                        lc = 0
                        pt = nextc
                        break
                else:
                    if lc == 0:
                        # unwrap previous line space if possible to
                        # fit more text (we're breaking a word anyway)
                        if b and (len(b[-1]) == 2 or (len(b[-1]) == 1 and
                                                      len(b[-1][0]) == 2)):
                            # look for removed space above
                            if len(b[-1]) == 1:
                                [(h_sc, h_off)] = b[-1]
                                p_sc = 0
                                p_off = p_end = h_off
                            else:
                                [(p_sc, p_off, p_end),
                                 (h_sc, h_off)] = b[-1][-2:]
                            if (p_sc < width and h_sc == 0 and
                               text[h_off] == sp_o):
                                # combine with previous line
                                old_line = b[-1][:-2]
                                del b[-1]
                                pt = p_off - p
                                pos, sc = calc_text_pos(
                                    line, pt, end, width)
                                old_line.append((sc, p + pt, p + pos))
                                b.append(old_line)
                                # check for trailing " " or "\n"
                                pt = pos
                                if pt < len(text) and (
                                   text[pt] in (sp_o, nl_o)):
                                    # removed character hint
                                    b[-1].append((0, p + pt))
                                    pt += 1
                                continue
                    # Break on previous tab, and try again.
                    if l:
                        b.append(l)
                        l = []
                        lc = 0
                        continue

                    # There is no space to break the line on, unwrapping the
                    # previous line doesn't help, I guess we just break on a
                    # character.
                    b.append([(sc, p + pt, p + pos)])
                    l = []
                    lc = 0
                    pt = pos

            # force any char wrap
            if l:
                b.append(l)
            elif not line:
                # An empty line.
                b.append([(0, n_cr)])
                pt = 1

            if text[pt-1:pt+1] in TWOCHAR_NEWLINES:
                # Two char newline:
                pt += 1
            p += pt
        return b
Example #5
0
    def calculate_text_segments(self, text, width, wrap):
        """
        Calculate the segments of text to display given width screen
        columns to display them.

        text - unicode text or byte string to display
        width - number of available screen columns
        wrap - wrapping mode used

        Returns a layout structure without aligmnent applied.
        """
        nl, nl_o, sp_o = "\n", "\n", " "
        if PYTHON3 and isinstance(text, bytes):
            nl = B(nl)  # can only find bytes in python3 bytestrings
            nl_o = ord(nl_o)  # + an item of a bytestring is the ordinal value
            sp_o = ord(sp_o)
        b = []
        p = 0
        if wrap == 'clip':
            # no wrapping to calculate, so it's easy.
            while p <= len(text):
                n_cr = text.find(nl, p)
                if n_cr == -1:
                    n_cr = len(text)
                sc = calc_width(text, p, n_cr)
                l = [(0, n_cr)]
                if p != n_cr:
                    l = [(sc, p, n_cr)] + l
                b.append(l)
                p = n_cr + 1
            return b

        while p <= len(text):
            # look for next eligible line break
            n_cr = text.find(nl, p)
            if n_cr == -1:
                n_cr = len(text)
            sc = calc_width(text, p, n_cr)
            if sc == 0:
                # removed character hint
                b.append([(0, n_cr)])
                p = n_cr + 1
                continue
            if sc <= width:
                # this segment fits
                b.append([
                    (sc, p, n_cr),
                    # removed character hint
                    (0, n_cr)
                ])

                p = n_cr + 1
                continue
            pos, sc = calc_text_pos(text, p, n_cr, width)
            if pos == p:  # pathological width=1 double-byte case
                raise CanNotDisplayText(
                    "Wide character will not fit in 1-column width")
            if wrap == 'any':
                b.append([(sc, p, pos)])
                p = pos
                continue
            assert wrap == 'space'
            if text[pos] == sp_o:
                # perfect space wrap
                b.append([
                    (sc, p, pos),
                    # removed character hint
                    (0, pos)
                ])
                p = pos + 1
                continue
            if is_wide_char(text, pos):
                # perfect next wide
                b.append([(sc, p, pos)])
                p = pos
                continue
            prev = pos
            while prev > p:
                prev = move_prev_char(text, p, prev)
                if text[prev] == sp_o:
                    sc = calc_width(text, p, prev)
                    l = [(0, prev)]
                    if p != prev:
                        l = [(sc, p, prev)] + l
                    b.append(l)
                    p = prev + 1
                    break
                if is_wide_char(text, prev):
                    # wrap after wide char
                    next = move_next_char(text, prev, pos)
                    sc = calc_width(text, p, next)
                    b.append([(sc, p, next)])
                    p = next
                    break
            else:
                # unwrap previous line space if possible to
                # fit more text (we're breaking a word anyway)
                if b and (len(b[-1]) == 2 or
                          (len(b[-1]) == 1 and len(b[-1][0]) == 2)):
                    # look for removed space above
                    if len(b[-1]) == 1:
                        [(h_sc, h_off)] = b[-1]
                        p_sc = 0
                        p_off = p_end = h_off
                    else:
                        [(p_sc, p_off, p_end), (h_sc, h_off)] = b[-1]
                    if (p_sc < width and h_sc == 0 and text[h_off] == sp_o):
                        # combine with previous line
                        del b[-1]
                        p = p_off
                        pos, sc = calc_text_pos(text, p, n_cr, width)
                        b.append([(sc, p, pos)])
                        # check for trailing " " or "\n"
                        p = pos
                        if p < len(text) and (text[p] in (sp_o, nl_o)):
                            # removed character hint
                            b[-1].append((0, p))
                            p += 1
                        continue

                # force any char wrap
                b.append([(sc, p, pos)])
                p = pos
        return b
Example #6
0
 def valid_char(self, ch):
     """Return true for printable characters."""
     return is_wide_char(ch,0) or (len(ch)==1 and ord(ch) >= 32)
Example #7
0
 def valid_char(self, ch):
     """Return true for printable characters."""
     return is_wide_char(ch, 0) or (len(ch) == 1 and ord(ch) >= 32)