我将this代码作为起点,并从rlcompleter2自动完成,但以下代码中存在两个问题,
import xxx as yyy
自动完成yyy无法正常工作x=3
,然后在pyqt解释器中运行x
,它说NameError: name 'x' is not defined
。如果你不使用maya,这个错误也可以从外部python解释器中重现,首先定义一些变量,然后启动这个ui,该变量不会被复制到ui中的解释器中。import os
import re
import sys
import code
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyInterpreter(QWidget):
def __init__(self, parent):
super(MyInterpreter, self).__init__(parent)
hBox = QHBoxLayout()
self.setLayout(hBox)
self.textEdit = PyInterp(self)
# this is how you pass in locals to the interpreter
self.textEdit.initInterpreter(locals())
self.resize(850, 400)
# self.centerOnScreen()
hBox.addWidget(self.textEdit)
hBox.setMargin(0)
hBox.setSpacing(0)
def centerOnScreen(self):
# center the widget on the screen
resolution = QDesktopWidget().screenGeometry()
self.move((resolution.width() / 2) - (self.frameSize().width() / 2),
(resolution.height() / 2) - (self.frameSize().height() / 2))
class PyInterp(QTextEdit):
class InteractiveInterpreter(code.InteractiveInterpreter):
def __init__(self, locals):
code.InteractiveInterpreter.__init__(self, locals)
def runIt(self, command):
code.InteractiveInterpreter.runsource(self, command)
def __init__(self, parent):
super(PyInterp, self).__init__(parent)
sys.stdout = self
sys.stderr = self
self.refreshMarker = False # to change back to >>> from ...
self.multiLine = False # code spans more than one line
self.command = '' # command to be ran
self.printBanner() # print sys info
self.marker() # make the >>> or ... marker
self.history = [] # list of commands entered
self.historyIndex = -1
self.interpreterLocals = {}
# setting the color for bg and text
# palette = QPalette()
# palette.setColor(QPalette.Base, QColor(0, 0, 0))
# palette.setColor(QPalette.Text, QColor(0, 255, 0))
# self.setPalette(palette)
self.setFont(QFont('Courier', 10))
# initilize interpreter with self locals
self.initInterpreter(locals())
from rlcompleter2 import Completer
self.completer = Completer()
def printBanner(self):
self.write(sys.version)
self.write(' on ' + sys.platform + '\n')
self.write('PyQt4 ' + PYQT_VERSION_STR + '\n')
# msg = 'Type !hist for a history view and !hist(n) history index recall'
# self.write(msg + '\n')
def marker(self):
if self.multiLine:
self.insertPlainText('... ')
else:
self.insertPlainText('>>> ')
def initInterpreter(self, interpreterLocals=None):
if interpreterLocals:
# when we pass in locals, we don't want it to be named "self"
# so we rename it with the name of the class that did the passing
# and reinsert the locals back into the interpreter dictionary
selfName = interpreterLocals['self'].__class__.__name__
interpreterLocalVars = interpreterLocals.pop('self')
self.interpreterLocals[selfName] = interpreterLocalVars
else:
self.interpreterLocals = interpreterLocals
self.interpreter = self.InteractiveInterpreter(self.interpreterLocals)
def updateInterpreterLocals(self, newLocals):
className = newLocals.__class__.__name__
self.interpreterLocals[className] = newLocals
def write(self, line):
self.insertPlainText(line)
self.ensureCursorVisible()
def clearCurrentBlock(self):
# block being current row
length = len(self.document().lastBlock().text()[4:])
if length == 0:
return None
else:
# should have a better way of doing this but I can't find it
[self.textCursor().deletePreviousChar() for x in xrange(length)]
return True
def recallHistory(self):
# used when using the arrow keys to scroll through history
self.clearCurrentBlock()
if self.historyIndex <> -1:
self.insertPlainText(self.history[self.historyIndex])
return True
def customCommands(self, command):
if command == '!hist': # display history
self.append('') # move down one line
# vars that are in the command are prefixed with ____CC and deleted
# once the command is done so they don't show up in dir()
backup = self.interpreterLocals.copy()
history = self.history[:]
history.reverse()
for i, x in enumerate(history):
iSize = len(str(i))
delta = len(str(len(history))) - iSize
line = line = ' ' * delta + '%i: %s' % (i, x) + '\n'
self.write(line)
self.updateInterpreterLocals(backup)
self.marker()
return True
if re.match('!hist\(\d+\)', command): # recall command from history
backup = self.interpreterLocals.copy()
history = self.history[:]
history.reverse()
index = int(command[6:-1])
self.clearCurrentBlock()
command = history[index]
if command[-1] == ':':
self.multiLine = True
self.write(command)
self.updateInterpreterLocals(backup)
return True
return False
def keyPressEvent(self, event):
if event.key() == Qt.Key_Tab:
line = str(self.document().lastBlock().text())[4:]
self.completer.construct(line)
if len(self.completer.rl_matches) == 1:
self.clearCurrentBlock()
self.insertPlainText(self.completer.rl_matches[0])
else:
print 'repeat:', self.completer.repeated
mod = self.completer.repeated % len(self.completer.completions)
if mod == 0:
# print '\n'.join(self.completer.rl_matches)
col_print(self.completer.rl_matches)
else:
print ' '
print '\n'.join(self.completer.rl_matches)
# print self.completer.rl_matches
self.marker()
self.insertPlainText(line)
return
if event.key() == Qt.Key_Escape:
# proper exit
self.interpreter.runIt('exit()')
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 qt version < 4.7, have to use position() - block().position()
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:
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)
# https://stackoverflow.com/a/30861871/2052889
def col_print(lines, term_width=90, indent=0, pad=2):
n_lines = len(lines)
if n_lines == 0:
return
col_width = max(len(line) for line in lines)
n_cols = int((term_width + pad - indent)/(col_width + pad))
n_cols = min(n_lines, max(1, n_cols))
col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1)
if (n_cols - 1) * col_len >= n_lines:
n_cols -= 1
cols = [lines[i*col_len: i*col_len + col_len] for i in range(n_cols)]
rows = list(zip(*cols))
rows_missed = zip(*[col[len(rows):] for col in cols[:-1]])
rows.extend(rows_missed)
for row in rows:
print(" "*indent + (" "*pad).join(line.ljust(col_width)
for line in row))
def main():
app = QApplication(sys.argv)
win = MyInterpreter(None)
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()