Package pytsonui :: Module console
[hide private]
[frames] | no frames]

Source Code for Module pytsonui.console

  1  import sys 
  2  import os 
  3   
  4  import traceback 
  5  import re 
  6   
  7  from rlcompleter import Completer 
  8  from itertools import takewhile 
  9   
 10  from PythonQt.QtCore import Qt 
 11  from PythonQt.QtGui import (QFont, QFontMetrics, QPlainTextEdit, QPalette, 
 12                              QTextCursor, QApplication) 
 13   
 14  import pytson 
 15   
 16   
17 -class StdRedirector:
18 - def __init__(self, callback):
19 self.callback = callback 20 self.no = False
21
22 - def write(self, text):
23 if not self.no: 24 self.callback(text.rstrip()) 25 self.no = not self.no
26 27
28 -def defaultFont():
29 if sys.platform.startswith("win"): 30 return QFont("Courier", 12) 31 else: 32 return QFont("Monospace", 12)
33 34
35 -class PythonConsole(QPlainTextEdit, pytson.Translatable):
36 - def __init__(self, tabcomplete=True, spaces=True, tabwidth=2, 37 font=defaultFont(), bgcolor=Qt.black, textcolor=Qt.white, 38 width=800, height=600, startup="", silentStartup=False, 39 parent=None, catchstd=False):
40 super(QPlainTextEdit, self).__init__(parent) 41 42 self.setLineWrapMode(QPlainTextEdit.NoWrap) 43 44 self.setAttribute(Qt.WA_DeleteOnClose) 45 self.setWindowTitle(self._tr("pyTSon Console")) 46 47 self.tabcomplete = tabcomplete 48 self.spaces = spaces 49 self.tabwidth = tabwidth 50 self.setFont(font) 51 52 self.resize(width, height) 53 54 self.setContextMenuPolicy(Qt.PreventContextMenu) 55 56 p = self.palette 57 p.setColor(QPalette.Base, bgcolor) 58 p.setColor(QPalette.Text, textcolor) 59 self.palette = p 60 61 self.history = [] 62 self.curhistory = -1 63 self.lastinp = "" 64 self.locked = False 65 self.globals = {} 66 self.inmulti = False 67 self.multi = "" 68 self.incmd = False 69 70 self.comp = Completer(self.globals) 71 72 self.selformat = self.currentCharFormat() 73 self.selformat.setBackground(Qt.white) 74 self.selformat.setForeground(Qt.black) 75 76 self.norformat = self.currentCharFormat() 77 78 if catchstd: 79 self.redirector = StdRedirector(self.appendLine) 80 self.stdout = sys.stdout 81 sys.stdout = self.redirector 82 83 self.connect("destroyed()", self._resetStdout) 84 else: 85 self.redirector = None 86 87 if os.path.isfile(startup): 88 with open(startup, "r") as f: 89 self.runCommand(f.read(), silentStartup) 90 91 self.writePrompt(self.plainText != "")
92
93 - def _resetStdout(self):
94 sys.stdout = self.stdout
95
96 - def setFont(self, f):
97 QPlainTextEdit.setFont(self, f) 98 99 fm = QFontMetrics(f) 100 self.setCursorWidth(fm.width("X")) 101 self.setTabStopWidth(fm.width("X") * self.tabwidth)
102
103 - def prompt(self):
104 return ">>> " if not self.inmulti else "... "
105
106 - def promptLength(self):
107 return len(self.prompt())
108
109 - def writePrompt(self, newline):
110 if newline: 111 self.textCursor().insertBlock() 112 113 self.textCursor().insertText(self.prompt())
114
115 - def promptCursor(self):
116 retcur = QTextCursor(self.textCursor()) 117 118 retcur.movePosition(QTextCursor.End) 119 retcur.movePosition(QTextCursor.StartOfLine) 120 retcur.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, 121 self.promptLength()) 122 123 return retcur
124
125 - def keyPressEvent(self, e):
126 if self.locked: 127 return 128 129 if self.textCursor() < self.promptCursor(): 130 self.moveCursor(QTextCursor.End) 131 132 key = e.key() 133 mods = e.modifiers() 134 135 if key == Qt.Key_C and mods & Qt.ControlModifier: 136 self.doKeyboardInterrupt() 137 elif key == Qt.Key_D and mods & Qt.ControlModifier: 138 self.doEndFile() 139 elif key == Qt.Key_Backspace and mods == Qt.NoModifier: 140 if self.textCursor() > self.promptCursor(): 141 QPlainTextEdit.keyPressEvent(self, e) 142 elif key in [Qt.Key_Enter, Qt.Key_Return] and mods == Qt.NoModifier: 143 self.doExecuteCommand() 144 elif key == Qt.Key_Up and mods == Qt.NoModifier: 145 self.doHistoryUp() 146 elif key == Qt.Key_Down and mods == Qt.NoModifier: 147 self.doHistoryDown() 148 elif key == Qt.Key_Left and mods == Qt.NoModifier: 149 if self.textCursor().positionInBlock() > self.promptLength(): 150 QPlainTextEdit.keyPressEvent(self, e) 151 elif key == Qt.Key_Right: 152 QPlainTextEdit.keyPressEvent(self, e) 153 elif key == Qt.Key_Delete and mods == Qt.NoModifier: 154 QPlainTextEdit.keyPressEvent(self, e) 155 elif key == Qt.Key_End and mods == Qt.NoModifier: 156 self.moveCursor(QTextCursor.EndOfLine) 157 elif key == Qt.Key_Tab and mods == Qt.NoModifier: 158 self.doTab() 159 elif ((key == Qt.Key_Tab and mods == Qt.ShiftModifier) or 160 key == Qt.Key_Backtab): 161 self.doUntab() 162 elif key == Qt.Key_Home and mods == Qt.NoModifier: 163 self.setTextCursor(self.promptCursor()) 164 else: 165 QPlainTextEdit.keyPressEvent(self, e) 166 167 self.ensureCursorVisible()
168
169 - def mousePressEvent(self, e):
170 if e.button() == Qt.LeftButton: 171 self.seltext = "" 172 cur = QTextCursor(self.document()) 173 cur.select(QTextCursor.Document) 174 cur.setCharFormat(self.norformat) 175 176 self.selcursor = self.textCursor() 177 QPlainTextEdit.mousePressEvent(self, e) 178 else: 179 QPlainTextEdit.mousePressEvent(self, e) 180 self.ensureCursorVisible()
181
182 - def mouseReleaseEvent(self, e):
183 QPlainTextEdit.mouseReleaseEvent(self, e) 184 if e.button() == Qt.LeftButton: 185 self.textCursor().setCharFormat(self.selformat) 186 self.seltext = self.textCursor().selectedText() 187 self.setTextCursor(self.selcursor) 188 elif e.button() == Qt.RightButton: 189 if self.seltext == "": 190 self.textCursor().insertText(QApplication.clipboard().text()) 191 else: 192 self.textCursor().insertText(self.seltext) 193 QApplication.clipboard().setText(self.seltext)
194
195 - def doKeyboardInterrupt(self):
196 self.moveCursor(QTextCursor.End) 197 198 self.textCursor().insertBlock() 199 self.textCursor().insertText("KeyboardInterrupt") 200 201 self.inmulti = False 202 self.multi = "" 203 204 self.writePrompt(True)
205
206 - def doEndFile(self):
207 cur = self.textCursor() 208 self.moveCursor(QTextCursor.Right) 209 210 # delete key to the right if there are 211 if cur != self.textCursor(): 212 self.textCursor().deletePreviousChar() 213 elif self.textCursor() == self.promptCursor(): 214 # if no chars in cur command, close 215 self.close()
216
217 - def currentLine(self):
218 return self.textCursor().block().text()[self.promptLength():]
219
220 - def removeCurrentLine(self):
221 self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor) 222 self.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor) 223 self.moveCursor(QTextCursor.End, QTextCursor.KeepAnchor) 224 self.textCursor().removeSelectedText()
225
226 - def addHistory(self, cmd):
227 if len(self.history) > 0: 228 if cmd in self.history: 229 self.history.pop(self.history.index(cmd)) 230 231 self.history.append(cmd)
232
233 - def doHistoryUp(self):
234 if len(self.history) == 0: 235 return 236 237 if self.curhistory == -1: 238 self.lastinp = self.currentLine() 239 self.curhistory = len(self.history) 240 241 self.removeCurrentLine() 242 self.writePrompt(False) 243 244 self.curhistory -= 1 245 246 if self.curhistory == -1: 247 self.textCursor().insertText(self.lastinp) 248 self.curhistory = -1 249 else: 250 self.textCursor().insertText(self.history[self.curhistory])
251
252 - def doHistoryDown(self):
253 if len(self.history) == 0 or self.curhistory == -1: 254 return 255 256 self.removeCurrentLine() 257 self.writePrompt(False) 258 259 self.curhistory += 1 260 261 if self.curhistory == len(self.history): 262 self.textCursor().insertText(self.lastinp) 263 self.curhistory = -1 264 else: 265 self.textCursor().insertText(self.history[self.curhistory])
266
267 - def doTab(self):
268 if self.tabcomplete: 269 cmd = self.currentLine() 270 tokens = list(filter(None, re.split("[, \t\-\+\*\[\]\{\}:\(\)]+", 271 cmd))) 272 if tokens[-1] != "": 273 state = 0 274 cur = self.comp.complete(tokens[-1], state) 275 276 if cur: 277 l = [cur] 278 279 while cur: 280 state += 1 281 cur = self.comp.complete(tokens[-1], state) 282 283 if cur: 284 l.append(cur) 285 286 if len(l) == 1: 287 self.removeCurrentLine() 288 self.writePrompt(False) 289 before = cmd[:-len(tokens[-1])] 290 if before == "": 291 self.textCursor().insertText(l[0]) 292 else: 293 self.textCursor().insertText(cmd[:-len(tokens[-1])] 294 + l[0]) 295 else: 296 self.appendLine("\t\t".join(l)) 297 self.writePrompt(True) 298 299 prefix = ''.join(c[0] for c in takewhile(lambda x: 300 all(x[0] == y for y in x), zip(*l))) 301 if prefix != '': 302 self.textCursor().insertText(cmd[:-len(tokens[-1])] 303 + prefix) 304 else: 305 self.textCursor().insertText(cmd) 306 else: 307 if self.spaces: 308 self.textCursor().insertText(" " * self.tabwidth) 309 else: 310 self.textCursor().insertText("\t")
311
312 - def doUntab(self):
313 if self.tabcomplete: 314 return 315 316 sel = self.textCursor() 317 318 tab = " " * self.tabwidth if self.spaces else "\t" 319 sel.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, len(tab)) 320 if sel >= self.promptCursor() and sel.selectedText() == tab: 321 sel.removeSelectedText() 322 return
323
324 - def appendLine(self, text):
325 curline = self.currentLine() 326 sel = self.textCursor() 327 328 self.moveCursor(QTextCursor.End) 329 self.appendPlainText(text) 330 331 if not self.incmd: 332 self.writePrompt(True) 333 334 if curline != "": 335 self.textCursor().insertText(curline) 336 337 cur = self.promptCursor() 338 cur.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, 339 sel.positionInBlock() - self.promptLength()) 340 self.setTextCursor(cur)
341
342 - def runCommand(self, cmd, silent):
343 self.incmd = True 344 345 if not self.redirector and not silent: 346 tmp = sys.stdout 347 sys.stdout = StdRedirector(self.appendLine) 348 349 try: 350 try: 351 res = eval(cmd, self.globals) 352 if res is not None: 353 self.appendLine(repr(res)) 354 except SyntaxError: 355 exec(cmd, self.globals) 356 except: 357 if not silent: 358 self.appendLine(traceback.format_exc(chain=False)) 359 360 if not self.redirector and not silent: 361 sys.stdout = tmp 362 363 self.incmd = False
364
365 - def doExecuteCommand(self):
366 cmd = self.currentLine().rstrip() 367 368 if cmd == "": 369 if self.inmulti: 370 cmd = self.multi 371 self.multi = "" 372 self.inmulti = False 373 else: 374 self.addHistory(cmd) 375 self.curhistory = -1 376 377 if self.inmulti: 378 self.multi += "\n" + cmd 379 self.writePrompt(True) 380 return 381 382 if cmd.endswith(":"): 383 self.inmulti = True 384 self.multi = cmd 385 self.writePrompt(True) 386 return 387 388 self.moveCursor(QTextCursor.End) 389 390 self.runCommand(cmd, False) 391 self.writePrompt(True) 392 393 self.ensureCursorVisible()
394