This page documents potential improvements to blame/annotate functionality.
Separate blame algorithm from presentation code
Currently, the low-level annotate function lives in context.py. Formatting of things like line numbers also occurs inside the function. There needs to be a refactoring to separate concerns.
hgweb links to ancestor's blame
Often when people use blame, they want to trace a file or block's history back through time. It is difficult to do this on hgweb (or via the CLI for that matter) today. Adding a link to hgweb that loaded the blame for the same line on the nearest ancestor changeset that modified that line/block would be a massive time saver.
hgweb links to changeset
Currently the links next to the code in the blame view links to the diff for the particular file. It would be more useful to link to the changeset which changed the given line since the changeset page contains more contextual information. So rather than link to <repository>/diff/<changeset>/<filepath>, link to <repository>/rev/<changeset>
Ideal would be to link to the changeset page, but to the line which added/changed the given source line. I.e. to <repository>/rev/<changeset>#l<line>
Keyboard shortcuts on hgweb
Adding keyboard shortcuts to hgweb for navigating blame could be very useful.
Calculate blame from tip to base
Currently, blame is calculated by starting at the base revision and applying deltas until you get to revision being blamed. It might be faster to calculate blame by starting at revision being blamed and apply reverse deltas until all lines have a revision attached.
- Comments by mpm (on irc):
2016-08-02 20:08:06(CEST)│@mpm│ tip-to-base won't be a win for the vast majority of source files with a copyright boilerplate or common includes. 2016-08-02 20:08:33(CEST)│@mpm│ And revlogs are slower in that direction. 2016-08-02 20:08:50(CEST)│nemo│ hm 2016-08-02 20:09:49(CEST)│nemo│ mpm: copyright boilerplate isn't the majority of the file right? 2016-08-02 20:10:13(CEST)│@mpm│ It doesn't matter. If it has to go all the way back to the base for -any- line, any win of being lazy is lost. 2016-08-02 20:10:23(CEST)│nemo│ oh 2016-08-02 20:10:32(CEST)│@mpm│ And then you take the loss for running in the slow direction.
Automatically skip revisions
It would be nice if you could easily configure blame to ignore certain changesets or types of changes. e.g. whitespace only changes, manually specified revset.
Preserve data for each revision
Currently, calling annotate() returns results for the requested revision and nothing else. Internally, annotate() builds up state for multiple revisions before returning the state of the requested revision. If we preserved this old state, we could do things like send it to consumers that are capable of storing every revision and quickly cycling between them.
See also the advanced HTML interface below for ideas on how this data could be used.
Advanced HTML interface
If hgweb exposed websockets or some other streaming protocol for receiving blame data, we could construct an advanced blame viewer that incrementally loaded blame information and allowed quick navigation between revisions. For example, the page could start by rendering the plain file content with no blame information. In the background, a websocket request starts receiving blame information for every revision of the file. As the blame information is received, the per-line/block blame information is updated and the browser stores a copy of the history of blame. A horizontal slider could be used to rapidly switch between revisions. These wouldn't require round trips to the server because the browser has already stored/cached blame information on multiple revisions.
A request for this interface is for "open in new tab" to just work. A lot of people do complex drill downs when using blame and open lots of tabs. If the advanced interface is in the middle of some context, opening a new tab from a link in the interface should preserve the state. i.e. URL query string parameters should allow permalinks to specific revisions, lines, etc.
It has been suggested to investigate :Gblame from fugitive.vim for ideas worth borrowing.
grep + blame
Add the ability to do a grep-like search + blame output. Use case is you are looking for a particular fragment of code but you also want to see blame / context around that line for revisions that changed it.
In "reverse blame" mode, one can easily find when a line in an old revision was modified or removed in a newer revision. This could be a link or mode in the HTML interface to quickly go the other direction.
Visual grouping of changesets
Typically there are block of lines all attributed to the same revision. Instead of rendering the revision/changeset for every line, we could only render it once per block.
Hover info box for changeset info
The per-line changeset info is very sparse. Perhaps an info box which renders more details could be rendered on hover. 3rd parties could extend the info rendered to e.g. include links to bugs.
In a case where you have a repo with divergent heads (maybe two branches, production and dev) you may want to know the 'blame' of only the difference between two revs.
I envision this as hg diffblame -r A:B where the output would have something like <rev>: +... and we *can* have <rev>: -... too.