Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
# fileview.py - File diff, content, and annotation display widget## Copyright 2010 Steve Borho <steve@borho.org>## This software may be used and distributed according to the terms of the# GNU General Public License version 2, incorporated herein by reference.importosimportdifflibimportrefrommercurialimporterror,utilfromtortoisehg.utilimporthglib,patchctx,colormap,thread2fromtortoisehg.hgqt.i18nimport_fromtortoisehg.hgqtimportqscilib,qtlib,blockmatcher,lexersfromtortoisehg.hgqtimportvisdiff,filedatafromPyQt4.QtCoreimport*fromPyQt4.QtGuiimport*fromPyQt4importQsciqsci=Qsci.QsciScintillaDiffMode=1FileMode=2AnnMode=3classHgFileView(QFrame):"file diff, content, and annotation viewer"diffHeaderRegExp=re.compile("^@@ -[0-9]+,[0-9]+ \+[0-9]+,[0-9]+ @@")linkActivated=pyqtSignal(QString)fileDisplayed=pyqtSignal(QString,QString)showMessage=pyqtSignal(QString)revisionSelected=pyqtSignal(int)shelveToolExited=pyqtSignal()grepRequested=pyqtSignal(unicode,dict)"""Emitted (pattern, opts) when user request to search changelog"""def__init__(self,repo,parent):QFrame.__init__(self,parent)framelayout=QVBoxLayout(self)framelayout.setContentsMargins(0,0,0,0)framelayout.setSpacing(0)l=QHBoxLayout()l.setContentsMargins(0,0,0,0)l.setSpacing(0)self.repo=repoself._diffs=[]self.topLayout=QVBoxLayout()self.labelhbox=hbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)hbox.setSpacing(2)self.topLayout.addLayout(hbox)self.diffToolbar=QToolBar(_('Diff Toolbar'))self.diffToolbar.setIconSize(QSize(16,16))hbox.addWidget(self.diffToolbar)self.filenamelabel=w=QLabel()w.setWordWrap(True)f=w.textInteractionFlags()w.setTextInteractionFlags(f|Qt.TextSelectableByMouse)w.linkActivated.connect(self.linkActivated)hbox.addWidget(w,1)self.extralabel=w=QLabel()w.setWordWrap(True)w.linkActivated.connect(self.linkActivated)self.topLayout.addWidget(w)w.hide()framelayout.addLayout(self.topLayout)framelayout.addLayout(l,1)hbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)hbox.setSpacing(0)l.addLayout(hbox)self.blk=blockmatcher.BlockList(self)self.sci=AnnotateView(repo,self)hbox.addWidget(self.blk)hbox.addWidget(self.sci,1)self.sci.showMessage.connect(self.showMessage)self.sci.setAnnotationEnabled(False)self.sci.setContextMenuPolicy(Qt.CustomContextMenu)self.sci.customContextMenuRequested.connect(self.menuRequest)self.blk.linkScrollBar(self.sci.verticalScrollBar())self.blk.setVisible(False)self.sci.setFrameStyle(0)self.sci.setReadOnly(True)self.sci.setUtf8(True)self.sci.installEventFilter(qscilib.KeyPressInterceptor(self))self.sci.setCaretLineVisible(False)# define markers for colorize zones of diffself.markerplus=self.sci.markerDefine(qsci.Background)self.markerminus=self.sci.markerDefine(qsci.Background)self.markertriangle=self.sci.markerDefine(qsci.Background)self.sci.setMarkerBackgroundColor(QColor('#B0FFA0'),self.markerplus)self.sci.setMarkerBackgroundColor(QColor('#A0A0FF'),self.markerminus)self.sci.setMarkerBackgroundColor(QColor('#FFA0A0'),self.markertriangle)# hide margin 0 (markers)self.sci.setMarginType(0,qsci.SymbolMargin)self.sci.setMarginWidth(0,0)self.searchbar=qscilib.SearchToolBar(hidable=True)self.searchbar.hide()self.searchbar.searchRequested.connect(self.find)self.searchbar.conditionChanged.connect(self.highlightText)self.layout().addWidget(self.searchbar)self._ctx=Noneself._filename=Noneself._status=Noneself._mode=Noneself._parent=0self._lostMode=Noneself._lastSearch=u'',Falseself.actionDiffMode=QAction(qtlib.geticon('view-diff'),_('View change as unified diff output'),self)self.actionDiffMode.setCheckable(True)self.actionDiffMode._mode=DiffModeself.actionFileMode=QAction(qtlib.geticon('view-file'),_('View change in context of file'),self)self.actionFileMode.setCheckable(True)self.actionFileMode._mode=FileModeself.actionAnnMode=QAction(qtlib.geticon('view-annotate'),_('annotate with revision numbers'),self)self.actionAnnMode.setCheckable(True)self.actionAnnMode._mode=AnnModeself.modeToggleGroup=QActionGroup(self)self.modeToggleGroup.addAction(self.actionDiffMode)self.modeToggleGroup.addAction(self.actionFileMode)self.modeToggleGroup.addAction(self.actionAnnMode)self.modeToggleGroup.triggered.connect(self.setMode)# Next/Prev diff (in full file mode)self.actionNextDiff=QAction(qtlib.geticon('go-down'),_('Next diff (alt+down)'),self)self.actionNextDiff.setShortcut('Alt+Down')self.actionNextDiff.triggered.connect(self.nextDiff)self.actionPrevDiff=QAction(qtlib.geticon('go-up'),_('Previous diff (alt+up)'),self)self.actionPrevDiff.setShortcut('Alt+Up')self.actionPrevDiff.triggered.connect(self.prevDiff)self.setMode(self.actionDiffMode)self.actionFirstParent=QAction('1',self)self.actionFirstParent.setCheckable(True)self.actionFirstParent.setChecked(True)self.actionFirstParent.setShortcut('CTRL+1')self.actionFirstParent.setToolTip(_('Show changes from first parent'))self.actionSecondParent=QAction('2',self)self.actionSecondParent.setCheckable(True)self.actionSecondParent.setShortcut('CTRL+2')self.actionSecondParent.setToolTip(_('Show changes from second parent'))self.parentToggleGroup=QActionGroup(self)self.parentToggleGroup.addAction(self.actionFirstParent)self.parentToggleGroup.addAction(self.actionSecondParent)self.parentToggleGroup.triggered.connect(self.setParent)self.actionFind=self.searchbar.toggleViewAction()self.actionFind.setIcon(qtlib.geticon('edit-find'))self.actionFind.setToolTip(_('Toggle display of text search bar'))self.actionFind.setShortcut(QKeySequence.Find)self.actionShelf=QAction('Shelve',self)self.actionShelf.setIcon(qtlib.geticon('shelve'))self.actionShelf.setToolTip(_('Open shelve tool'))self.actionShelf.triggered.connect(self.launchShelve)tb=self.diffToolbartb.addAction(self.actionFirstParent)tb.addAction(self.actionSecondParent)tb.addSeparator()tb.addAction(self.actionDiffMode)tb.addAction(self.actionFileMode)tb.addAction(self.actionAnnMode)tb.addSeparator()tb.addAction(self.actionNextDiff)tb.addAction(self.actionPrevDiff)tb.addSeparator()tb.addAction(self.actionFind)tb.addAction(self.actionShelf)self.timer=QTimer()self.timer.setSingleShot(False)self.timer.timeout.connect(self.timerBuildDiffMarkers)deflaunchShelve(self):fromtortoisehg.hgqtimportshelve# TODO: pass self._filenamedlg=shelve.ShelveDialog(self.repo,self)dlg.finished.connect(dlg.deleteLater)dlg.exec_()self.shelveToolExited.emit()defsetFont(self,font):self.sci.setFont(font)defloadSettings(self,qs,prefix):self.sci.loadSettings(qs,prefix)defsaveSettings(self,qs,prefix):self.sci.saveSettings(qs,prefix)defsetRepo(self,repo):self.repo=repoself.sci.repo=repo@pyqtSlot(QAction)defsetMode(self,action):'One of the mode toolbar buttons has been toggled'mode=action._modeself._lostMode=modeifmode!=self._mode:self._mode=modeself.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)self.blk.setVisible(mode!=DiffMode)self.sci.setAnnotationEnabled(mode==AnnMode)self.displayFile(self._filename,self._status)@pyqtSlot(QAction)defsetParent(self,action):ifaction.text()=='1':parent=0else:parent=1ifself._parent!=parent:self._parent=parentself.displayFile(self._filename,self._status)defrestrictModes(self,candiff,canfile,canann):'Disable modes based on content constraints'self.actionDiffMode.setEnabled(candiff)self.actionFileMode.setEnabled(canfile)self.actionAnnMode.setEnabled(canann)# Switch mode if necessarymode=self._modeifnotcandiffandmode==DiffModeandcanfile:mode=FileModeifnotcanfileandmode!=DiffMode:mode=DiffModeifself._lostModeisNone:self._lostMode=self._modeifself._mode!=mode:self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)self.blk.setVisible(mode!=DiffMode)self.sci.setAnnotationEnabled(mode==AnnMode)self._mode=modeifself._mode==DiffMode:self.actionDiffMode.setChecked(True)elifself._mode==FileMode:self.actionFileMode.setChecked(True)else:self.actionAnnMode.setChecked(True)defsetContext(self,ctx,ctx2=None):self._ctx=ctxself._ctx2=ctx2self.sci.setTabWidth(ctx._repo.tabwidth)self.actionAnnMode.setVisible(ctx.rev()!=None)self.actionShelf.setVisible(ctx.rev()==None)self.actionFirstParent.setVisible(len(ctx.parents())==2)self.actionSecondParent.setVisible(len(ctx.parents())==2)self.actionFirstParent.setEnabled(len(ctx.parents())==2)self.actionSecondParent.setEnabled(len(ctx.parents())==2)defshowLine(self,line):ifline<self.sci.lines():self.sci.setCursorPosition(line,0)@pyqtSlot()defclearDisplay(self):self._filename=Noneself._diffs=[]self.restrictModes(False,False,False)self.sci.setMarginWidth(1,0)self.clearMarkup()defclearMarkup(self):self.sci.clear()self.blk.clear()# Setting the label to ' ' rather than clear() keeps the label# from disappearing during refresh, and tool layouts bouncingself.filenamelabel.setText(' ')self.extralabel.hide()self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)defdisplayFile(self,filename=None,status=None):ifisinstance(filename,(unicode,QString)):filename=hglib.fromunicode(filename)status=hglib.fromunicode(status)iffilenameandself._filename==filename:# Get the last visible line to restore it after reloading the editorlastScrollPosition=self.sci.firstVisibleLine()else:# Reset the scroll positions when the file is changedlastScrollPosition=0self._filename,self._status=filename,statusself.clearMarkup()self._diffs=[]iffilenameisNone:self.restrictModes(False,False,False)returnifself._ctx2:ctx2=self._ctx2elifself._parent==0orlen(self._ctx.parents())==1:ctx2=self._ctx.p1()else:ctx2=self._ctx.p2()fd=filedata.FileData(self._ctx,ctx2,filename,status)iffd.elabel:self.extralabel.setText(fd.elabel)self.extralabel.show()else:self.extralabel.hide()self.filenamelabel.setText(fd.flabel)ifnotfd.isValid():self.sci.setText(fd.error)self.sci.setLexer(None)self.sci.setFont(qtlib.getfont('fontlog').font())self.sci.setMarginWidth(1,0)self.blk.setVisible(False)self.restrictModes(False,False,False)returncandiff=bool(fd.diff)canfile=bool(fd.contentsorfd.ucontents)canann=bool(fd.contents)andtype(self._ctx.rev())isintifnotcandiffornotcanfile:self.restrictModes(candiff,canfile,canann)else:self.actionDiffMode.setEnabled(True)self.actionFileMode.setEnabled(True)self.actionAnnMode.setEnabled(True)ifself._lostMode:self._mode=self._lostModeifself._lostMode==DiffMode:self.actionDiffMode.trigger()elifself._lostMode==FileMode:self.actionFileMode.trigger()elifself._lostMode==AnnMode:self.actionAnnMode.trigger()self._lostMode=Noneself.blk.setVisible(self._mode!=DiffMode)self.sci.setAnnotationEnabled(self._mode==AnnMode)ifself._mode==DiffMode:self.sci.setMarginWidth(1,0)lexer=lexers.get_diff_lexer(self)self.sci.setLexer(lexer)iflexerisNone:self.sci.setFont(qtlib.getfont('fontlog').font())# trim first three lines, for example:# diff -r f6bfc41af6d7 -r c1b18806486d tortoisehg/hgqt/thgrepo.py# --- a/tortoisehg/hgqt/thgrepo.py# +++ b/tortoisehg/hgqt/thgrepo.pyiffd.diff:out=fd.diff.split('\n',3)iflen(out)==4:self.sci.setText(hglib.tounicode(out[3]))else:# there was an error or rename without diffsself.sci.setText(hglib.tounicode(fd.diff))eliffd.ucontents:# subrepo summary and perhaps other dataself.sci.setText(fd.ucontents)self.sci.setLexer(None)self.sci.setFont(qtlib.getfont('fontlog').font())self.sci.setMarginWidth(1,0)self.blk.setVisible(False)returneliffd.contents:lexer=lexers.get_lexer(filename,fd.contents,self)self.sci.setLexer(lexer)iflexerisNone:self.sci.setFont(qtlib.getfont('fontlog').font())self.sci.setText(hglib.tounicode(fd.contents))self.blk.setVisible(True)self.sci._updatemarginwidth()ifself._mode==AnnMode:self.sci._updateannotation(self._ctx,filename)else:return# Recover the last scroll position# Make sure that lastScrollPosition never exceeds the amount of# lines on the editorlastScrollPosition=min(lastScrollPosition,self.sci.lines()-1)self.sci.verticalScrollBar().setValue(lastScrollPosition)self.highlightText(*self._lastSearch)uf=hglib.tounicode(filename)uc=hglib.tounicode(fd.contents)or''self.fileDisplayed.emit(uf,uc)ifself._mode!=DiffMode:self.blk.setVisible(True)self.blk.syncPageStep()iffd.contentsandfd.olddata:ifself.timer.isActive():self.timer.stop()self._fd=fdself.timer.start()self.actionNextDiff.setEnabled(bool(self._diffs))self.actionPrevDiff.setEnabled(bool(self._diffs))## These four functions are used by Shift+Cursor actions in revdetails#defnextLine(self):x,y=self.sci.getCursorPosition()self.sci.setCursorPosition(x+1,y)defprevLine(self):x,y=self.sci.getCursorPosition()self.sci.setCursorPosition(x-1,y)defnextCol(self):x,y=self.sci.getCursorPosition()self.sci.setCursorPosition(x,y+1)defprevCol(self):x,y=self.sci.getCursorPosition()self.sci.setCursorPosition(x,y-1)@pyqtSlot(unicode,bool,bool,bool)deffind(self,exp,icase=True,wrap=False,forward=True):self.sci.find(exp,icase,wrap,forward)@pyqtSlot(unicode,bool)defhighlightText(self,match,icase=False):self._lastSearch=match,icaseself.sci.highlightText(match,icase)defverticalScrollBar(self):returnself.sci.verticalScrollBar()## file mode diff markers#deftimerBuildDiffMarkers(self):'show modified and added lines in the self.blk margin'# The way the diff markers are generated differs between the DiffMode# and the other modes# In the DiffMode case, the marker positions are found by looking for# lines matching a regular expression representing a diff header, while# in all other cases we use the difflib.SequenceMatcher, which returns# a set of opcodes that must be parsed# In any case, the markers are generated incrementally. This function is# run by a timer, which each time that is called processes a bunch of# lines (when in DiffMode) or of opcodes (in all other modes).# When there are no more lines or opcodes to consume the timer is# stopped.self.sci.setUpdatesEnabled(False)self.blk.setUpdatesEnabled(False)ifself._mode==DiffMode:ifself._fd:self._fd=Noneself._diffs=[]self._linestoprocess=unicode(self.sci.text()).splitlines()self._firstlinetoprocess=0self._opcodes=True# Process linesPerBlock lines at a timelinesPerBlock=100# Look for lines matching the "diff header"forn,lineinenumerate(self._linestoprocess[:linesPerBlock]):ifself.diffHeaderRegExp.match(line):diffLine=self._firstlinetoprocess+nself._diffs.append([diffLine,diffLine])self.sci.markerAdd(diffLine,self.markerplus)self._linestoprocess=self._linestoprocess[linesPerBlock:]self._firstlinetoprocess+=linesPerBlockifnotself._linestoprocess:self._opcodes=Falseself._firstlinetoprocess=0else:ifself._fd:olddata=self._fd.olddata.splitlines()newdata=self._fd.contents.splitlines()diff=difflib.SequenceMatcher(None,olddata,newdata) self._opcodes = diff.get_opcodes()
self._fd = None
self._diffs = []
-else if isinstance(self._opcodes, bool):
+elif isinstance(self._opcodes, bool):
# catch self._mode changes while this thread is active
self._opcodes = []
fortag,alo,ahi,blo,bhiinself._opcodes[:30]:iftag=='replace':self._diffs.append([blo,bhi])self.blk.addBlock('x',blo,bhi)foriinrange(blo,bhi):self.sci.markerAdd(i,self.markertriangle)eliftag=='insert':self._diffs.append([blo,bhi])self.blk.addBlock('+',blo,bhi)foriinrange(blo,bhi):self.sci.markerAdd(i,self.markerplus)eliftagin('equal','delete'):passelse:raiseValueError,'unknown tag %r'%(tag,)self._opcodes=self._opcodes[30:]ifnotself._opcodes:self.actionNextDiff.setEnabled(bool(self._diffs))self.actionPrevDiff.setEnabled(False)self.timer.stop()self.sci.setUpdatesEnabled(True)self.blk.setUpdatesEnabled(True)defnextDiff(self):ifnotself._diffs:self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)returnelse:row,column=self.sci.getCursorPosition()fori,(lo,hi)inenumerate(self._diffs):iflo>row:last=(i==(len(self._diffs)-1))self.sci.setCursorPosition(lo,0)self.sci.verticalScrollBar().setValue(lo)breakelse:last=Trueself.actionNextDiff.setEnabled(notlast)self.actionPrevDiff.setEnabled(True)defprevDiff(self):ifnotself._diffs:self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)returnelse:row,column=self.sci.getCursorPosition()fori,(lo,hi)inenumerate(reversed(self._diffs)):ifhi<row:first=(i==(len(self._diffs)-1))self.sci.setCursorPosition(lo,0)self.sci.verticalScrollBar().setValue(lo)breakelse:first=Trueself.actionNextDiff.setEnabled(True)self.actionPrevDiff.setEnabled(notfirst)defnDiffs(self):returnlen(self._diffs)defeditSelected(self,path,rev,line):"""Open editor to show the specified file"""path=hglib.fromunicode(path)base=visdiff.snapshot(self.repo,[path],self.repo[rev])[0]files=[os.path.join(base,path)]pattern=hglib.fromunicode(self._lastSearch[0])qtlib.editfiles(self.repo,files,line,pattern,self)@pyqtSlot(QPoint)defmenuRequest(self,point):menu=self.sci.createStandardContextMenu()line=self.sci.lineAt(point)point=self.sci.viewport().mapToGlobal(point)selection=self.sci.selectedText()defsreq(**opts):returnlambda:self.grepRequested.emit(selection,opts)defsann():self.searchbar.search(selection)self.searchbar.show()ifself._mode!=AnnMode:ifselection:menu.addSeparator()forname,funcin[(_('Search in current file'),sann),(_('Search in history'),sreq(all=True))]:defadd(name,func):action=menu.addAction(name)action.triggered.connect(func)add(name,func)returnmenu.exec_(point)ifline<0orline>=len(self.sci._links):returnmenu.exec_(point)fctx,line=self.sci._links[line]ifselection:defsreq(**opts):returnlambda:self.grepRequested.emit(selection,opts)defsann():self.searchbar.search(selection)self.searchbar.show()menu.addSeparator()forname,funcin[(_('Search in original revision'),sreq(rev=fctx.rev())),(_('Search in working revision'),sreq(rev='.')),(_('Search in current annotation'),sann),(_('Search in history'),sreq(all=True))]:defadd(name,func):action=menu.addAction(name)action.triggered.connect(func)add(name,func)defsetSource(path,rev,line):self.revisionSelected.emit(rev)self.setContext(self.repo[rev])self.displayFile(path,None)self.showLine(line)data=[hglib.tounicode(fctx.path()),fctx.rev(),line]defannorig():setSource(*data)defeditorig():self.editSelected(*data)menu.addSeparator()forname,funcin[(_('Annotate originating revision'),annorig),(_('View originating revision'),editorig)]:defadd(name,func):action=menu.addAction(name)action.triggered.connect(func)add(name,func)forpfctxinfctx.parents():pdata=[hglib.tounicode(pfctx.path()),pfctx.changectx().rev(),line]defannparent(data):setSource(*data)defeditparent(data):self.editSelected(*data)forname,funcin[(_('Annotate parent revision %d')%pdata[1],annparent),(_('View parent revision %d')%pdata[1],editparent)]:defadd(name,func):action=menu.addAction(name)action.data=pdataaction.run=lambda:func(action.data)action.triggered.connect(action.run)add(name,func)menu.exec_(point)classAnnotateView(qscilib.Scintilla):'QScintilla widget capable of displaying annotations'showMessage=pyqtSignal(QString)def__init__(self,repo,parent=None):super(AnnotateView,self).__init__(parent)self.setReadOnly(True)self.setMarginLineNumbers(1,True)self.setMarginType(2,qsci.TextMarginRightJustified)self.setMouseTracking(False)self._annotation_enabled=Falseself._links=[]# by lineself._revmarkers={}# by revself._lastrev=Noneself._thread=AnnotateThread(self)self._thread.finished.connect(self.fillModel)self.repo=repoself.repo.configChanged.connect(self.configChanged)self.configChanged()defconfigChanged(self):self.setIndentationWidth(self.repo.tabwidth)self.setTabWidth(self.repo.tabwidth)defkeyPressEvent(self,event):ifevent.key()==Qt.Key_Escape:self._thread.abort()returnreturnsuper(AnnotateView,self).keyPressEvent(event)defmouseMoveEvent(self,event):self._emitRevisionHintAtLine(self.lineAt(event.pos()))super(AnnotateView,self).mouseMoveEvent(event)def_emitRevisionHintAtLine(self,line):ifline<0:returntry:fctx=self._links[line][0]iffctx.rev()!=self._lastrev:s=hglib.get_revision_desc(fctx,self.annfile)self.showMessage.emit(s)self._lastrev=fctx.rev()exceptIndexError:passdef_updateannotation(self,ctx,filename):ifctx.rev()isNone:returnwsub,filename,ctx=hglib.getDeepestSubrepoContainingFile(filename,ctx)ifwsubisNone:# The file was not found in the repo context or its subrepos# This may happen for files that have been removedreturnself.ctx=ctxself.annfile=filenameself._thread.abort()self._thread.start(ctx[filename])@pyqtSlot()deffillModel(self):self._thread.wait()ifself._thread.dataisNone:returnself._links=list(self._thread.data)self._updaterevmargin()self._updatemarkers()self._updatemarginwidth()defclear(self):super(AnnotateView,self).clear()self.clearMarginText()self.markerDeleteAll()defsetAnnotationEnabled(self,enabled):"""Enable / disable annotation"""self._annotation_enabled=enabledself._updatemarginwidth()self.setMouseTracking(enabled)ifnotenabled:self.markerDeleteAll()defisAnnotationEnabled(self):"""True if annotation enabled and available"""returnself._annotation_enableddef_updaterevmargin(self):"""Update the content of margin area showing revisions"""s=self._margin_style# Workaround to set style of the current sci widget.# QsciStyle sends style data only to the first sci widget.# See qscintilla2/Qt4/qscistyle.cppself.SendScintilla(qsci.SCI_STYLESETBACK,s.style(),s.paper())self.SendScintilla(qsci.SCI_STYLESETFONT,s.style(),s.font().family().toAscii().data())self.SendScintilla(qsci.SCI_STYLESETSIZE,s.style(),s.font().pointSize())fori,(fctx,_origline)inenumerate(self._links):self.setMarginText(i,str(fctx.rev()),s)def_updatemarkers(self):"""Update markers which colorizes each line"""self._redefinemarkers()fori,(fctx,_origline)inenumerate(self._links):m=self._revmarkers.get(fctx.rev())ifmisnotNone:self.markerAdd(i,m)def_redefinemarkers(self):"""Redefine line markers according to the current revs"""curdate=self.ctx.date()[0]# make sure to colorize at least 1 yearmindate=curdate-365*24*60*60self._revmarkers.clear()filectxs=iter(fctxforfctx,_origlineinself._links)palette=colormap.makeannotatepalette(filectxs,curdate,maxcolors=32,maxhues=8,maxsaturations=16,mindate=mindate)fori,(color,fctxs)inenumerate(palette.iteritems()):self.markerDefine(qsci.Background,i)self.setMarkerBackgroundColor(QColor(color),i)forfctxinfctxs:self._revmarkers[fctx.rev()]=i@util.propertycachedef_margin_style(self):"""Style for margin area"""s=Qsci.QsciStyle()s.setPaper(QApplication.palette().color(QPalette.Window))s.setFont(self.font())returns@pyqtSlot()def_updatemarginwidth(self):self.setMarginsFont(self.font())deflentext(s):return'M'*(len(str(s))+2)# 2 for marginself.setMarginWidth(1,lentext(self.lines()))ifself.isAnnotationEnabled()andself._links:maxrev=max(fctx.rev()forfctx,_origlineinself._links)self.setMarginWidth(2,lentext(maxrev))else:self.setMarginWidth(2,0)classAnnotateThread(QThread):'Background thread for annotating a file at a revision'def__init__(self,parent=None):super(AnnotateThread,self).__init__(parent)self._threadid=None@pyqtSlot(object)defstart(self,fctx):self._fctx=fctxsuper(AnnotateThread,self).start()self.data=None@pyqtSlot()defabort(self):ifself._threadidisNone:returntry:thread2._async_raise(self._threadid,KeyboardInterrupt)self.wait()exceptValueError:passdefrun(self):assertself.currentThread()!=qApp.thread()self._threadid=self.currentThreadId()try:try:data=[]for(fctx,line),_textinself._fctx.annotate(True,True):data.append((fctx,line))self.data=dataexceptKeyboardInterrupt:passfinally:self._threadid=Nonedelself._fctx
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.