def smart_indent_event(self, event): tracing.user_is_typing() first, last = self.get_selection_indices() self.undo_block_start() try: if first and last: if index2line(first) != index2line(last): return self.indent_region_event(event) self.send_deletion(first, last) self.delete(first, last) self.mark_set("insert", first) prefix = self.get("insert linestart", "insert") raw, effective = classifyws(prefix, self.tabwidth) if raw == len(prefix): # only whitespace to the left self.reindent_to(effective + self.indentwidth) else: # tab to the next 'stop' within or to right of line's self: if self.usetabs: pad = '\t' else: effective = len(prefix.expandtabs(self.tabwidth)) n = self.indentwidth pad = ' ' * (n - effective % n) self.insert("insert", pad) self.see("insert") return "break" finally: self.undo_block_stop()
def smart_backspace_event(self, event): tracing.user_is_typing() self.typed_char = False if self.old_line is None: self.old_line = self.create_line(self.get_current_line_number()) first, last = self.get_selection_indices() if first and last: self.send_deletion(first, last) self.delete(first, last) self.mark_set("insert", first) return "break" # Delete whitespace left, until hitting a real char or closest # preceding virtual tab stop. chars = self.get("insert linestart", "insert") if chars == '': if self.compare("insert", ">", "1.0"): # easy: delete preceding newline self.send_update_changed_line(force_sending=True) self.reset_line() self.delete("insert-1c") else: self.bell() # at start of buffer return "break" if chars[-1] not in " \t": # easy: delete preceding real char self.delete("insert-1c") return "break" # Ick. It may require *inserting* spaces if we back up over a # tab character! This is written to be clear, not fast. tabwidth = self.tabwidth have = len(chars.expandtabs(tabwidth)) assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... if self.context_use_ps1: last_line_of_prompt = sys.ps1.split('\n')[-1] else: last_line_of_prompt = '' ncharsdeleted = 0 while 1: if chars == last_line_of_prompt: break chars = chars[:-1] ncharsdeleted = ncharsdeleted + 1 have = len(chars.expandtabs(tabwidth)) if have <= want or chars[-1] not in " \t": break self.undo_block_start() self.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: self.insert("insert", ' ' * (want - have)) self.undo_block_stop() return "break"
def keypress_event(self, event): """Used to check if user typed a keyword, deleted some selection and to initialize old_line to check if user modified an instruction""" tracing.user_is_typing() keypress_is_char = len(event.char) >= 1 keypress_is_separator = keypress_is_char and event.char.isalnum( ) is False first, last = self.get_selection_indices() if self.typed_char and (keypress_is_separator or event.keysym == "space"): self.send_keyword(self.index("insert")) else: self.typed_char = keypress_is_char if keypress_is_char and first and last: self.send_deletion(first, last) if self.old_line is None: self.old_line = self.create_line(self.get_current_line_number())
def newline_and_indent_event(self, event): tracing.user_is_typing() if self.old_line is None: self.old_line = self.create_line(self.get_current_line_number()) # Trace last word if it's a keyword if self.typed_char: cursor = self.index("insert") self.send_keyword(cursor) self.typed_char = False first, last = self.get_selection_indices() self.undo_block_start() try: if first and last: self.send_deletion(first, last) self.delete(first, last) self.mark_set("insert", first) line = self.get("insert linestart", "insert") i, n = 0, len(line) while i < n and line[i] in " \t": i = i + 1 if i == n: # the cursor is in or at leading indentation in a continuation # line; just inject an empty line at the start self.insert("insert linestart", '\n') return "break" indent = line[:i] # strip whitespace before insert point unless it's in the prompt i = 0 last_line_of_prompt = sys.ps1.split('\n')[-1] while line and line[-1] in " \t" and line != last_line_of_prompt: line = line[:-1] i = i + 1 if i: self.delete("insert - %d chars" % i, "insert") # strip whitespace after insert point while self.get("insert") in " \t": self.delete("insert") # start new line self.insert("insert", '\n') # adjust indentation for continuations and block # open/close first need to find the last stmt lno = index2line(self.index('insert')) y = PyParse.Parser(self.indentwidth, self.tabwidth) if not self.context_use_ps1: for context in self.num_context_lines: startat = max(lno - context, 1) startatindex = repr(startat) + ".0" rawtext = self.get(startatindex, "insert") y.set_str(rawtext) bod = y.find_good_parse_start( self.context_use_ps1, self._build_char_in_string_func(startatindex)) if bod is not None or startat == 1: break y.set_lo(bod or 0) else: r = self.tag_prevrange("console", "insert") if r: startatindex = r[1] else: startatindex = "1.0" rawtext = self.get(startatindex, "insert") y.set_str(rawtext) y.set_lo(0) c = y.get_continuation_type() if c != PyParse.C_NONE: # The current stmt hasn't ended yet. if c == PyParse.C_STRING_FIRST_LINE: # after the first line of a string; do not indent at all pass elif c == PyParse.C_STRING_NEXT_LINES: # inside a string which started before this line; # just mimic the current indent self.insert("insert", indent) elif c == PyParse.C_BRACKET: # line up with the first (if any) element of the # last open bracket structure; else indent one # level beyond the indent of the line with the # last open bracket self.reindent_to(y.compute_bracket_indent()) elif c == PyParse.C_BACKSLASH: # if more than one line in this stmt already, just # mimic the current indent; else if initial line # has a start on an assignment stmt, indent to # beyond leftmost =; else to beyond first chunk of # non-whitespace on initial line if y.get_num_lines_in_stmt() > 1: self.insert("insert", indent) else: self.reindent_to(y.compute_backslash_indent()) else: assert 0, "bogus continuation type %r" % (c, ) return "break" # This line starts a brand new stmt; indent relative to # indentation of initial line of closest preceding # interesting stmt. indent = y.get_base_indent_string() self.insert("insert", indent) if y.is_block_opener(): self.smart_indent_event(event) elif indent and y.is_block_closer(): self.smart_backspace_event(event) return "break" finally: self.see("insert") self.undo_block_stop() self.send_update_changed_line(newline=True)