class PyEditor(QsciScintilla): def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.setTabWidth(4) self.setTabIndents(True) self.setIndentationsUseTabs(False) self._lexer = QsciLexerPython() self._lexer.setFont(QFont('DejaVu Sans Mono')) self._lexer.setIndentationWarning(QsciLexerPython.Tabs) # load current preview to lexer api = QsciAPIs(self._lexer) api.load('/tmp/preview.py') api.prepare() self.setLexer(self._lexer) self.setAutoCompletionSource(QsciScintilla.AcsAll) self.setAutoCompletionThreshold(2) self.setAutoIndent(True) self.setCaretForegroundColor(g.cursor_color) self.zoomTo(5)
class PythonEditor(BaseEditor): def __init__(self, parent=None, line_num_margin=3, autocomplete_list=None): super(PythonEditor, self).__init__(parent, line_num_margin, autocomplete_list) # Set Python lexer self.lexer = QsciLexerPython(self) self.lexer.setDefaultFont(self.editor_font) self.lexer.setFont(self.editor_font, QsciLexerPython.Comment) # Indentation warning ("The indentation is inconsistent when compared to the previous line") self.lexer.setIndentationWarning(QsciLexerPython.Inconsistent) # Set auto-completion self.api = QsciAPIs(self.lexer) if autocomplete_list is not None: # Add additional completion strings for i in autocomplete_list: self.api.add(i) self.api.prepare() self.setAutoCompletionThreshold(3) self.setAutoCompletionSource(QsciScintilla.AcsAll) self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit) self.setLexer(self.lexer) # PEP8 tabs self.setIndentationsUseTabs(False) self.setAutoIndent(True) self.setIndentationGuides(True) # PEP8 edge column line self.edgecol = 80 # Linters self.linter = 'internal' def clean_code(self): self.setText(autopep8.fix_code(self.text(), options={'aggressive': 2})) def check_code(self, path): self._clear_all_margin_markers() self.lint_data = {} try: warnings = linter.check(self.text(), os.path.basename(path)) for w in warnings: w.type = 'warning' key = w.lineno - 1 if key in self.lint_data.keys(): self.lint_data[key].append(w) else: self.lint_data[key] = [w] self._add_warn_margin_marker(w.lineno - 1) except linter.LinterSyntaxError as e: e.type = 'error' self.lint_data[e.lineno - 1] = e self._add_error_margin_marker(e.lineno - 1) except linter.LinterUnexpectedError as e: print(e) def margin_clicked(self, marnum, linenum, modifiers): if self._margin_popup.isVisible(): self._hide_margin_popup() else: try: warnings = self.lint_data[linenum] desc = '' if isinstance(warnings, linter.LinterError): desc = warnings.message self._show_margin_popup(desc.strip(), bg_color=self.colorErrorBackground) else: for warning in warnings: desc += warning.message % warning.message_args + '\n' self._show_margin_popup(desc.strip(), bg_color=self.colorWarnBackground) except KeyError: pass return True
class Editor(QsciScintilla): def __init__(self, parent=None): super(Editor,self).__init__(parent) self.parent = parent self.settings = QSettings() # Enable non-ascii chars for editor self.setUtf8(True) # Set the default font font = QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(10) self.setFont(font) self.setMarginsFont(font) # Margin 0 is used for line numbers #fm = QFontMetrics(font) #fontmetrics = QFontMetrics(font) self.setMarginsFont(font) self.setMarginWidth(1, "00000") self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor("#3E3EE3")) self.setMarginsBackgroundColor(QColor("#f9f9f9")) self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#fcf3ed")) # Clickable margin 1 for showing markers # self.setMarginSensitivity(1, True) # self.connect(self, # SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'), # self.on_margin_clicked) # self.markerDefine(QsciScintilla.RightArrow, # self.ARROW_MARKER_NUM) # self.setMarkerBackgroundColor(QColor("#ee1111"), # self.ARROW_MARKER_NUM) self.setMinimumHeight(120) #self.setMinimumWidth(300) # Folding self.setFolding(QsciScintilla.PlainFoldStyle) self.setFoldMarginColors(QColor("#f4f4f4"),QColor("#f4f4f4")) #self.setWrapMode(QsciScintilla.WrapCharacter) ## Edge Mode self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor("#FF0000")) #self.setWrapMode(QsciScintilla.WrapCharacter) self.setWhitespaceVisibility(QsciScintilla.WsVisibleAfterIndent) #self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.settingsEditor() # Annotations #self.setAnnotationDisplay(QsciScintilla.ANNOTATION_BOXED) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) self.setIndentationGuides(True) ## Disable command key ctrl, shift = self.SCMOD_CTRL<<16, self.SCMOD_SHIFT<<16 self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L')+ ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T')+ ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D')+ ctrl) #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z')+ ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y')+ ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L')+ ctrl+shift) ## New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete self.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.newShortcutCS.setContext(Qt.WidgetShortcut) self.newShortcutCS.activated.connect(self.autoCompleteKeyBinding) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.runSelectedCode) self.runScriptScut = QShortcut(QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_E), self) self.runScriptScut.setContext(Qt.WidgetShortcut) self.runScriptScut.activated.connect(self.runScriptCode) self.commentScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_3), self) self.commentScut.setContext(Qt.WidgetShortcut) self.commentScut.activated.connect(self.parent.pc.commentCode) self.uncommentScut = QShortcut(QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_3), self) self.uncommentScut.setContext(Qt.WidgetShortcut) self.uncommentScut.activated.connect(self.parent.pc.uncommentCode) def settingsEditor(self): # Set Python lexer self.setLexers() threshold = self.settings.value("pythonConsole/autoCompThresholdEditor", 2).toInt()[0] radioButtonSource = self.settings.value("pythonConsole/autoCompleteSourceEditor", 'fromAPI').toString() autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabledEditor", True).toBool() self.setAutoCompletionThreshold(threshold) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.setAutoCompletionSource(self.AcsDocument) elif radioButtonSource == 'fromAPI': self.setAutoCompletionSource(self.AcsAPIs) elif radioButtonSource == 'fromDocAPI': self.setAutoCompletionSource(self.AcsAll) else: self.setAutoCompletionSource(self.AcsNone) def autoCompleteKeyBinding(self): radioButtonSource = self.settings.value("pythonConsole/autoCompleteSourceEditor").toString() autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabledEditor").toBool() if autoCompEnabled: if radioButtonSource == 'fromDoc': self.autoCompleteFromDocument() elif radioButtonSource == 'fromAPI': self.autoCompleteFromAPIs() elif radioButtonSource == 'fromDocAPI': self.autoCompleteFromAll() def on_margin_clicked(self, nmargin, nline, modifiers): # Toggle marker for the line the margin was clicked on if self.markersAtLine(nline) != 0: self.markerDelete(nline, self.ARROW_MARKER_NUM) else: self.markerAdd(nline, self.ARROW_MARKER_NUM) def setLexers(self): from qgis.core import QgsApplication self.lexer = QsciLexerPython() self.lexer.setIndentationWarning(QsciLexerPython.Inconsistent) self.lexer.setFoldComments(True) self.lexer.setFoldQuotes(True) loadFont = self.settings.value("pythonConsole/fontfamilytextEditor", "Monospace").toString() fontSize = self.settings.value("pythonConsole/fontsizeEditor", 10).toInt()[0] 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.lexer.setDefaultFont(font) self.lexer.setColor(Qt.red, 1) self.lexer.setColor(Qt.darkGreen, 5) self.lexer.setColor(Qt.darkBlue, 15) self.lexer.setFont(font, 1) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) self.api = QsciAPIs(self.lexer) chekBoxAPI = self.settings.value("pythonConsole/preloadAPI", True).toBool() if chekBoxAPI: self.api.loadPrepared( QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap" ) else: apiPath = self.settings.value("pythonConsole/userAPI").toStringList() for i in range(0, len(apiPath)): self.api.load(QString(unicode(apiPath[i]))) self.api.prepare() self.lexer.setAPIs(self.api) self.setLexer(self.lexer) 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_end_pos(self): """Return (line, index) position of the last character""" line = self.lines() - 1 return (line, self.text(line).length()) def contextMenuEvent(self, e): menu = QMenu(self) iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png") iconCodePad = QgsApplication.getThemeIcon("console/iconCodepadConsole.png") iconNewEditor = QgsApplication.getThemeIcon("console/iconTabEditorConsole.png") iconCommentEditor = QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png") iconUncommentEditor = QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png") iconSettings = QgsApplication.getThemeIcon("console/iconSettingsConsole.png") hideEditorAction = menu.addAction("Hide Editor", self.hideEditor) menu.addSeparator() newTabAction = menu.addAction(iconNewEditor, "New Tab", self.parent.newTab, 'Ctrl+T') closeTabAction = menu.addAction("Close Tab", self.parent.close, 'Ctrl+W') menu.addSeparator() runSelected = menu.addAction(iconRun, "Enter selected", self.runSelectedCode, 'Ctrl+E') runScript = menu.addAction(iconRun, "Run Script", self.runScriptCode, 'Shift+Ctrl+E') menu.addSeparator() undoAction = menu.addAction("Undo", self.undo, QKeySequence.Undo) redoAction = menu.addAction("Redo", self.redo, QKeySequence.Redo) menu.addSeparator() cutAction = menu.addAction("Cut", self.cut, QKeySequence.Cut) copyAction = menu.addAction("Copy", self.copy, QKeySequence.Copy) pasteAction = menu.addAction("Paste", self.paste, QKeySequence.Paste) menu.addSeparator() commentCodeAction = menu.addAction(iconCommentEditor, "Comment", self.parent.pc.commentCode, 'Ctrl+3') uncommentCodeAction = menu.addAction(iconUncommentEditor, "Uncomment", self.parent.pc.uncommentCode, 'Shift+Ctrl+3') menu.addSeparator() codePadAction = menu.addAction(iconCodePad, "Share on codepad", self.codepad) menu.addSeparator() showCodeInspection = menu.addAction("Hide/Show Object list", self.objectListEditor) menu.addSeparator() selectAllAction = menu.addAction("Select All", self.selectAll, QKeySequence.SelectAll) menu.addSeparator() settingsDialog = menu.addAction(iconSettings, "Settings", self.parent.pc.openSettings) pasteAction.setEnabled(False) codePadAction.setEnabled(False) cutAction.setEnabled(False) runSelected.setEnabled(False) copyAction.setEnabled(False) selectAllAction.setEnabled(False) closeTabAction.setEnabled(False) undoAction.setEnabled(False) redoAction.setEnabled(False) if self.parent.mw.count() > 1: closeTabAction.setEnabled(True) if self.hasSelectedText(): runSelected.setEnabled(True) copyAction.setEnabled(True) cutAction.setEnabled(True) codePadAction.setEnabled(True) if not self.text() == '': selectAllAction.setEnabled(True) if self.isUndoAvailable(): undoAction.setEnabled(True) if self.isRedoAvailable(): redoAction.setEnabled(True) if QApplication.clipboard().text() != "": pasteAction.setEnabled(True) action = menu.exec_(self.mapToGlobal(e.pos())) def objectListEditor(self): listObj = self.parent.pc.listClassMethod if listObj.isVisible(): listObj.hide() self.parent.pc.objectListButton.setChecked(False) else: listObj.show() self.parent.pc.objectListButton.setChecked(True) def codepad(self): import urllib2, urllib listText = self.selectedText().split('\n') getCmd = [] for strLine in listText: if strLine != "": #if s[0:3] in (">>>", "..."): # filter for special command (_save,_clear) and comment if strLine[4] != "_" and strLine[:2] != "##": strLine.replace(">>> ", "").replace("... ", "") getCmd.append(unicode(strLine)) pasteText= u"\n".join(getCmd) url = 'http://codepad.org' values = {'lang' : 'Python', 'code' : pasteText, 'submit':'Submit'} try: response = urllib2.urlopen(url, urllib.urlencode(values)) url = response.read() for href in url.split("</a>"): if "Link:" in href: ind=href.index('Link:') found = href[ind+5:] for i in found.split('">'): if '<a href=' in i: link = i.replace('<a href="',"").strip() if link: QApplication.clipboard().setText(link) msgText = QCoreApplication.translate('PythonConsole', 'URL copied to clipboard.') self.parent.pc.callWidgetMessageBarEditor(msgText) except urllib2.URLError, e: msgText = QCoreApplication.translate('PythonConsole', 'Connection error: ') self.parent.pc.callWidgetMessageBarEditor(msgText + str(e.args))