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)
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
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
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
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
def valid_char(self, ch): """Return true for printable characters.""" return is_wide_char(ch,0) or (len(ch)==1 and ord(ch) >= 32)
def valid_char(self, ch): """Return true for printable characters.""" return is_wide_char(ch, 0) or (len(ch) == 1 and ord(ch) >= 32)