def __init__(self, lint, args, editor, results_iter, message): AbstractProcess.__init__(self, lint, args, editor) # self.lint = lint # self.args = args # self.editor = editor self.results_iter = results_iter self.message = message # Must be callable. # Set up styling for annotations. self.console.setAnnotationDisplay(2) self.font = Qt.QFont('Courier', 9, Qt.QFont.Normal, True) self.info = QsciStyle(-1, 'Hilite style for lint info', Qt.QColor('#222222'), Qt.QColor('#FFFFFF'), self.font) self.warning = QsciStyle(-1, 'Hilite style for lint warnings', Qt.QColor('#222222'), Qt.QColor('#FFFF44'), self.font) self.error = QsciStyle(-1, 'Hilite style for lint errors', Qt.QColor('#FFFFFF'), Qt.QColor('#EE0000'), self.font) self.severities = { 'I': self.info, 'C': self.info, 'W': self.warning, 'R': self.warning, 'E': self.error, 'F': self.error } self.connect(self, Qt.SIGNAL('results()'), self.apply_results) return
def __setRevisionText(self): " Sets the revision margin text " for revNumber in self.__revisionInfo: author = self.__revisionInfo[revNumber]['author'] if '@' in author: # Most probably this is an e-mail address. Leave just name. self.__revisionInfo[revNumber]['shortAuthor'] = author.split( '@')[0] else: self.__revisionInfo[revNumber]['shortAuthor'] = author skin = GlobalData().skin revisionMarginFont = QFont(skin.lineNumFont) revisionMarginFont.setItalic(True) style = QsciStyle(-1, "Revision margin style", skin.revisionMarginColor, skin.revisionMarginPaper, revisionMarginFont) lineNumber = 0 self.__maxLength = -1 # Altering line background support currentRevision = -1 needMarker = True for lineRevision in self.__lineRevisions: if lineRevision in self.__revisionInfo: marginText = " " + ":".join([ str(lineRevision), self.__revisionInfo[lineRevision]['shortAuthor'] ]) else: marginText = " " + str(lineRevision) textLength = len(marginText) if textLength > self.__maxLength: self.__maxLength = textLength self.setMarginText(lineNumber, marginText, style) # Set the line background if needed if lineRevision != currentRevision: currentRevision = lineRevision needMarker = not needMarker if needMarker: self.markerAdd(lineNumber, self.__alterMarker) lineNumber += 1 self.setRevisionMarginWidth() return
def __init__(self, distributedObjects, filename, parent): ScintillaWrapper.__init__(self, parent) self.breakpointOverlays = {} filename = str(filename) self.distributedObjects = distributedObjects self.debugController = self.distributedObjects.debugController self.__bpModel = self.distributedObjects.breakpointModel self.tracepointController = self.distributedObjects.tracepointController self.signalProxy = self.distributedObjects.signalProxy self.filename = filename self.lastContextMenuLine = 0 self.markerBp = QPixmap(":/markers/bp.png") self.markerBpDisabled = QPixmap(":/markers/bp_dis.png") self.markerTp = QPixmap(":/markers/tp.png") self.markerExec = QPixmap(":/markers/exec_pos.png") self.markerStack = QPixmap(":/markers/stack_pos.png") self.markerExecSignal = QPixmap(":/markers/exec_pos_signal.png") self.shown = False self.setToolTip("") self.setWhatsThis("") self.setMarginLineNumbers(self.MARGIN_NUMBERS, True) # set sensitivity self.setMarginSensitivity(self.MARGIN_NUMBERS, True) self.setMarginSensitivity(self.MARGIN_MARKER_BP, True) self.setMarginSensitivity(self.MARGIN_MARKER_TP, True) # define symbol self.markerDefine(self.markerBp, self.MARGIN_MARKER_BP) self.markerDefine(self.markerBpDisabled, self.MARGIN_MARKER_BP_DIS) self.markerDefine(self.markerTp, self.MARGIN_MARKER_TP) self.markerDefine(self.markerExec, self.MARGIN_MARKER_EXEC) self.markerDefine(self.markerStack, self.MARGIN_MARKER_STACK) self.markerDefine(self.markerExecSignal, self.MARGIN_MARKER_EXEC_SIGNAL) self.markerDefine(QsciScintilla.Background, self.MARKER_HIGHLIGHTED_LINE) # define width and mask to show margin self.setMarginWidth(self.MARGIN_MARKER_BP, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_BP, 1 << self.MARGIN_MARKER_BP | 1 << self.MARGIN_MARKER_BP_DIS) self.setMarginWidth(self.MARGIN_MARKER_TP, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_TP, 1 << self.MARGIN_MARKER_TP) self.setMarginWidth(self.MARGIN_MARKER_EXEC, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_EXEC, 1 << self.MARGIN_MARKER_EXEC | 1 << self.MARGIN_MARKER_EXEC_SIGNAL | 1 << self.MARGIN_MARKER_STACK) self.setMarginWidth(self.MARKER_HIGHLIGHTED_LINE, 0) self.setMarginMarkerMask(self.MARKER_HIGHLIGHTED_LINE, 1 << self.MARKER_HIGHLIGHTED_LINE) self.INDICATOR_TOOLTIP = self.indicatorDefine(self.BoxIndicator) self.setIndicatorDrawUnder(True, self.INDICATOR_TOOLTIP) self.setReadOnly(False) self.modificationChanged.connect(self.__setFileModified) self.SendScintilla(QsciScintilla.SCI_SETMOUSEDWELLTIME, 500) # override scintillas context menu with our own self.SendScintilla(QsciScintilla.SCI_USEPOPUP, 0) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showContextMenu) self.marginClicked.connect(self.onMarginClicked) self.SCN_DOUBLECLICK.connect(self.editDoubleClicked) self.dwellStart.connect(self.onDwellStart) self.dwellEnd.connect(self.onDwellEnd) self.__bpModel.rowsInserted.connect(self.breakpointsInserted) # don't connect to rowsRemoved here since the breakpoint is already gone # from the model when it's emitted self.__bpModel.rowsAboutToBeRemoved.connect(self.breakpointsRemoved) self.__bpModel.dataChanged.connect(self.breakpointsModified) _model = self.tracepointController.model() _model.rowsInserted.connect(self.getTracepointsFromModel) _model.rowsRemoved.connect(self.getTracepointsFromModel) act = self.distributedObjects.actions act.ToggleTrace.triggered.connect(self.toggleTracepoint) self.__allowToolTip = True self.__enableToolTip(True) self.__popupMenu = None self.__disAsmStyle = QsciStyle() self.__fileWatcher = QFileSystemWatcher([self.filename]) self.__fileWatcher.fileChanged.connect(self.__fileChanged) # this timer is used for a workaround: QFileSystemWatcher will sometimes # report a change multiple times; therefore, in self.__fileChanged, we # simply start the timer on a notification and discard all notifications # while the timer is running self.__fileChangedTimer = QTimer() self.__fileChangedTimer.setSingleShot(True) self.__fileChangedTimer.setInterval(100) ScintillaWrapper.init(self, distributedObjects) self.setLexer(QsciLexerCPP()) self.openFile()
class OpenedFileView(ScintillaWrapper): MARGIN_NUMBERS, MARGIN_MARKER_FOLD, MARGIN_MARKER_BP, MARGIN_MARKER_TP, MARGIN_MARKER_EXEC, \ MARGIN_MARKER_EXEC_SIGNAL, MARKER_HIGHLIGHTED_LINE, MARGIN_MARKER_STACK, MARGIN_MARKER_BP_DIS = range(9) def __init__(self, distributedObjects, filename, parent): ScintillaWrapper.__init__(self, parent) self.breakpointOverlays = {} filename = str(filename) self.distributedObjects = distributedObjects self.debugController = self.distributedObjects.debugController self.__bpModel = self.distributedObjects.breakpointModel self.tracepointController = self.distributedObjects.tracepointController self.signalProxy = self.distributedObjects.signalProxy self.filename = filename self.lastContextMenuLine = 0 self.markerBp = QPixmap(":/markers/bp.png") self.markerBpDisabled = QPixmap(":/markers/bp_dis.png") self.markerTp = QPixmap(":/markers/tp.png") self.markerExec = QPixmap(":/markers/exec_pos.png") self.markerStack = QPixmap(":/markers/stack_pos.png") self.markerExecSignal = QPixmap(":/markers/exec_pos_signal.png") self.shown = False self.setToolTip("") self.setWhatsThis("") self.setMarginLineNumbers(self.MARGIN_NUMBERS, True) # set sensitivity self.setMarginSensitivity(self.MARGIN_NUMBERS, True) self.setMarginSensitivity(self.MARGIN_MARKER_BP, True) self.setMarginSensitivity(self.MARGIN_MARKER_TP, True) # define symbol self.markerDefine(self.markerBp, self.MARGIN_MARKER_BP) self.markerDefine(self.markerBpDisabled, self.MARGIN_MARKER_BP_DIS) self.markerDefine(self.markerTp, self.MARGIN_MARKER_TP) self.markerDefine(self.markerExec, self.MARGIN_MARKER_EXEC) self.markerDefine(self.markerStack, self.MARGIN_MARKER_STACK) self.markerDefine(self.markerExecSignal, self.MARGIN_MARKER_EXEC_SIGNAL) self.markerDefine(QsciScintilla.Background, self.MARKER_HIGHLIGHTED_LINE) # define width and mask to show margin self.setMarginWidth(self.MARGIN_MARKER_BP, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_BP, 1 << self.MARGIN_MARKER_BP | 1 << self.MARGIN_MARKER_BP_DIS) self.setMarginWidth(self.MARGIN_MARKER_TP, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_TP, 1 << self.MARGIN_MARKER_TP) self.setMarginWidth(self.MARGIN_MARKER_EXEC, 10) self.setMarginMarkerMask(self.MARGIN_MARKER_EXEC, 1 << self.MARGIN_MARKER_EXEC | 1 << self.MARGIN_MARKER_EXEC_SIGNAL | 1 << self.MARGIN_MARKER_STACK) self.setMarginWidth(self.MARKER_HIGHLIGHTED_LINE, 0) self.setMarginMarkerMask(self.MARKER_HIGHLIGHTED_LINE, 1 << self.MARKER_HIGHLIGHTED_LINE) self.INDICATOR_TOOLTIP = self.indicatorDefine(self.BoxIndicator) self.setIndicatorDrawUnder(True, self.INDICATOR_TOOLTIP) self.setReadOnly(False) self.modificationChanged.connect(self.__setFileModified) self.SendScintilla(QsciScintilla.SCI_SETMOUSEDWELLTIME, 500) # override scintillas context menu with our own self.SendScintilla(QsciScintilla.SCI_USEPOPUP, 0) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showContextMenu) self.marginClicked.connect(self.onMarginClicked) self.SCN_DOUBLECLICK.connect(self.editDoubleClicked) self.dwellStart.connect(self.onDwellStart) self.dwellEnd.connect(self.onDwellEnd) self.__bpModel.rowsInserted.connect(self.breakpointsInserted) # don't connect to rowsRemoved here since the breakpoint is already gone # from the model when it's emitted self.__bpModel.rowsAboutToBeRemoved.connect(self.breakpointsRemoved) self.__bpModel.dataChanged.connect(self.breakpointsModified) _model = self.tracepointController.model() _model.rowsInserted.connect(self.getTracepointsFromModel) _model.rowsRemoved.connect(self.getTracepointsFromModel) act = self.distributedObjects.actions act.ToggleTrace.triggered.connect(self.toggleTracepoint) self.__allowToolTip = True self.__enableToolTip(True) self.__popupMenu = None self.__disAsmStyle = QsciStyle() self.__fileWatcher = QFileSystemWatcher([self.filename]) self.__fileWatcher.fileChanged.connect(self.__fileChanged) # this timer is used for a workaround: QFileSystemWatcher will sometimes # report a change multiple times; therefore, in self.__fileChanged, we # simply start the timer on a notification and discard all notifications # while the timer is running self.__fileChangedTimer = QTimer() self.__fileChangedTimer.setSingleShot(True) self.__fileChangedTimer.setInterval(100) ScintillaWrapper.init(self, distributedObjects) self.setLexer(QsciLexerCPP()) self.openFile() def updateConfig(self): if not ScintillaWrapper.updateConfig(self): return False # check whether we're supposed to use overlays and reload everything # that uses them qs = QsciScintilla c = self.distributedObjects.editorController.config l = self.lexer() self.setFolding(qs.BoxedTreeFoldStyle if c.folding.value else qs.NoFoldStyle, self.MARGIN_MARKER_FOLD) self.setMarkerBackgroundColor(QColor(c.highlightColor.value), self.MARKER_HIGHLIGHTED_LINE) l.setColor(QColor(c.preprocessorColor.value), l.PreProcessor) l.setColor(QColor(c.commentColor.value), l.CommentLine) l.setColor(QColor(c.commentColor.value), l.CommentDoc) self.__disAsmStyle.setFont(formlayout.tuple_to_qfont(self.distributedObjects.editorController.config.font.value)) # make the annotation's background slightly shaded with the identifier color bg = QColor(self.distributedObjects.editorController.config.backgroundColor.value) fg = QColor(self.distributedObjects.editorController.config.identifierColor.value) self.__disAsmStyle.setPaper(mixColor(bg, .8, fg)) self.__disAsmStyle.setColor(fg) self.__useBreakpointOverlays = c.useBreakpointOverlays.value self.getBreakpointsFromModel() self.setDisassemble(self.distributedObjects.editorController.config.showDisassemble.value) return True def __fileChanged(self): if not self.__fileChangedTimer.isActive(): logging.warning("Source file %s modified. Recompile executable for correct debugging.", self.filename) self.__fileChangedTimer.start() def saveFile(self): ''' Save source file ''' if (QFile.exists(self.filename)): f = open(self.filename, 'w') f.write(self.text()) f.close() self.openFile() def openFile(self): if not (QFile.exists(self.filename)): logging.error("Could not open file %s", self.filename) self.file_ = QFile(self.filename) self.file_.open(QIODevice.ReadOnly | QIODevice.Text) self.read(self.file_) self.file_.close() self.setMarginWidthByLineNumbers() self.__setFileModified(False) # read all breakpoints and tracepoints from the model self.getTracepointsFromModel() self.getBreakpointsFromModel() def __setFileModified(self, modified): ''' Method called whenever current file is marked as modified ''' self.distributedObjects.signalProxy.fileModified.emit(self.filename, modified) def onDwellStart(self, pos, x, y): if self.__allowToolTip: exp, (line, start, _) = self.getWordOrSelectionAndRangeFromPosition(pos) # try evaluating the expression before doing anything else: this will return None if the # expression is not valid (ie. something that is not a variable) if self.debugController.evaluateExpression(exp.strip()) is not None: startPos = self.positionFromLineIndex(line, start) x = self.SendScintilla(QsciScintilla.SCI_POINTXFROMPOSITION, 0, startPos) y = self.SendScintilla(QsciScintilla.SCI_POINTYFROMPOSITION, 0, startPos) self.distributedObjects.toolTipController.showToolTip(exp, QPoint(x + 3, y + 3 + self.textHeight(line)), self) def onDwellEnd(self, _1, _2, _3): self.distributedObjects.toolTipController.hideToolTip() def showContextMenu(self, point): scipos = self.SendScintilla( QsciScintilla.SCI_POSITIONFROMPOINT, point.x(), point.y()) point = self.mapToGlobal(point) exp, _ = self.getWordOrSelectionAndRangeFromPosition(scipos) # self.lineIndexFromPosition(..) returns tuple. first element is line self.lastContextMenuLine = int(self.lineIndexFromPosition(scipos)[0]) self.__popupMenu = QMenu(self) self.__popupMenu.addAction(self.distributedObjects.actions.ToggleTrace) if exp: self.__popupMenu.addAction(self.distributedObjects.actions.getAddToWatchAction(exp, self.signalProxy.addWatch)) self.__popupMenu.addAction(self.distributedObjects.actions.getAddToDatagraphAction(exp, self.distributedObjects.datagraphController.addWatch)) self.__popupMenu.addAction(self.distributedObjects.actions.getAddWatchpointAction(exp, self.distributedObjects.breakpointModel.insertWatchpoint)) listOfTracepoints = self.tracepointController.getTracepointsFromModel() if listOfTracepoints: subPopupMenu = QMenu(self) subPopupMenu.setTitle("Add variable " + exp + " to tracepoint...") for tp in listOfTracepoints: subPopupMenu.addAction(self.distributedObjects.actions.getAddToTracepointAction(exp, tp.name, tp.addVar)) self.__popupMenu.addSeparator() self.__popupMenu.addMenu(subPopupMenu) self.__popupMenu.popup(point) # disable the tooltips while the menu is shown self.__enableToolTip(False) self.__popupMenu.aboutToHide.connect(lambda: self.__enableToolTip(True)) def __enableToolTip(self, enable): self.__allowToolTip = enable def isPositionInsideSelection(self, position): lf, cf, lt, ct = self.getSelection() pl, pc = self.lineIndexFromPosition(position) if lf < pl and pl < lt: return True elif lf == pl and pl < lt: return True if cf <= pc else False elif lf < pl and pl == lt: return True if pc <= ct else False elif lf == pl and pl == lt: return True if (cf <= pc and pc <= ct) else False else: return False def getWordOrSelectionAndRangeFromPosition(self, position): if self.isPositionInsideSelection(position): line, start, lineTo, end = self.getSelection() if line != lineTo: return "", (None, None, None) else: line, start, end = self.getWordRangeFromPosition(position) return self.getWordFromRange(line, start, end), (line, start, end) def getWordRangeFromPosition(self, position): line, col = self.lineIndexFromPosition(position) start, end = self.getWordRangeFromLineCol(line, col) return line, start, end def getWordRangeFromLineCol(self, line, col): s = str(self.text(line)) start = col - 1 end = col a = 0 while start >= 0: if s[start].isalnum() or s[start] in [".", "_"]: pass elif s[start] == ">" and start >= 1 and s[start - 1] == "-": start -= 1 elif s[start] == "]": a -= 1 elif s[start] == "[": a += 1 else: break start -= 1 start += 1 while end < len(s): if a >= 0: pass if s[end].isalnum() or s[end] == "_": pass elif s[end] == "]": a -= 1 else: break end += 1 if a == 0: return start, end else: return 0, 0 def getWordFromLineCol(self, line, col): self.clearIndicatorRange(0, 0, self.lines(), 1, self.INDICATOR_TOOLTIP) start, end = self.getWordRangeFromLineCol(line, col) word = self.getWordFromRange(line, start, end) if word: for i, line in enumerate(self.text().split('\n')): for match in re.finditer(r"\b%s\b" % word, line): self.fillIndicatorRange(i, match.start(), i, match.end(), self.INDICATOR_TOOLTIP) def getWordFromRange(self, line, start, end): return str(self.text(line))[start:end] def editDoubleClicked(self, position, line, modifiers): line, start, end = self.getWordRangeFromPosition(position) w = str(self.text(line))[start:end] if w: self.signalProxy.addWatch(w) def showExecutionPosition(self, line): self.markerAdd(line, self.MARGIN_MARKER_EXEC) self.showLine(line) def showSignalPosition(self, line): self.markerAdd(line, self.MARGIN_MARKER_EXEC_SIGNAL) self.showLine(line) def showLine(self, line): self.setCursorPosition(line, 1) self.ensureLineVisible(line) def clearExecutionPositionMarkers(self): self.markerDeleteAll(self.MARGIN_MARKER_EXEC) def setMarginWidthByLineNumbers(self): self.setMarginWidth(0, ceil(log(self.lines(), 10)) * 10 + 5) def onMarginClicked(self, margin, line, _): # if breakpoint should be toggled if margin == self.MARGIN_NUMBERS or margin == self.MARGIN_MARKER_BP: self.toggleBreakpointWithLine(line) elif margin == self.MARGIN_MARKER_TP: self.toggleTracepointWithLine(line) def toggleBreakpointWithLine(self, line): self.__bpModel.toggleBreakpoint(self.filename, line + 1) def toggleTracepointWithLine(self, line): self.tracepointController.toggleTracepoint(self.filename, line + 1) def toggleTracepoint(self): self.toggleTracepointWithLine(self.lastContextMenuLine) def getBreakpointsFromModel(self): self.markerDeleteAll(self.MARGIN_MARKER_BP) self.markerDeleteAll(self.MARGIN_MARKER_BP_DIS) self.removeAllOverlayWidgets() self.breakpointOverlays = {} for bp in self.__bpModel.breakpoints: if bp.fullname == self.filename: self.markerAdd(bp.line - 1, self.MARGIN_MARKER_BP if bp.enabled else self.MARGIN_MARKER_BP_DIS) self.__addBreakpointOverlay(bp) def __addBreakpointOverlay(self, bp): if not self.__useBreakpointOverlays: return l = BreakpointOverlayWidget(self.viewport(), self.distributedObjects, bp, self.__bpModel) self.breakpointOverlays[bp.number] = l self.__updateBreakpointOverlay(bp) l.show() self.addOverlayWidget(l, int(bp.line), None, 50, 400) def __updateBreakpointOverlay(self, bp): if not self.__useBreakpointOverlays: return w = self.breakpointOverlays[bp.number] w.update() def __removeBreakpointOverlay(self, bp): if not self.__useBreakpointOverlays: return self.removeOverlayWidget(self.breakpointOverlays[bp.number], bp.line) def __validBreakpoints(self, startRow, endRow): for i in range(startRow, endRow + 1): # the column has no meaning here, all columns will return the # breakpoint object for role InternalDataRole bp = self.__bpModel.data(self.__bpModel.index(i, 0), self.__bpModel.InternalDataRole) if not bp.fullname == self.filename: continue yield bp def breakpointsInserted(self, _, start, end): for bp in self.__validBreakpoints(start, end): self.markerAdd(bp.line - 1, self.MARGIN_MARKER_BP if bp.enabled else self.MARGIN_MARKER_BP_DIS) self.__addBreakpointOverlay(bp) def breakpointsRemoved(self, _, start, end): for bp in self.__validBreakpoints(start, end): self.markerDelete(bp.line - 1, self.MARGIN_MARKER_BP) self.markerDelete(bp.line - 1, self.MARGIN_MARKER_BP_DIS) self.__removeBreakpointOverlay(bp) def breakpointsModified(self, topLeft, bottomRight): for bp in self.__validBreakpoints(topLeft.row(), bottomRight.row()): self.markerDelete(bp.line - 1, self.MARGIN_MARKER_BP) self.markerDelete(bp.line - 1, self.MARGIN_MARKER_BP_DIS) self.markerAdd(bp.line - 1, self.MARGIN_MARKER_BP if bp.enabled else self.MARGIN_MARKER_BP_DIS) self.__updateBreakpointOverlay(bp) def getTracepointsFromModel(self): """Get tracepoints from model.""" self.markerDeleteAll(self.MARGIN_MARKER_TP) for tp in self.tracepointController.getTracepointsFromModel(): if tp.fullname == self.filename: self.markerAdd(int(tp.line) - 1, self.MARGIN_MARKER_TP) def highlightLine(self, line): self.removeHighlightedLines() self.markerAdd(line, self.MARKER_HIGHLIGHTED_LINE) QTimer.singleShot(int(self.distributedObjects.editorController.config.highlightingDuration.value), self.removeHighlightedLines) def removeHighlightedLines(self): self.markerDeleteAll(self.MARKER_HIGHLIGHTED_LINE) def setDisassemble(self, enable): self.clearAnnotations() if not enable: return ret = self.distributedObjects.gdb_connector.disassemble(self.filename) for i in ret.asm_insns: assert i.dest=="src_and_asm_line" insns = "\n".join((j.address + " "*4 + j.inst for j in i.src.line_asm_insn)) if insns: self.annotate(int(i.src.line)-1, insns, self.__disAsmStyle)