def keypress(self, size, key): if key in config.edit_node_key_remappings: key = config.edit_node_key_remappings[key] p = self.edit_pos if key == 'enter': self.tree_widget.stop_editing() return None # paste elif key == "ctrl y": for char in self.paste_buffer: p = move_next_char(self.edit_text, p, -1) self.set_edit_text(self.edit_text + char) self.set_edit_pos(p + 1) # kill to beginning of line elif key == "ctrl u": if not self._delete_highlighted(): if p == 0: return key while (p != 0): p = move_prev_char(self.edit_text, 0, p) self.paste_buffer = self.edit_text[p:] + self.paste_buffer self.set_edit_text(self.edit_text[:p] + self.edit_text[self.edit_pos:]) self.set_edit_pos(p) # kill to beginning of word elif key == "ctrl w": if not self._delete_highlighted(): if p == 0: return key # first delete all whitespace while (p != 0) and (self.edit_text[p - 1] == ' '): p = move_prev_char(self.edit_text, 0, p) self.paste_buffer = self.edit_text[p:] + self.paste_buffer self.set_edit_text(self.edit_text[:p] + self.edit_text[self.edit_pos:]) self.set_edit_pos(p) # then delete all characters until whitespace or the beginning of the node is found while (p != 0) and (self.edit_text[p - 1] != ' '): p = move_prev_char(self.edit_text, 0, p) self.paste_buffer = self.edit_text[p:] + self.paste_buffer self.set_edit_text(self.edit_text[:p] + self.edit_text[self.edit_pos:]) self.set_edit_pos(p) (maxcol, maxrow) = size key = self.__super.keypress((maxcol, ), key)
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 keypress(self, size, key): if self.mode == 'n': p = self.edit_pos if key.isdigit(): self.count += key self.draw_statusbar(size) elif key == 'esc': self.reset_command() self.draw_statusbar(size) elif key == 'i': self.set_mode('i', size) elif key == 'h': if p == 0: return p = move_prev_char(self.edit_text, 0, p) self.set_edit_pos(p) elif key == 'j': x, y = self.get_cursor_coords(size) pref_col = self.get_pref_col(size) assert pref_col is not None if not self.move_cursor_to_coords(size, pref_col, y + 1): return elif key == 'k': x, y = self.get_cursor_coords(size) pref_col = self.get_pref_col(size) assert pref_col is not None if not self.move_cursor_to_coords(size, pref_col, y - 1): return elif key == 'l': if p >= len(self.edit_text): return p = move_next_char(self.edit_text, p, len(self.edit_text)) self.set_edit_pos(p) elif key == ':': self.command_start(':') elif key == '/': self.command_start('/') else: if key in self.path: self.path = self.path[key] if callable(self.path): if self.path.command_or_motion == 'motion': self.do_command(self.path, size) if self.future_command: self.do_command(self.future_command, size) else: self.master.document.move_caret() self.move_cursor_to_coords(size, self.master.document.caret.offset, self.master.document.caret.par) self.reset_command() elif self.path.immediate: self.do_command(self.path, size) self.reset_command() else: self.future_command = self.path self.reset_command_path() self.draw_statusbar(size) else: self.reset_command() elif self.mode == 'i': if key == 'esc': self.set_mode('n', size) elif key == 'meta enter': self.insert_text('\n') elif key == 'enter': self.insert_text('\n\n') else: super(Editor, self).keypress(size, key)
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 cmd_move_left(self, pressed=CURSOR_LEFT): if self.p==0: return pressed p = move_prev_char(self.edit_text,0,self.p) self.set_edit_pos(p)
def keypress(self, size, key): """ Handle editing keystrokes, return others. >>> e, size = Edit(), (20,) >>> e.keypress(size, 'x') >>> e.keypress(size, 'left') >>> e.keypress(size, '1') >>> print e.edit_text 1x >>> e.keypress(size, 'backspace') >>> e.keypress(size, 'end') >>> e.keypress(size, '2') >>> print e.edit_text x2 >>> e.keypress(size, 'shift f1') 'shift f1' """ (maxcol,) = size p = self.edit_pos if self.valid_char(key): self.insert_text( key ) elif key=="tab" and self.allow_tab: key = " "*(8-(self.edit_pos%8)) self.insert_text( key ) elif key=="enter" and self.multiline: key = "\n" self.insert_text( key ) elif command_map[key] == 'cursor left': if p==0: return key p = move_prev_char(self.edit_text,0,p) self.set_edit_pos(p) elif command_map[key] == 'cursor right': if p >= len(self.edit_text): return key p = move_next_char(self.edit_text,p,len(self.edit_text)) self.set_edit_pos(p) elif command_map[key] in ('cursor up', 'cursor down'): self.highlight = None x,y = self.get_cursor_coords((maxcol,)) pref_col = self.get_pref_col((maxcol,)) assert pref_col is not None #if pref_col is None: # pref_col = x if command_map[key] == 'cursor up': y -= 1 else: y += 1 if not self.move_cursor_to_coords((maxcol,),pref_col,y): return key elif key=="backspace": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p == 0: return key p = move_prev_char(self.edit_text,0,p) self.set_edit_text( self.edit_text[:p] + self.edit_text[self.edit_pos:] ) self.set_edit_pos( p ) elif key=="delete": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p >= len(self.edit_text): return key p = move_next_char(self.edit_text,p,len(self.edit_text)) self.set_edit_text( self.edit_text[:self.edit_pos] + self.edit_text[p:] ) elif command_map[key] in ('cursor max left', 'cursor max right'): self.highlight = None self.pref_col_maxcol = None, None x,y = self.get_cursor_coords((maxcol,)) if command_map[key] == 'cursor max left': self.move_cursor_to_coords((maxcol,), LEFT, y) else: self.move_cursor_to_coords((maxcol,), RIGHT, y) return else: # key wasn't handled return key
def keypress(self, size, key): """ Handle editing keystrokes, return others. >>> e, size = Edit(), (20,) >>> e.keypress(size, 'x') >>> e.keypress(size, 'left') >>> e.keypress(size, '1') >>> print e.edit_text 1x >>> e.keypress(size, 'backspace') >>> e.keypress(size, 'end') >>> e.keypress(size, '2') >>> print e.edit_text x2 >>> e.keypress(size, 'shift f1') 'shift f1' """ (maxcol, ) = size p = self.edit_pos if self.valid_char(key): self.insert_text(key) elif key == "tab" and self.allow_tab: key = " " * (8 - (self.edit_pos % 8)) self.insert_text(key) elif key == "enter" and self.multiline: key = "\n" self.insert_text(key) elif self._command_map[key] == 'cursor left': if p == 0: return key p = move_prev_char(self.edit_text, 0, p) self.set_edit_pos(p) elif self._command_map[key] == 'cursor right': if p >= len(self.edit_text): return key p = move_next_char(self.edit_text, p, len(self.edit_text)) self.set_edit_pos(p) elif self._command_map[key] in ('cursor up', 'cursor down'): self.highlight = None x, y = self.get_cursor_coords((maxcol, )) pref_col = self.get_pref_col((maxcol, )) assert pref_col is not None #if pref_col is None: # pref_col = x if self._command_map[key] == 'cursor up': y -= 1 else: y += 1 if not self.move_cursor_to_coords((maxcol, ), pref_col, y): return key elif key == "backspace": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p == 0: return key p = move_prev_char(self.edit_text, 0, p) self.set_edit_text(self.edit_text[:p] + self.edit_text[self.edit_pos:]) self.set_edit_pos(p) elif key == "delete": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p >= len(self.edit_text): return key p = move_next_char(self.edit_text, p, len(self.edit_text)) self.set_edit_text(self.edit_text[:self.edit_pos] + self.edit_text[p:]) elif self._command_map[key] in ('cursor max left', 'cursor max right'): self.highlight = None self.pref_col_maxcol = None, None x, y = self.get_cursor_coords((maxcol, )) if self._command_map[key] == 'cursor max left': self.move_cursor_to_coords((maxcol, ), LEFT, y) else: self.move_cursor_to_coords((maxcol, ), RIGHT, y) return else: # key wasn't handled return key
def keypress(self, size, key): """ Handle editing keystrokes, return others. >>> e, size = Edit(), (20,) >>> e.keypress(size, 'x') >>> e.keypress(size, 'left') >>> e.keypress(size, '1') >>> print e.edit_text 1x >>> e.keypress(size, 'backspace') >>> e.keypress(size, 'end') >>> e.keypress(size, '2') >>> print e.edit_text x2 >>> e.keypress(size, 'shift f1') 'shift f1' """ (maxcol,) = size p = self.edit_pos if self.valid_char(key): if (isinstance(key, unicode) and not isinstance(self._caption, unicode)): # screen is sending us unicode input, must be using utf-8 # encoding because that's all we support, so convert it # to bytes to match our caption's type key = key.encode('utf-8') self.insert_text(key) elif key=="tab" and self.allow_tab: key = " "*(8-(self.edit_pos%8)) self.insert_text(key) elif key=="enter" and self.multiline: key = "\n" self.insert_text(key) elif self._command_map[key] == 'cursor left': if p==0: return key p = move_prev_char(self.edit_text,0,p) self.set_edit_pos(p) elif self._command_map[key] == 'cursor right': if p >= len(self.edit_text): return key p = move_next_char(self.edit_text,p,len(self.edit_text)) self.set_edit_pos(p) elif self._command_map[key] in ('cursor up', 'cursor down'): self.highlight = None x,y = self.get_cursor_coords((maxcol,)) pref_col = self.get_pref_col((maxcol,)) assert pref_col is not None #if pref_col is None: # pref_col = x if self._command_map[key] == 'cursor up': y -= 1 else: y += 1 if not self.move_cursor_to_coords((maxcol,),pref_col,y): return key elif key=="backspace": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p == 0: return key p = move_prev_char(self.edit_text,0,p) self.set_edit_text( self.edit_text[:p] + self.edit_text[self.edit_pos:] ) self.set_edit_pos( p ) elif key=="delete": self.pref_col_maxcol = None, None if not self._delete_highlighted(): if p >= len(self.edit_text): return key p = move_next_char(self.edit_text,p,len(self.edit_text)) self.set_edit_text( self.edit_text[:self.edit_pos] + self.edit_text[p:] ) elif self._command_map[key] in ('cursor max left', 'cursor max right'): self.highlight = None self.pref_col_maxcol = None, None x,y = self.get_cursor_coords((maxcol,)) if self._command_map[key] == 'cursor max left': self.move_cursor_to_coords((maxcol,), LEFT, y) else: self.move_cursor_to_coords((maxcol,), RIGHT, y) return else: # key wasn't handled return key
def keypress(self, size, key): (maxcol, maxrow) = size focus_widget, pos = self.body.get_focus() # This is copied. I don't understand what it does. # I will test to remove it, but later. def actual_key(unhandled): if unhandled: return key if self.set_focus_pending or self.set_focus_valign_pending: self._set_focus_complete((maxcol, maxrow), focus=True) if self._valid_char(key): self._insert_char(key, focus_widget, pos) return if key == "tab": # Tab is magical and maps to different commands in different # situations. So far we insert a tab, though. self._insert_char('\t', focus_widget, pos) return if key == "enter": # We don't want to be able to remap enter, so we handle it here, # shortcutting it's command mapping. self.body.split_focus('\n') return command = self._command_map[key] # pass off the heavy lifting if command == urwid.CURSOR_UP: return actual_key(self._keypress_up((maxcol, maxrow))) if command == urwid.CURSOR_DOWN: return actual_key(self._keypress_down((maxcol, maxrow))) if command == urwid.CURSOR_PAGE_UP: return actual_key(self._keypress_page_up((maxcol, maxrow))) if command == urwid.CURSOR_PAGE_DOWN: return actual_key(self._keypress_page_down((maxcol, maxrow))) if command == urwid.CURSOR_MAX_LEFT: focus_widget.set_edit_pos(0) return if command == urwid.CURSOR_MAX_RIGHT: focus_widget.set_edit_pos(focus_widget.get_edit_len()) return if command == urwid.CURSOR_LEFT: col = focus_widget.edit_pos if col != 0: col = move_prev_char(focus_widget.edit_text, 0, col) focus_widget.set_edit_pos(col) return # Start of line, move to previous line, if any: if self.focus_position == 0: # No previous line return key focus_widget, pos = self.body.get_prev(pos) self.set_focus(pos, 'below') self.keypress(size, "end") return if command == urwid.CURSOR_RIGHT: col = focus_widget.edit_pos l = focus_widget.get_edit_len() if col < l: col = move_next_char(focus_widget.edit_text, col, len(focus_widget.edit_text)) focus_widget.set_edit_pos(col) return # We are moving beyond the end of line, go to next line. focus_widget, pos = self.body.get_next(pos) if not focus_widget: # No more lines return key self.set_focus(pos, 'above') self.keypress(size, "home") return if command == ERASE_LEFT: col = focus_widget.edit_pos if col == 0: if pos == 0: # Nothing to delete return key # Merge the lines self.body.combine_focus_with_prev() return self.body.code.delete_text(pos, col-1, pos, col) focus_widget.set_edit_text(self.body.code[pos]) focus_widget.set_edit_pos(col-1) return if command == ERASE_RIGHT: col = focus_widget.edit_pos if col == focus_widget.get_edit_len(): # End of line nextline, ignore = self.body.get_next(pos) if nextline is None: # Nothing to delete return key # Merge the lines self.body.combine_focus_with_next() return self.body.code.delete_text(pos, col, pos, col + 1) focus_widget.set_edit_text(self.body.code[pos]) return return key