class CommandShell(QsciScintilla): def __init__(self, parent=None): super(CommandShell, self).__init__(parent) self.setMinimumHeight(50) self.setMaximumHeight(50) self.settings = QSettings() self.lex = QsciLexerPython(self) self.apis = QsciAPIs(self.lex) self.lex.setAPIs(self.apis) self.setLexers() self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.SendScintilla(QsciScintilla.SCI_SETVSCROLLBAR, 0) self.setFolding(0) self._start_prompt = _start_prompt self.prompt = self._start_prompt self.currentfunction = None self.setAutoCompletionSource(self.AcsAPIs) self.setAutoCompletionThreshold(1) self.setAutoCompletionReplaceWord(True) self.setCallTipsStyle(QsciScintilla.CallTipsNoContext) self.parent().installEventFilter(self) self.textChanged.connect(self.text_changed) self._lastcompletions = None def text_changed(self): if not self.get_data().strip(): return try: completions = command.completions_for_line(self.get_data()) if completions == self._lastcompletions: self.autoCompleteFromAPIs() return self._lastcompletions = completions self.apis.cancelPreparation() self.apis.clear() for value in completions: data = u"{}".format(value) self.apis.add(data) self.apis.prepare() except command.NoFunction: return def end(self): self.parent().removeEventFilter(self) self.close() def eventFilter(self, object, event): if event.type() == QEvent.Resize: self.adjust_size() return QWidget.eventFilter(self, object, event) def keyPressEvent(self, e): if e.key() in (Qt.Key_Return, Qt.Key_Enter): self.entered() elif e.key() == Qt.Key_Escape: self.close() elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete): _, newindex = self.getCursorPosition() if newindex > len(self.prompt): QsciScintilla.keyPressEvent(self, e) else: QsciScintilla.keyPressEvent(self, e) def show_prompt(self, prompt=_start_prompt, data=None): self.clear() if not prompt == _start_prompt: prompt += ":" text = prompt if data: text = prompt + str(data) self.setText(text) self.prompt = prompt self.move_cursor_to_end() def get_end_pos(self): """Return (line, index) position of the last character""" line = self.lines() - 1 return (line, len(self.text(line))) def move_cursor_to_end(self): """Move cursor to end of text""" line, index = self.get_end_pos() self.setCursorPosition(line, index) self.ensureCursorVisible() self.ensureLineVisible(line) def get_data(self): line = self.text() line = line[len(self.prompt):] return line def entered(self): line = self.get_data() if not self.currentfunction: try: gen = command.parse_line_data(line) except command.NoFunction: return if gen: self.currentfunction = gen line = None else: self.currentfunction = None self.show_prompt() return try: prompt, data = self.currentfunction.send(line) self.show_prompt(prompt, data) except StopIteration: self.currentfunction = None self.show_prompt() def setLexers(self): loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace") fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int) font = QFont(loadFont) font.setFixedPitch(True) font.setPointSize(fontSize) font.setStyleHint(QFont.TypeWriter) font.setStretch(QFont.SemiCondensed) font.setLetterSpacing(QFont.PercentageSpacing, 87.0) font.setBold(False) self.lex.setFont(font) self.lex.setDefaultFont(font) self.setLexer(self.lex) def adjust_size(self): fm = QFontMetrics(self.font()) self.setMaximumHeight(20) self.resize(self.parent().width(), 20) self.move(0, self.parent().height() - self.height()) def showEvent(self, event): self.adjust_size() self.show_prompt() self.setFocus() def activated(self): visible = self.isVisible() self.setVisible(not visible)
class APIs(QObject): """ Class implementing an API storage entity. @signal apiPreparationFinished() emitted after the API preparation has finished @signal apiPreparationCancelled() emitted after the API preparation has been cancelled @signal apiPreparationStarted() emitted after the API preparation has started """ def __init__(self, language, forPreparation = False, parent = None): """ Constructor @param language language of the APIs object (string) @param forPreparation flag indicating this object is just needed for a preparation process (boolean) @param parent reference to the parent object (QObject) """ QObject.__init__(self, parent) self.setObjectName("APIs_%s" % language) self.__inPreparation = False self.__language = language self.__forPreparation = forPreparation self.__lexer = Lexers.getLexer(self.__language) self.__apifiles = Preferences.getEditorAPI(self.__language) self.__apifiles.sort() if self.__lexer is None: self.__apis = None else: self.__apis = QsciAPIs(self.__lexer) self.connect(self.__apis, SIGNAL("apiPreparationFinished()"), self.__apiPreparationFinished) self.connect(self.__apis, SIGNAL("apiPreparationCancelled()"), self.__apiPreparationCancelled) self.connect(self.__apis, SIGNAL("apiPreparationStarted()"), self.__apiPreparationStarted) self.__loadAPIs() def __loadAPIs(self): """ Private method to load the APIs. """ if self.__apis.isPrepared(): # load a prepared API file if not self.__forPreparation and Preferences.getEditor("AutoPrepareAPIs"): self.prepareAPIs() self.__apis.loadPrepared() else: # load the raw files and prepare the API file if not self.__forPreparation and Preferences.getEditor("AutoPrepareAPIs"): self.prepareAPIs(ondemand = True) def reloadAPIs(self): """ Public method to reload the API information. """ if not self.__forPreparation and Preferences.getEditor("AutoPrepareAPIs"): self.prepareAPIs() self.__loadAPIs() def getQsciAPIs(self): """ Public method to get a reference to QsciAPIs object. @return reference to the QsciAPIs object (QsciAPIs) """ if not self.__forPreparation and Preferences.getEditor("AutoPrepareAPIs"): self.prepareAPIs() return self.__apis def __apiPreparationFinished(self): """ Private method called to save an API, after it has been prepared. """ res = self.__apis.savePrepared() self.__inPreparation = False self.emit(SIGNAL('apiPreparationFinished()')) def __apiPreparationCancelled(self): """ Private method called, after the API preparation process has been cancelled. """ self.__inPreparation = False self.emit(SIGNAL('apiPreparationCancelled()')) def __apiPreparationStarted(self): """ Private method called, when the API preparation process started. """ self.__inPreparation = True self.emit(SIGNAL('apiPreparationStarted()')) def prepareAPIs(self, ondemand = False, rawList = None): """ Public method to prepare the APIs if necessary. @keyparam ondemand flag indicating a requested preparation (boolean) @keyparam rawList list of raw API files (QStringList) """ if self.__apis is None or self.__inPreparation: return needsPreparation = False if ondemand: needsPreparation = True else: # check, if a new preparation is necessary preparedAPIs = self.__defaultPreparedName() if not preparedAPIs.isEmpty(): preparedAPIsInfo = QFileInfo(preparedAPIs) if not preparedAPIsInfo.exists(): needsPreparation = True else: preparedAPIsTime = preparedAPIsInfo.lastModified() apifiles = Preferences.getEditorAPI(self.__language) apifiles.sort() if self.__apifiles != apifiles: needsPreparation = True for apifile in apifiles: if QFileInfo(apifile).lastModified() > preparedAPIsTime: needsPreparation = True break if needsPreparation: # do the preparation self.__apis.clear() if rawList: apifiles = rawList else: apifiles = Preferences.getEditorAPI(self.__language) for apifile in apifiles: self.__apis.load(apifile) self.__apis.prepare() self.__apifiles = apifiles def cancelPreparation(self): """ Public slot to cancel the APIs preparation. """ self.__apis and self.__apis.cancelPreparation() def installedAPIFiles(self): """ Public method to get a list of installed API files. @return list of installed API files (QStringList) """ if self.__apis is not None: if Utilities.isWindowsPlatform(): qsciPath = os.path.join(Utilities.getPyQt4ModulesDirectory(), "qsci") if os.path.exists(qsciPath): # it's the installer if self.__lexer.lexer() is not None: apidir = os.path.join(qsciPath, "api", self.__lexer.lexer()) fnames = QStringList() filist = QDir(apidir).entryInfoList(["*.api"], QDir.Files, QDir.IgnoreCase) for fi in filist: fnames.append(fi.absoluteFilePath()) return fnames else: return QStringList() return self.__apis.installedAPIFiles() else: return QStringList() def __defaultPreparedName(self): """ Private method returning the default name of a prepared API file. @return complete filename for the Prepared APIs file (QString) """ if self.__apis is not None: return self.__apis.defaultPreparedName() else: return QString()