Ability to specify line to be active while using log cmd

19 views
Skip to first unread message

Artemr Rudenko

unread,
May 21, 2013, 9:16:13 AM5/21/13
to thg...@googlegroups.com
Hi all,

This is my very first time and change and i'd like to add it into the thg-build. I don't asking you to implement this - I have implemented this already. I will be thankfull if anyone will say me on whether it's OK to add this feature into main thg build.
First of all i will try to explain you what my manager asked me to do - one day he said - can you please modify 'log' cmd in order to extend it's posibilities or not. He said let's add the argument 'n' so when user will type: 'thg log -n10 <filename>' then the 'HG file log viewer' wnd will be opened in 'Annotate Mode' and the specified line will be active. Also he asked me to read into memory active line revision details. 
So what will you say about this feature? If you will said it's OK i will try to post here code to review - there is just few lines which are needed for this feature

Best Regards,
Artem

Yuya Nishihara

unread,
May 23, 2013, 10:10:59 AM5/23/13
to thg...@googlegroups.com
On Tue, 21 May 2013 06:16:13 -0700 (PDT), Artemr Rudenko wrote:
> type: 'thg log -n10 <filename>' then the 'HG file log viewer' wnd will be
> opened in 'Annotate Mode' and the specified line will be active. Also he
> asked me to read into memory active line revision details.
> So what will you say about this feature? If you will said it's OK i will
> try to post here code to review - there is just few lines which are needed
> for this feature

It might be useful.

Regards,

Artemr Rudenko

unread,
Jun 6, 2013, 4:38:59 AM6/6/13
to thg...@googlegroups.com
Hi all, 
Since i made several merge operations wrong i can post my changed here only this way for now. If it strongly not acceptable i will try to find the way how to post changes the way it needed. Below are filenames, class names and methods modified:

filedialogs.py:


class FileLogDialog(_AbstractFileDialog):
    """ 
        A dialog showing a revision graph for a file. 
    """ 

    def __init__(self, repo, filename, repoviewer=None, line=0, annotate=False):
        self.line = line
        self.annotate = annotate 

    def onRevisionSelected(self, rev): 
        pos = self.textView.verticalScrollBar().value() 
        ctx = self.filerevmodel.repo.changectx(rev) 
        self.textView.setContext(ctx) 
        self.textView.displayFile(self.filerevmodel.graph.filename(rev), None) 
        self.textView.verticalScrollBar().setValue(pos) 
        self.revpanel.set_revision(rev) 
        self.revpanel.update(repo = self.repo) 
        (self.line and self.textView.changeActiveViewMode('annotate'))  # if line specified than switch to 'Annotate Mode'
        self.textView.displayFile(self.filerevmodel.graph.filename(rev), None, line=self.line)  # After mode is switched reload file and activate the line specified


fileview.py


class HgFileView(QFrame):
    "file diff, content, and annotation viewer"

    def setSource(self, path, rev, line):
        self.revisionSelected.emit(rev) 
        self.setContext(self.repo[rev]) 
        self.displayFile(path, None) 
        self.showLine(line)

    def changeActiveViewMode(self, mode):  # changes the mode to the specified 
        if mode.lower() == 'annotate': 
            self._setModeByAction(self.actionAnnMode) 
        elif mode.lower() == 'diff': 
            self._setModeByAction(self.actionDiffMode) 
        else: 
            self._setModeByAction(self.actionFileMode) 

    def showLine(self, line):
        if line < self.sci.lines(): 
            self.sci.setCursorPosition(line, 0) 


    def displayFile(self, filename=None, status=None, force=False, line=0):

        if isinstance(filename, (unicode, QString)):

            filename = hglib.fromunicode(filename)

            status = hglib.fromunicode(status)

        if filename and self._filename == filename:

            # Get the last visible line to restore it after reloading the editor

            lastCursorPosition = self.sci.getCursorPosition()

            lastScrollPosition = self.sci.firstVisibleLine()

        else:

            lastCursorPosition = (0, 0)

            lastScrollPosition = 0

        self._filename, self._status = filename, status

        self.clearMarkup()

        self._diffs = []

        if filename is None:

            self.restrictModes(False, False, False)

            return

        if self._ctx2:

            ctx2 = self._ctx2

        elif self._parent == 0 or len(self._ctx.parents()) == 1:

            ctx2 = self._ctx.p1()

        else:

            ctx2 = self._ctx.p2()

        fd = filedata.FileData(self._ctx, ctx2, filename, status, self.changeselection, force=force)

        if fd.elabel:

            self.extralabel.setText(fd.elabel)

            self.extralabel.show()

        else:

            self.extralabel.hide()

        self.filenamelabel.setText(fd.flabel)

        uf = hglib.tounicode(filename)

        if not fd.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)

            self.newChunkList.emit(uf, None)

            forcedisplaymsg = filedata.forcedisplaymsg

            linkstart = fd.error.find(forcedisplaymsg)

            if linkstart >= 0:

                # add the link to force to view the data anyway

                self._setupForceViewIndicator()

                self.sci.fillIndicatorRange(

                    0, linkstart, 0, linkstart+len(forcedisplaymsg), self._forceviewindicator)

            return

        candiff = bool(fd.diff)

        canfile = bool(fd.contents or fd.ucontents)

        canann = bool(fd.contents) and type(self._ctx.rev()) is int

        if not candiff or not canfile:

            self.restrictModes(candiff, canfile, canann)

        else:

            self.actionDiffMode.setEnabled(True)

            self.actionFileMode.setEnabled(True)

            self.actionAnnMode.setEnabled(True)

            if self._lostMode:

                self._mode = self._lostMode

                if self._lostMode == DiffMode:

                    self.actionDiffMode.trigger()

                elif self._lostMode == FileMode:

                    self.actionFileMode.trigger()

                elif self._lostMode == AnnMode:

                    self.actionAnnMode.trigger()

                self._lostMode = None

                self.blk.setVisible(self._mode != DiffMode)

                self.sci.setAnnotationEnabled(self._mode == AnnMode)

        if self._mode == DiffMode:

            self.sci.setMarginWidth(1, 0)

            lexer = lexers.difflexer(self)

            self.sci.setLexer(lexer)

            if lexer is None:

                self.sci.setFont(qtlib.getfont('fontlog').font())

            if fd.changes:

                self._showChangeSelectMargin(True)

                self.changes = fd.changes

                self.sci.setText(hglib.tounicode(fd.diff))

                for chunk in self.changes.hunks:

                    self.chunkatline[chunk.lineno] = chunk

                    self.sci.markerAdd(chunk.lineno, self.inclmarker)

            elif fd.diff:

                out = fd.diff.split('\n', 3)

                if len(out) == 4:

                    self.sci.setText(hglib.tounicode(out[3]))

                else:

                    # there was an error or rename without diffs

                    self.sci.setText(hglib.tounicode(fd.diff))

            self.newChunkList.emit(uf, fd.changes)

        elif fd.ucontents:

            # subrepo summary and perhaps other data

            self.sci.setText(fd.ucontents)

            self.sci.setLexer(None)

            self.sci.setFont(qtlib.getfont('fontlog').font())

            self.sci.setMarginWidth(1, 0)

            self.blk.setVisible(False)

            self.newChunkList.emit(uf, None)

            return

        elif fd.contents:

            lexer = lexers.getlexer(self.repo.ui, filename, fd.contents, self)

            self.sci.setLexer(lexer)

            if lexer is None:

                self.sci.setFont(qtlib.getfont('fontlog').font())

            self.sci.setText(hglib.tounicode(fd.contents))

            self.blk.setVisible(True)

            self.sci._updatemarginwidth()

            if self._mode == AnnMode:

                self.sci._updateannotation(self._ctx, filename)

            self.newChunkList.emit(uf, None)

        else:

            self.newChunkList.emit(uf, None)

            return

        # Recover the last cursor/scroll position

        self.sci.setCursorPosition(*lastCursorPosition)

        # Make sure that lastScrollPosition never exceeds the amount of

        # lines on the editor

        lastScrollPosition = min(lastScrollPosition,  self.sci.lines() - 1)

        self.sci.verticalScrollBar().setValue(lastScrollPosition)

        self.highlightText(*self._lastSearch)

        uc = hglib.tounicode(fd.contents) or ''

        self.fileDisplayed.emit(uf, uc)

        if self._mode != DiffMode:

            self.blk.setVisible(True)

            self.blk.syncPageStep()

        self.blksearch.syncPageStep()

        if fd.contents and fd.olddata:

            if self.timer.isActive():

                self.timer.stop()

            self._fd = fd

            self.timer.start()

        self.actionNextDiff.setEnabled(bool(self._diffs))

        self.actionPrevDiff.setEnabled(bool(self._diffs))

        lexer = self.sci.lexer()

        if lexer:

            font = self.sci.lexer().font(0)

        else:

            font = self.sci.font()

        fm = QFontMetrics(font)

        self.maxWidth = fm.maxWidth()

        lines = unicode(self.sci.text()).splitlines()

        if lines:

            # assume that the longest line has the largest width;

            # fm.width() is too slow to apply to each line.

            try:

                longestline = max(lines, key=len)

            except TypeError:  # Python<2.5 has no key support

                longestline = max((len(l), l) for l in lines)[1]

            self.maxWidth += fm.width(longestline)

        self.updateScrollBar()

        if line:

            self.showLine(line)

            self.sci.setFocus()

            self.sci.revisionInfoAtLine(line)


class AnnotateView(qscilib.Scintilla):

    'QScintilla widget capable of displaying annotations'

    def revisionInfoAtLine(self, line):  # retrieves line revision details and put them into the clipboard

        if line < 0:

            return

        (not self._links and self.fillModel())

        try:

            fctx = self._links[line][0]

            s = hglib.get_revision_desc(fctx, self.annfile)

            #QMessageBox.about(None, 'Active row annotation', s)

            QApplication.clipboard().setText(s)

        except IndexError:

            pass

workbench.py

def run(ui, *pats, **opts):

    root = opts.get('root') or paths.find_root()

    line = opts.get('line') and int(opts['line']) or None

    annotate = True if line and int(line) > 0 else False

    if root and pats:

        repo = thgrepo.repository(ui, root)

        pats = hglib.canonpaths(pats)

        if len(pats) == 1 and os.path.isfile(repo.wjoin(pats[0])):

            from tortoisehg.hgqt.filedialogs import FileLogDialog

            fname = pats[0]

            return FileLogDialog(repo, fname, line=line, annotate=annotate)

run.py

@command('^log|history|explorer|workbench',

    [('l', 'limit', '', _('(DEPRECATED)')),

     ('n', 'line', '', _('open to line'))],

    _('thg log [OPTIONS] [FILE]'))

def log(ui, *pats, **opts):

    """workbench application"""

    from tortoisehg.hgqt.workbench import run

    return qtrun(run, ui, *pats, **opts)

Best Regards,

Artem

Yuya Nishihara

unread,
Jun 6, 2013, 7:15:06 AM6/6/13
to thg...@googlegroups.com
On Thu, 6 Jun 2013 01:38:59 -0700 (PDT), Artemr Rudenko wrote:
> On Thursday, May 23, 2013 5:10:59 PM UTC+3, Yuya Nishihara wrote:
> >
> > On Tue, 21 May 2013 06:16:13 -0700 (PDT), Artemr Rudenko wrote:
> > > type: 'thg log -n10 <filename>' then the 'HG file log viewer' wnd will
> > be
> > > opened in 'Annotate Mode' and the specified line will be active. Also he
> > > asked me to read into memory active line revision details.
> > > So what will you say about this feature? If you will said it's OK i will
> > > try to post here code to review - there is just few lines which are
> > needed
> > > for this feature
> >
> > It might be useful.
>
> Hi all,
> Since i made several merge operations wrong i can post my changed here only
> this way for now. If it strongly not acceptable i will try to find the way
> how to post changes the way it needed. Below are filenames, class names and
> methods modified:

Oops, please send as patch.

FWIW, I'm going to change "thg annotate" to use FileLogDialog instead of
ManifestDialog. If the following changes are accepted, "thg annotate" is the
one you want.

https://groups.google.com/d/msg/thg-dev/R8Jn5A00_Yw/AA9tKobp1nwJ

Regards,

Martin Geisler

unread,
Jun 6, 2013, 8:48:20 AM6/6/13
to thg...@googlegroups.com
Yuya Nishihara <yu...@tcha.org> writes:

> FWIW, I'm going to change "thg annotate" to use FileLogDialog instead
> of ManifestDialog. If the following changes are accepted, "thg
> annotate" is the one you want.

If I'm guessing correctly what this means, then it sounds good! :)

I'm now using thg daily (thanks to Angel and hidden changesets for
convincing me!) and I find 'thg annotate foo' annoying because it shows
a manifest instead of the file log that I really need.

On the other hand, I recently discovered that 'thg log foo' works well
after clicking the small '#' icon -- after clicking the icon 'thg log'
behaves pretty much like 'hgtk annotate' did :)

> https://groups.google.com/d/msg/thg-dev/R8Jn5A00_Yw/AA9tKobp1nwJ
>
> Regards,

--
Martin Geisler

Artemr Rudenko

unread,
Jun 6, 2013, 8:58:40 AM6/6/13
to thg...@googlegroups.com
As i understood your change is only partly related to what we want, since it wouldn't allow to activate particular line using cmd and retrieve it's revision details. However you changes are always great. Please find below patch details - i hope that i have correctly splitted needed changes - if possible can you please review this patch?

diff -r 8431fac743a7 -r 1149efa217db tortoisehg/hgqt/filedialogs.py
--- a/tortoisehg/hgqt/filedialogs.py Sat May 25 21:14:24 2013 +0900
+++ b/tortoisehg/hgqt/filedialogs.py Thu Jun 06 14:49:04 2013 +0300
@@ -93,12 +93,14 @@
     """
     A dialog showing a revision graph for a file.
     """
-    def __init__(self, repo, filename, repoviewer=None):
+    def __init__(self, repo, filename, repoviewer=None, line=0, annotate=False):
         super(FileLogDialog, self).__init__(repo, filename, repoviewer)
         self._readSettings()
         self.menu = None
         self.dualmenu = None
         self.revdetails = None
+        self.line = line
+        self.annotate = annotate
 
     def closeEvent(self, event):
         self._writeSettings()
@@ -382,6 +384,8 @@
         self.textView.verticalScrollBar().setValue(pos)
         self.revpanel.set_revision(rev)
         self.revpanel.update(repo = self.repo)
+        (self.line and self.textView.changeActiveViewMode('annotate'))
+        self.textView.displayFile(self.filerevmodel.graph.filename(rev), None, line=self.line)
 
     # It does not make sense to select more than two revisions at a time.
     # Rather than enforcing a max selection size we simply let the user
diff -r 8431fac743a7 -r 1149efa217db tortoisehg/hgqt/fileview.py
--- a/tortoisehg/hgqt/fileview.py Sat May 25 21:14:24 2013 +0900
+++ b/tortoisehg/hgqt/fileview.py Thu Jun 06 14:49:04 2013 +0300
@@ -239,6 +239,14 @@
         self.timer.setSingleShot(False)
         self.timer.timeout.connect(self.timerBuildDiffMarkers)
 
+    def changeActiveViewMode(self, mode):
+        if mode.lower() == 'annotate':
+            self._setModeByAction(self.actionAnnMode)
+        elif mode.lower() == 'diff':
+            self._setModeByAction(self.actionDiffMode)
+        else:
+            self._setModeByAction(self.actionFileMode)
+
     def launchShelve(self):
         from tortoisehg.hgqt import shelve
         # TODO: pass self._filename
@@ -494,7 +502,7 @@
         QTimer.singleShot(10,
             lambda: self.displayFile(self._filename, self._status, force=True))
 
-    def displayFile(self, filename=None, status=None, force=False):
+    def displayFile(self, filename=None, status=None, force=False, line=0):
         if isinstance(filename, (unicode, QString)):
             filename = hglib.fromunicode(filename)
             status = hglib.fromunicode(status)
                 longestline = max((len(l), l) for l in lines)[1]
             self.maxWidth += fm.width(longestline)
         self.updateScrollBar()
-
+        if line:
+            self.showLine(line)
+            self.sci.setFocus()
+            self.sci.revisionInfoAtLine(line)
     #
     # These four functions are used by Shift+Cursor actions in revdetails
     #

                 self.setSource(*data)
             def editparent(data):
                 self.editSelected(*data)
+            def diffparent(data):
+                self.visualDiffParentToLocal(*data)
             for name, func, smenu in [(_('&Parent Revision (%d)') % pdata[1],
                                   annparent, anngotomenu),
                                (_('&Parent Revision (%d)') % pdata[1],
-                                  editparent, annviewmenu)]:
+                                  editparent, annviewmenu),
+                               (_('&Diff to Parent Revision (%d)') % pdata[1],
+                                diffparent, annviewmenu)]:
                 def add(name, func):
                     action = smenu.addAction(name)
                     action.data = pdata
@@ -986,6 +1009,18 @@
         self.configChanged()
         self._loadAnnotateSettings()
 
+    def revisionInfoAtLine(self, line):
+        if line < 0:
+            return
+        (not self._links and self.fillModel())
+        try:
+            fctx = self._links[line][0]
+            s = hglib.get_revision_desc(fctx, self.annfile)
+            #QMessageBox.about(None, 'Active row annotation', s)
+            QApplication.clipboard().setText(s)
+        except IndexError:
+            pass
+
     def _loadAnnotateSettings(self):
         s = QSettings()
         wb = "Annotate/"
diff -r 8431fac743a7 -r 1149efa217db tortoisehg/hgqt/run.py
--- a/tortoisehg/hgqt/run.py Sat May 25 21:14:24 2013 +0900
+++ b/tortoisehg/hgqt/run.py Thu Jun 06 14:49:04 2013 +0300
@@ -959,7 +959,9 @@
     return qtrun(run, ui, *pats, **opts)
 
 @command('^log|history|explorer|workbench',
-    [('l', 'limit', '', _('(DEPRECATED)'))],
+    [('l', 'limit', '', _('(DEPRECATED)')),
+     ('n', 'line', '', _('open to line'))],
     _('thg log [OPTIONS] [FILE]'))
 def log(ui, *pats, **opts):
     """workbench application"""
diff -r 8431fac743a7 -r 1149efa217db tortoisehg/hgqt/workbench.py
--- a/tortoisehg/hgqt/workbench.py Sat May 25 21:14:24 2013 +0900
+++ b/tortoisehg/hgqt/workbench.py Thu Jun 06 14:49:04 2013 +0300
@@ -1280,13 +1282,18 @@
 
 def run(ui, *pats, **opts):
     root = opts.get('root') or paths.find_root()
+    line = opts.get('line') and int(opts['line']) or None
+    annotate = True if line and int(line) > 0 else False
     if root and pats:
         repo = thgrepo.repository(ui, root)
         pats = hglib.canonpaths(pats)
         if len(pats) == 1 and os.path.isfile(repo.wjoin(pats[0])):
             from tortoisehg.hgqt.filedialogs import FileLogDialog
             fname = pats[0]
-            return FileLogDialog(repo, fname)
+            return FileLogDialog(repo, fname, line=line, annotate=annotate)

Best Regards,
Artem

2013/6/6 Yuya Nishihara <yu...@tcha.org>

--
You received this message because you are subscribed to a topic in the Google Groups "TortoiseHg Developers" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/thg-dev/Zo-6OQ6wa2M/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to thg-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



line_patch.diff

Yuya Nishihara

unread,
Jun 6, 2013, 11:42:21 AM6/6/13
to thg...@googlegroups.com
On Thu, 06 Jun 2013 14:48:20 +0200, Martin Geisler wrote:
> On the other hand, I recently discovered that 'thg log foo' works well
> after clicking the small '#' icon -- after clicking the icon 'thg log'
> behaves pretty much like 'hgtk annotate' did :)
>
> > https://groups.google.com/d/msg/thg-dev/R8Jn5A00_Yw/AA9tKobp1nwJ

Yes, with my patch, "thg annotate <filename>" should be exactly the same as
"thg log <filename>" + click '#' icon.

On Thu, 6 Jun 2013 15:58:40 +0300, Artemr Rudenko wrote:
> As i understood your change is only partly related to what we want, since
> it wouldn't allow to activate particular line using cmd and retrieve it's
> revision details. However you changes are always great. Please find below
> patch details - i hope that i have correctly splitted needed changes - if
> possible can you please review this patch?

"annotate" command has "-n <line>" option, so it can at least move cursor
to the specified line. I guess the only difference is revisionInfoAtLine().

> + if line:
> + self.showLine(line)
> + self.sci.setFocus()
> + self.sci.revisionInfoAtLine(line)

> + def revisionInfoAtLine(self, line):
> + if line < 0:
> + return
> + (not self._links and self.fillModel())
> + try:
> + fctx = self._links[line][0]
> + s = hglib.get_revision_desc(fctx, self.annfile)
> + #QMessageBox.about(None, 'Active row annotation', s)
> + QApplication.clipboard().setText(s)
> + except IndexError:
> + pass

FWIW, your patch cannot be applied. Probably it lacks some chunk headers or
has wrong number of chunk lines.

Regards,

Artemr Rudenko

unread,
Jun 7, 2013, 2:50:54 AM6/7/13
to thg...@googlegroups.com
Hi Yuya,

If hg annotate is working the way you have described than yes it will perform the same as my patch should except revision details. 
I have broken my patch while removing another set of changes that i'd like to suggest.
Previously i was posted a message about how to add new context menu option. The idea was simply to add two more options which will allow to open diff between selected line and its parent revision. If this option is Ok i will post my code for review.
Another one change is related to excluding all closed revision from view through command line argument. If this feature is also Ok i will add my code.

Thank you for your help. If there any help that i can provide you i will be glad to help.

Best Regards,
Artem
Reply all
Reply to author
Forward
0 new messages