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.importosimportdifflibfrommercurialimporterror,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"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.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.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()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()ifself._mode!=DiffModeandfd.contentsandfd.olddata:ifself.timer.isActive():self.timer.stop()self._fd=fdself.timer.start()## 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'self.sci.setUpdatesEnabled(False)self.blk.setUpdatesEnabled(False)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=Noneself._diffs=[]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):ifself._mode==DiffModeornotself._diffs:self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)returnrow,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):ifself._mode==DiffModeornotself._diffs:self.actionNextDiff.setEnabled(False)self.actionPrevDiff.setEnabled(False)returnrow,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): if ctx.rev() is None:
return
wsub, filename, ctx = hglib.getDeepestSubrepoContainingFile(filename, ctx)
-assertfilename in ctx+ifwsub is None:+ # The file was not found in the repo context or its subrepos+ # This may happen for files that have been removed+ return self.ctx = ctx
self.annfile = filename
self._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.