class CommandCompleter(object): def __init__(self, local_vars): super(CommandCompleter, self).__init__() self._locals = local_vars self._make_completer() self._n = 0 self._text = '' def _make_completer(self): l = {} l.update(builtins.__dict__) l.update(locals()) l.update(self._locals) self._completer = Completer(l) def complete_start(self, text): self._make_completer() self._text = text self._n = -1 return self.complete() def complete(self): self._n += 1 suggest = self._completer.complete(self._text, self._n) return suggest def complete_back(self): self._n -= 1 if self._n < 0: self._n = 0 return None suggest = self._completer.complete(self._text, self._n) return suggest
def handle_TAB(self): """ Trap the TAB keystroke. """ necessarypart = "".join(self.lineBuffer).split(" ")[-1] completer = Completer(globals()) if completer.complete(necessarypart, 0): matches = list(set(completer.matches)) # has multiples if len(matches) == 1: length = len(necessarypart) self.lineBuffer = self.lineBuffer[:-length] self.lineBuffer.extend(matches[0]) self.lineBufferIndex = len(self.lineBuffer) else: matches.sort() commons = self.find_common(matches) if commons: length = len(necessarypart) self.lineBuffer = self.lineBuffer[:-length] self.lineBuffer.extend(commons) self.lineBufferIndex = len(self.lineBuffer) self.terminal.nextLine() while matches: matches, part = matches[4:], matches[:4] for item in part: self.terminal.write("%s" % item.ljust(30)) self.terminal.write("\n") self.terminal.nextLine() self.terminal.eraseLine() self.terminal.cursorBackward(self.lineBufferIndex + 5) self.terminal.write("%s %s" % (self.ps[self.pn], "".join(self.lineBuffer)))
def handle_TAB(self): necessarypart = "".join(self.lineBuffer).split(' ')[-1] completer = Completer(globals()) if completer.complete(necessarypart, 0): matches = list(set(completer.matches)) # has multiples if len(matches) == 1: length = len(necessarypart) self.lineBuffer = self.lineBuffer[:-length] self.lineBuffer.extend(matches[0]) self.lineBufferIndex = len(self.lineBuffer) else: matches.sort() commons = self.find_common(matches) if commons: length = len(necessarypart) self.lineBuffer = self.lineBuffer[:-length] self.lineBuffer.extend(commons) self.lineBufferIndex = len(self.lineBuffer) self.terminal.nextLine() while matches: matches, part = matches[4:], matches[:4] for item in part: self.terminal.write('%s' % item.ljust(30)) self.terminal.write('\n') self.terminal.nextLine() self.terminal.eraseLine() self.terminal.cursorBackward(self.lineBufferIndex + 5) self.terminal.write("%s %s" % (self.ps[self.pn], "".join(self.lineBuffer)))
def complete(self,text,state): if text.endswith(".__doc__"): new_text = text.replace(".__doc__","") help(eval(new_text)) readline.redisplay() readline.insert_text(new_text) else: value = Completer.complete(self,text,state) return value
def keyPressEvent(self, event): qt = QtCore.Qt if event.key() == qt.Key_Tab: line = str(self.document().lastBlock().text())[4:] completer = Completer(self.interpreter.locals) suggestion = completer.complete(line, 0) if suggestion is not None: self.insertPlainText(suggestion[len(line):]) return None if event.key() == qt.Key_Down: if self.historyIndex == len(self.history): self.historyIndex -= 1 try: if self.historyIndex > -1: self.historyIndex -= 1 self.recallHistory() else: self.clearCurrentBlock() except Exception: pass return None if event.key() == qt.Key_Up: try: if len(self.history) - 1 > self.historyIndex: self.historyIndex += 1 self.recallHistory() else: self.historyIndex = len(self.history) except Exception: pass return None if event.key() == qt.Key_Home: # set cursor to position 4 in current block. 4 because that's where # the marker stops blockLength = len(self.document().lastBlock().text()[4:]) lineLength = len(self.document().toPlainText()) position = lineLength - blockLength textCursor = self.textCursor() textCursor.setPosition(position) self.setTextCursor(textCursor) return None if event.key() in [qt.Key_Left, qt.Key_Backspace]: # don't allow deletion of marker if self.textCursor().positionInBlock() == 4: return None if event.key() in [qt.Key_Return, qt.Key_Enter]: self.doEnter(event) return None # allow all other key events super(PyInterp, self).keyPressEvent(event)
def keyPressEvent(self, event): qt = QtCore.Qt if event.key() == qt.Key_Tab: line = str(self.document().lastBlock().text())[4:] completer = Completer(self.interpreter.locals) suggestion = completer.complete(line, 0) if suggestion is not None: self.insertPlainText(suggestion[len(line):]) return None if event.key() == qt.Key_Down: if self.historyIndex == len(self.history): self.historyIndex -= 1 try: if self.historyIndex > -1: self.historyIndex -= 1 self.recallHistory() else: self.clearCurrentBlock() except Exception: pass return None if event.key() == qt.Key_Up: try: if len(self.history) - 1 > self.historyIndex: self.historyIndex += 1 self.recallHistory() else: self.historyIndex = len(self.history) except Exception: pass return None if event.key() == qt.Key_Home: # set cursor to position 4 in current block. 4 because that's where # the marker stops blockLength = len(self.document().lastBlock().text()[4:]) lineLength = len(self.document().toPlainText()) position = lineLength - blockLength textCursor = self.textCursor() textCursor.setPosition(position) self.setTextCursor(textCursor) return None if event.key() in [qt.Key_Left, qt.Key_Backspace]: # don't allow deletion of marker if self.textCursor().positionInBlock() == 4: return None if event.key() in [qt.Key_Return, qt.Key_Enter]: self.doEnter(event) return None # allow all other key events super(PyInterp, self).keyPressEvent(event)
def complete(self, text, state): # Don't show all objects if we're typing in code if self.current_prompt == sys.ps2: if state == 0: if text == '': return ' ' else: return None return Completer.complete(self, text, state)
class CommandCompleter(object): def __init__(self, local_vars): super(CommandCompleter, self).__init__() self._locals = local_vars self._make_completer() self._n = 0 self._text = '' def _make_completer(self): l = {} l.update(builtins.__dict__) l.update(locals()) l.update(self._locals) self._completer = Completer(l) def complete_start(self, text): self._make_completer() self._text = text self._n = -1 return self.complete() def complete(self): self._n += 1 suggest = self._completer.complete(self._text, self._n) return suggest def complete_back(self): self._n -= 1 if self._n < 0: self._n = 0 return None suggest = self._completer.complete(self._text, self._n) return suggest
def handle_TAB(self): text = "".join(self.lineBuffer).split(' ')[-1] if len(text) == 0: # Bell character self.terminal.write("\a") return completer = Completer(self.namespace) if completer.complete(text, 0): allMatches = list(set(completer.matches)) # Get rid of a bunch of cruft builtins = __builtin__.keys() matches = [ x for x in allMatches if x.strip('(') not in builtins and "__" not in x ] matches.sort() # If there are no matches, ring the terminal bell # If there's only one match, autocomplete it # If there's more than one match, print a list of matches if len(matches) == 0: self.terminal.write("\a") return elif len(matches) == 1: length = len(text) self.lineBuffer = self.lineBuffer[:-length] self.lineBuffer.extend(matches[0]) self.lineBufferIndex = len(self.lineBuffer) else: # Remove text before the last dot, for brevity if "." in matches[0]: matches = [x[x.rfind(".") + 1:] for x in matches] self.terminal.nextLine() self.terminal.write(repr(matches)) self.terminal.nextLine() self.terminal.write("%s%s" % (self.ps[self.pn], "")) self.terminal.eraseLine() self.terminal.cursorBackward(self.lineBufferIndex + 5) self.terminal.write("%s%s" % (self.ps[self.pn], "".join(self.lineBuffer))) else: self.terminal.write("\a")
def _complete(text, globals_): """ Gets the completions for text from the exec globals. Returns a sorted list. """ from rlcompleter import Completer ctr = Completer(globals_) i = 0 comps = [] while 1: c = ctr.complete(text, i) if c is None: break comps.append(c) i += 1 comps = tuple(sorted(frozenset(comps))) return comps
class InteractiveConsole(BaseInteractiveConsole): def __init__(self, ls): BaseInteractiveConsole.__init__(self, ls) self.stdout = sys.stdout = sys.stderr = Stdout() self.completer = Completer(dict(self.locals)) def push(self, line): result = BaseInteractiveConsole.push(self, line) return (result, self.stdout.get_buffer()) def complete(self, text): state = 0 comps = [] while True: self.completer.namespace = dict(self.locals) result = self.completer.complete(text, state) if result is None: break comps.append(result) state += 1 return comps
def complete(self, text, state): if text == '': # you could replace ' ' to \t if you indent via tab return [' ', None][state] elif text.count("'") == 1: if not state: self.file_matches(text, "'") try: return self.matches[state] except IndexError: return None elif text.count('"') == 1: if not state: self.file_matches(text, '"') try: return self.matches[state] except IndexError: return None else: return Completer.complete(self, text, state)
def complete(self, text, state): if text == '': # you could replace ' ' to \t if you indent via tab return [' ', None][state] elif text.count("'") == 1: if not state: self.file_matches(text, "'") try: return self.matches[state] except IndexError: return None elif text.count('"') == 1: if not state: self.file_matches(text, '"') try: return self.matches[state] except IndexError: return None else: return Completer.complete(self, text, state)
def getSuggestions(self, line): from rlcompleter import Completer def _inRange(i): if MAX_COMPLETIONS <= 0: # No limit return True else: return i <= MAX_COMPLETIONS result = [] completer = Completer(self.globals) i = 0 suggestion = True while suggestion and _inRange(i): suggestion = completer.complete(line, i) if suggestion: if i == MAX_COMPLETIONS and MAX_COMPLETIONS != 0: result.append('...') else: if suggestion not in result: result.append(suggestion) i += 1 return result
def getSuggestions(self, line): from rlcompleter import Completer def _inRange(i): if MAX_COMPLETIONS <= 0: # No limit return True else: return i <= MAX_COMPLETIONS result = [] completer = Completer(self.globals) i = 0 suggestion = True while suggestion and _inRange(i): suggestion = completer.complete(line, i) if suggestion: if i == MAX_COMPLETIONS and MAX_COMPLETIONS != 0: result.append('...') else: if suggestion not in result: result.append(suggestion) i += 1 return result
class GTKInterpreterConsole(Gtk.ScrolledWindow): """ An InteractiveConsole for GTK. It's an actual widget, so it can be dropped in just about anywhere. """ __gtype_name__ = "GTKInterpreterConsole" def __init__(self, locals: Dict[str, object], banner=banner): Gtk.ScrolledWindow.__init__(self) self.locals = locals locals["help"] = Help() self.set_min_content_width(640) self.set_min_content_height(480) self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.text = Gtk.TextView() self.text.set_wrap_mode(True) self.text.set_monospace(True) self.text.set_border_width(4) self.interpreter = code.InteractiveInterpreter(locals) self.completer = Completer(locals) self.buffer: List[str] = [] self.history: List[str] = [] self.banner = banner self.ps1 = ">>> " self.ps2 = "... " self.text.add_events(Gdk.EventMask.KEY_PRESS_MASK) self.text.connect("key_press_event", self.key_pressed) self.current_history = -1 self.mark = self.text.get_buffer().create_mark( "End", self.text.get_buffer().get_end_iter(), False ) # setup colors self.style_banner = Gtk.TextTag.new("banner") self.style_banner.set_property("foreground", "saddle brown") self.style_ps1 = Gtk.TextTag.new("ps1") self.style_ps1.set_property("foreground", "DarkOrchid4") self.style_ps1.set_property("editable", False) self.style_ps2 = Gtk.TextTag.new("ps2") self.style_ps2.set_property("foreground", "DarkOliveGreen") self.style_ps2.set_property("editable", False) self.style_out = Gtk.TextTag.new("stdout") self.style_out.set_property("foreground", "midnight blue") self.style_out.set_property("editable", False) self.style_err = Gtk.TextTag.new("stderr") self.style_err.set_property("style", Pango.Style.ITALIC) self.style_err.set_property("foreground", "red") self.style_err.set_property("editable", False) self.text.get_buffer().get_tag_table().add(self.style_banner) self.text.get_buffer().get_tag_table().add(self.style_ps1) self.text.get_buffer().get_tag_table().add(self.style_ps2) self.text.get_buffer().get_tag_table().add(self.style_out) self.text.get_buffer().get_tag_table().add(self.style_err) self.stdout = TextViewWriter("stdout", self.text, self.style_out) self.stderr = TextViewWriter("stderr", self.text, self.style_err) self.current_prompt = lambda: "" self.add(self.text) self.text.show() self.write_line(self.banner, self.style_banner) self.prompt_ps1() def reset_history(self): self.history = [] def reset_buffer(self): self.buffer = [] def prompt_ps1(self): self.current_prompt = self.prompt_ps1 self.write_line(self.ps1, self.style_ps1) def prompt_ps2(self): self.current_prompt = self.prompt_ps2 self.write_line(self.ps2, self.style_ps2) def write_line(self, text, style=None): start, end = self.text.get_buffer().get_bounds() if style: self.text.get_buffer().insert_with_tags(end, text, style) else: self.text.get_buffer().insert(end, text) self.text.scroll_to_mark(self.mark, 0, True, 1, 1) def push(self, line): self.buffer.append(line) if len(line) > 0: self.history.append(line) source = "\n".join(self.buffer) with self.stdout, self.stderr: more = self.interpreter.runsource(source, "<<console>>") if not more: self.reset_buffer() return more def key_pressed(self, widget, event): if event.keyval == Gdk.keyval_from_name("Return"): return self.execute_line() if event.keyval == Gdk.keyval_from_name("Tab"): return self.complete_line() if event.keyval == Gdk.keyval_from_name("Up"): self.current_history = self.current_history - 1 if self.current_history < -len(self.history): self.current_history = -len(self.history) return self.show_history() if event.keyval == Gdk.keyval_from_name("Down"): self.current_history = self.current_history + 1 if self.current_history > 0: self.current_history = 0 return self.show_history() ctrl = event.state & Gdk.ModifierType.CONTROL_MASK if (event.keyval == Gdk.keyval_from_name("Home")) or ( ctrl and event.keyval == Gdk.KEY_a ): line_count = self.text.get_buffer().get_line_count() - 1 start = self.text.get_buffer().get_iter_at_line_offset(line_count, 4) self.text.get_buffer().place_cursor(start) return True if ctrl and event.keyval == Gdk.KEY_e: end = self.text.get_buffer().get_end_iter() self.text.get_buffer().place_cursor(end) return True return False def show_history(self): if self.current_history != 0: self.replace_line(self.history[self.current_history]) return True def current_line(self): start, end = self.current_line_bounds() return self.text.get_buffer().get_text(start, end, True) def current_line_bounds(self): txt_buffer = self.text.get_buffer() line_count = txt_buffer.get_line_count() - 1 start = txt_buffer.get_iter_at_line(line_count) if start.get_chars_in_line() >= 4: start.forward_chars(4) end = txt_buffer.get_end_iter() return start, end def replace_line(self, txt): start, end = self.current_line_bounds() self.text.get_buffer().delete(start, end) self.write_line(txt) def execute_line(self): line = self.current_line() self.write_line("\n") more = self.push(line) self.text.get_buffer().place_cursor(self.text.get_buffer().get_end_iter()) if more: self.prompt_ps2() else: self.prompt_ps1() self.current_history = 0 return True def complete_line(self): line = self.current_line() tokens = line.split() if tokens: token = tokens[-1] completions: List[str] = [] p = self.completer.complete(token, len(completions)) while p: assert p completions.append(p) p = self.completer.complete(token, len(completions)) else: completions = list(self.locals.keys()) if len(completions) > 1: max_len = max(map(len, completions)) + 2 per_line = 80 // max_len for i, c in enumerate(completions): if i % per_line == 0: self.write_line("\n") self.write_line(c, self.style_ps1) self.write_line(" " * (max_len - len(c)), self.style_ps1) self.write_line("\n") self.current_prompt() self.write_line(line) elif len(completions) == 1: i = line.rfind(token) line = line[0:i] + completions[0] self.replace_line(line) return True
class GTKInterpreterConsole(Gtk.ScrolledWindow): """ An InteractiveConsole for GTK. It's an actual widget, so it can be dropped in just about anywhere. """ __gtype_name__ = "GTKInterpreterConsole" def __init__(self, locals=None, banner=banner): Gtk.ScrolledWindow.__init__(self) self.set_min_content_width(640) self.set_min_content_height(480) self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.text = Gtk.TextView() self.text.set_wrap_mode(True) self.text.set_monospace(True) self.text.set_border_width(4) self.interpreter = code.InteractiveInterpreter(locals) self.interpreter.locals["help"] = Help() self.completer = Completer(self.interpreter.locals) self.buffer = [] self.history = [] self.banner = banner self.ps1 = ">>> " self.ps2 = "... " self.text.add_events(Gdk.EventMask.KEY_PRESS_MASK) self.text.connect("key_press_event", self.key_pressed) self.current_history = -1 self.mark = self.text.get_buffer().create_mark( "End", self.text.get_buffer().get_end_iter(), False ) # setup colors self.style_banner = Gtk.TextTag.new("banner") self.style_banner.set_property("foreground", "saddle brown") self.style_ps1 = Gtk.TextTag.new("ps1") self.style_ps1.set_property("foreground", "DarkOrchid4") self.style_ps1.set_property("editable", False) self.style_ps2 = Gtk.TextTag.new("ps2") self.style_ps2.set_property("foreground", "DarkOliveGreen") self.style_ps2.set_property("editable", False) self.style_out = Gtk.TextTag.new("stdout") self.style_out.set_property("foreground", "midnight blue") self.style_out.set_property("editable", False) self.style_err = Gtk.TextTag.new("stderr") self.style_err.set_property("style", Pango.Style.ITALIC) self.style_err.set_property("foreground", "red") self.style_err.set_property("editable", False) self.text.get_buffer().get_tag_table().add(self.style_banner) self.text.get_buffer().get_tag_table().add(self.style_ps1) self.text.get_buffer().get_tag_table().add(self.style_ps2) self.text.get_buffer().get_tag_table().add(self.style_out) self.text.get_buffer().get_tag_table().add(self.style_err) self.stdout = TextViewWriter("stdout", self.text, self.style_out) self.stderr = TextViewWriter("stderr", self.text, self.style_err) self.current_prompt = None self.add(self.text) self.text.show() self.write_line(self.banner, self.style_banner) GLib.idle_add(self.prompt_ps1) def reset_history(self): self.history = [] def reset_buffer(self): self.buffer = [] def prompt_ps1(self): self.current_prompt = self.prompt_ps1 self.write_line(self.ps1, self.style_ps1) def prompt_ps2(self): self.current_prompt = self.prompt_ps2 self.write_line(self.ps2, self.style_ps2) def write_line(self, text, style=None): start, end = self.text.get_buffer().get_bounds() if style: self.text.get_buffer().insert_with_tags(end, text, style) else: self.text.get_buffer().insert(end, text) self.text.scroll_to_mark(self.mark, 0, True, 1, 1) def push(self, line): self.buffer.append(line) if len(line) > 0: self.history.append(line) source = "\n".join(self.buffer) with self.stdout, self.stderr: more = self.interpreter.runsource(source, "<<console>>") if not more: self.reset_buffer() return more def key_pressed(self, widget, event): if event.keyval == Gdk.keyval_from_name("Return"): return self.execute_line() if event.keyval == Gdk.keyval_from_name("Tab"): return self.complete_line() if event.keyval == Gdk.keyval_from_name("Up"): self.current_history = self.current_history - 1 if self.current_history < -len(self.history): self.current_history = -len(self.history) return self.show_history() if event.keyval == Gdk.keyval_from_name("Down"): self.current_history = self.current_history + 1 if self.current_history > 0: self.current_history = 0 return self.show_history() ctrl = event.state & Gdk.ModifierType.CONTROL_MASK if (event.keyval == Gdk.keyval_from_name("Home")) or ( ctrl and event.keyval == Gdk.KEY_a ): l = self.text.get_buffer().get_line_count() - 1 start = self.text.get_buffer().get_iter_at_line_offset(l, 4) self.text.get_buffer().place_cursor(start) return True if ctrl and event.keyval == Gdk.KEY_e: end = self.text.get_buffer().get_end_iter() self.text.get_buffer().place_cursor(end) return True return False def show_history(self): if self.current_history == 0: return True else: self.replace_line(self.history[self.current_history]) return True def current_line(self): start, end = self.current_line_bounds() return self.text.get_buffer().get_text(start, end, True) def current_line_bounds(self): txt_buffer = self.text.get_buffer() l = txt_buffer.get_line_count() - 1 start = txt_buffer.get_iter_at_line(l) if start.get_chars_in_line() >= 4: start.forward_chars(4) end = txt_buffer.get_end_iter() return start, end def replace_line(self, txt): start, end = self.current_line_bounds() self.text.get_buffer().delete(start, end) self.write_line(txt) def execute_line(self): line = self.current_line() self.write_line("\n") more = self.push(line) self.text.get_buffer().place_cursor(self.text.get_buffer().get_end_iter()) if more: self.prompt_ps2() else: self.prompt_ps1() self.current_history = 0 return True def complete_line(self): line = self.current_line() tokens = line.split() if tokens: token = tokens[-1] completions = [] p = self.completer.complete(token, len(completions)) while p != None: completions.append(p) p = self.completer.complete(token, len(completions)) else: completions = list(self.interpreter.locals.keys()) if len(completions) > 1: max_len = max(map(len, completions)) + 2 per_line = 80 // max_len for i, c in enumerate(completions): if i % per_line == 0: self.write_line("\n") self.write_line(c, self.style_ps1) self.write_line(" " * (max_len - len(c)), self.style_ps1) self.write_line("\n") self.current_prompt() self.write_line(line) elif len(completions) == 1: i = line.rfind(token) line = line[0:i] + completions[0] self.replace_line(line) return True
class PythonConsole(QPlainTextEdit, pytson.Translatable): def __init__(self, tabcomplete=True, spaces=True, tabwidth=2, font=defaultFont(), bgcolor=Qt.black, textcolor=Qt.white, startup="", silentStartup=False, parent=None, *, catchstd=False, closeAction): super(QPlainTextEdit, self).__init__(parent) self.setLineWrapMode(QPlainTextEdit.NoWrap) self.setWindowTitle(self._tr("pyTSon Console")) self.tabcomplete = tabcomplete self.spaces = spaces self.tabwidth = tabwidth self.setFont(font) self.setContextMenuPolicy(Qt.PreventContextMenu) p = self.palette p.setColor(QPalette.Base, bgcolor) p.setColor(QPalette.Text, textcolor) self.palette = p self.history = [] self.curhistory = -1 self.lastinp = "" self.locked = False self.globals = {} self.inmulti = False self.multi = "" self.incmd = False self.comp = Completer(self.globals) self.selformat = self.currentCharFormat() self.selformat.setBackground(Qt.white) self.selformat.setForeground(Qt.black) self.norformat = self.currentCharFormat() self.closeAction = closeAction # we have to make sure, that this runs in the same context as # commands run from the console self.clearlocals = list(eval("dir()", self.globals)) self.connect("destroyed()", self._resetdir) if catchstd: self.redirector = StdRedirector(self.appendLine) self.stdout = sys.stdout sys.stdout = self.redirector self.connect("destroyed()", self._resetStdout) else: self.redirector = None if os.path.isfile(startup): with open(startup, "r") as f: self.runCommand(f.read(), silentStartup) self.writePrompt(self.plainText != "") def _resetdir(self): curlocals = list(eval("dir()", self.globals)) for var in curlocals: if var not in self.clearlocals: try: exec("del %s" % var, self.globals) except Exception as e: pass def _resetStdout(self): sys.stdout = self.stdout def setFont(self, f): QPlainTextEdit.setFont(self, f) fm = QFontMetrics(f) self.setCursorWidth(fm.width("X")) self.setTabStopWidth(fm.width("X") * self.tabwidth) def prompt(self): return ">>> " if not self.inmulti else "... " def promptLength(self): return len(self.prompt()) def writePrompt(self, newline): if newline: self.textCursor().insertBlock() self.textCursor().insertText(self.prompt()) def promptCursor(self): retcur = QTextCursor(self.textCursor()) retcur.movePosition(QTextCursor.End) retcur.movePosition(QTextCursor.StartOfLine) retcur.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, self.promptLength()) return retcur def keyPressEvent(self, e): if self.locked: return if self.textCursor() < self.promptCursor(): self.moveCursor(QTextCursor.End) key = e.key() mods = e.modifiers() if key == Qt.Key_C and mods & Qt.ControlModifier: self.doKeyboardInterrupt() elif key == Qt.Key_D and mods & Qt.ControlModifier: self.doEndFile() elif key == Qt.Key_Backspace and mods == Qt.NoModifier: if self.textCursor() > self.promptCursor(): QPlainTextEdit.keyPressEvent(self, e) elif key in [Qt.Key_Enter, Qt.Key_Return] and mods == Qt.NoModifier: self.doExecuteCommand() elif key == Qt.Key_Up and mods == Qt.NoModifier: self.doHistoryUp() elif key == Qt.Key_Down and mods == Qt.NoModifier: self.doHistoryDown() elif key == Qt.Key_Left and mods == Qt.NoModifier: if self.textCursor().positionInBlock() > self.promptLength(): QPlainTextEdit.keyPressEvent(self, e) elif key == Qt.Key_Right: QPlainTextEdit.keyPressEvent(self, e) elif key == Qt.Key_Delete and mods == Qt.NoModifier: QPlainTextEdit.keyPressEvent(self, e) elif key == Qt.Key_End and mods == Qt.NoModifier: self.moveCursor(QTextCursor.EndOfLine) elif key == Qt.Key_Tab and mods == Qt.NoModifier: self.doTab() elif ((key == Qt.Key_Tab and mods == Qt.ShiftModifier) or key == Qt.Key_Backtab): self.doUntab() elif key == Qt.Key_Home and mods == Qt.NoModifier: self.setTextCursor(self.promptCursor()) else: QPlainTextEdit.keyPressEvent(self, e) self.ensureCursorVisible() def mousePressEvent(self, e): if e.button() == Qt.LeftButton: self.seltext = "" cur = QTextCursor(self.document()) cur.select(QTextCursor.Document) cur.setCharFormat(self.norformat) self.selcursor = self.textCursor() QPlainTextEdit.mousePressEvent(self, e) else: QPlainTextEdit.mousePressEvent(self, e) self.ensureCursorVisible() def mouseReleaseEvent(self, e): QPlainTextEdit.mouseReleaseEvent(self, e) if e.button() == Qt.LeftButton: self.textCursor().setCharFormat(self.selformat) self.seltext = self.textCursor().selectedText() self.setTextCursor(self.selcursor) elif e.button() == Qt.RightButton: if self.seltext == "": self.textCursor().insertText(QApplication.clipboard().text()) else: self.textCursor().insertText(self.seltext) QApplication.clipboard().setText(self.seltext) def doKeyboardInterrupt(self): self.moveCursor(QTextCursor.End) self.textCursor().insertBlock() self.textCursor().insertText("KeyboardInterrupt") self.inmulti = False self.multi = "" self.writePrompt(True) def doEndFile(self): cur = self.textCursor() self.moveCursor(QTextCursor.Right) # delete key to the right if there are if cur != self.textCursor(): self.textCursor().deletePreviousChar() elif self.textCursor() == self.promptCursor(): # if no chars in cur command, close self.closeAction() def currentLine(self): return self.textCursor().block().text()[self.promptLength():] def removeCurrentLine(self): self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor) self.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor) self.moveCursor(QTextCursor.End, QTextCursor.KeepAnchor) self.textCursor().removeSelectedText() def addHistory(self, cmd): if len(self.history) > 0: if cmd in self.history: self.history.pop(self.history.index(cmd)) self.history.append(cmd) def doHistoryUp(self): if len(self.history) == 0: return if self.curhistory == -1: self.lastinp = self.currentLine() self.curhistory = len(self.history) self.removeCurrentLine() self.writePrompt(False) self.curhistory -= 1 if self.curhistory == -1: self.textCursor().insertText(self.lastinp) self.curhistory = -1 else: self.textCursor().insertText(self.history[self.curhistory]) def doHistoryDown(self): if len(self.history) == 0 or self.curhistory == -1: return self.removeCurrentLine() self.writePrompt(False) self.curhistory += 1 if self.curhistory == len(self.history): self.textCursor().insertText(self.lastinp) self.curhistory = -1 else: self.textCursor().insertText(self.history[self.curhistory]) def doTab(self): if self.tabcomplete: cmd = self.currentLine() tokens = list(filter(None, re.split("[, \t\-\+\*\[\]\{\}:\(\)]+", cmd))) lasttoken = tokens[-1] if lasttoken != "": if lasttoken[-1] != cmd[-1]: # operators are filtered out (such as opening braces), # so append the last non-alphanumeric characters back # to the completion token lastalpha = max(cmd.rfind(i) for i in string.letters + string.digits) lasttoken += cmd[- lastalpha + 1:] state = 0 cur = self.comp.complete(lasttoken, state) if cur: l = [cur] while cur: state += 1 cur = self.comp.complete(lasttoken, state) if cur: l.append(cur) if len(l) == 1: self.removeCurrentLine() self.writePrompt(False) before = cmd[:-len(lasttoken)] if before == "": self.textCursor().insertText(l[0]) else: self.textCursor().insertText(cmd[:-len(lasttoken)] + l[0]) else: self.appendLine("\t\t".join(l)) prefix = ''.join(c[0] for c in takewhile(lambda x: all(x[0] == y for y in x), zip(*l))) if prefix != '': self.textCursor().insertText(prefix[len(lasttoken): ]) else: self.textCursor().insertText(cmd) else: if self.spaces: self.textCursor().insertText(" " * self.tabwidth) else: self.textCursor().insertText("\t") def doUntab(self): if self.tabcomplete: return sel = self.textCursor() tab = " " * self.tabwidth if self.spaces else "\t" sel.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, len(tab)) if sel >= self.promptCursor() and sel.selectedText() == tab: sel.removeSelectedText() return def appendLine(self, text): curline = self.currentLine() sel = self.textCursor() self.moveCursor(QTextCursor.End) self.appendPlainText(text) if not self.incmd: self.writePrompt(True) if curline != "": self.textCursor().insertText(curline) cur = self.promptCursor() cur.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, sel.positionInBlock() - self.promptLength()) self.setTextCursor(cur) def runCommand(self, cmd, silent): self.incmd = True if not self.redirector and not silent: tmp = sys.stdout sys.stdout = StdRedirector(self.appendLine) try: try: res = eval(cmd, self.globals) if res is not None: self.appendLine(repr(res)) except SyntaxError: exec(cmd, self.globals) except: if not silent: self.appendLine(traceback.format_exc(chain=False)) if not self.redirector and not silent: sys.stdout = tmp self.incmd = False def doExecuteCommand(self): cmd = self.currentLine().rstrip() if cmd == "": if self.inmulti: cmd = self.multi self.multi = "" self.inmulti = False else: self.addHistory(cmd) self.curhistory = -1 if self.inmulti: self.multi += "\n" + cmd self.writePrompt(True) return if cmd.endswith(":"): self.inmulti = True self.multi = cmd self.writePrompt(True) return self.moveCursor(QTextCursor.End) self.runCommand(cmd, False) self.writePrompt(True) self.ensureCursorVisible()
def keyPressEvent(self, event): qt = QtCore.Qt if event.key() == qt.Key_Tab: line = str(self.document().lastBlock().text())[4:] completer = Completer(self.interpreter.locals) suggestion = completer.complete(line, 0) if suggestion is not None: self.insertPlainText(suggestion[len(line):]) return None if event.key() == qt.Key_Down: if self.historyIndex == len(self.history): self.historyIndex -= 1 try: if self.historyIndex > -1: self.historyIndex -= 1 self.recallHistory() else: self.clearCurrentBlock() except: pass return None if event.key() == qt.Key_Up: try: if len(self.history) - 1 > self.historyIndex: self.historyIndex += 1 self.recallHistory() else: self.historyIndex = len(self.history) except: pass return None if event.key() == qt.Key_Home: # set cursor to position 4 in current block. 4 because that's where # the marker stops blockLength = len(self.document().lastBlock().text()[4:]) lineLength = len(self.document().toPlainText()) position = lineLength - blockLength textCursor = self.textCursor() textCursor.setPosition(position) self.setTextCursor(textCursor) return None if event.key() in [qt.Key_Left, qt.Key_Backspace]: # don't allow deletion of marker if self.textCursor().positionInBlock() == 4: return None if event.key() in [qt.Key_Return, qt.Key_Enter]: # set cursor to end of line to avoid line splitting textCursor = self.textCursor() position = len(self.document().toPlainText()) textCursor.setPosition(position) self.setTextCursor(textCursor) line = str(self.document().lastBlock().text())[4:] # remove marker line.rstrip() self.historyIndex = -1 if self.customCommands(line): return None else: try: # pylint: disable=pointless-statement line[-1] self.haveLine = True if line[-1] == ':': self.multiLine = True self.history.insert(0, line) except: self.haveLine = False if self.haveLine and self.multiLine: # multi line command self.command += line + '\n' # + command and line self.append('') # move down one line self.marker() # handle marker style return None if self.haveLine and not self.multiLine: # one line command self.command = line # line is the command self.append('') # move down one line self.interpreter.runIt(self.command) self.command = '' # clear command self.marker() # handle marker style return None if self.multiLine and not self.haveLine: # multi line done self.append('') # move down one line self.interpreter.runIt(self.command) self.command = '' # clear command self.multiLine = False # back to single line self.marker() # handle marker style return None if not self.haveLine and not self.multiLine: # just enter self.append('') self.marker() return None return None # allow all other key events super(PyInterp, self).keyPressEvent(event)