SideBySide2: Support linking directly to a line of code or comment
Using "@nnn" as a suffix on the URL token will open the file at the given line on the B (right) side of the file. "@aNNN" can be used to open the file relative to the line NNN on the A (left) side. In the History section of ChangeScreen2 hyperlink each line number to the line that comment appears on. Bug: issue 348 Change-Id: I37de37d63d5deb6dc38f040e7e9b2bf5b09ef909
This commit is contained in:
@@ -70,6 +70,7 @@ import com.google.gerrit.client.changes.PublishCommentScreen;
|
||||
import com.google.gerrit.client.changes.QueryScreen;
|
||||
import com.google.gerrit.client.dashboards.DashboardInfo;
|
||||
import com.google.gerrit.client.dashboards.DashboardList;
|
||||
import com.google.gerrit.client.diff.DisplaySide;
|
||||
import com.google.gerrit.client.diff.SideBySide2;
|
||||
import com.google.gerrit.client.documentation.DocScreen;
|
||||
import com.google.gerrit.client.groups.GroupApi;
|
||||
@@ -109,12 +110,17 @@ public class Dispatcher {
|
||||
|
||||
public static String toSideBySide(PatchSet.Id diffBase,
|
||||
PatchSet.Id revision, String fileName) {
|
||||
return toPatch("", diffBase, revision, fileName);
|
||||
return toPatch("", diffBase, revision, fileName, null, 0);
|
||||
}
|
||||
|
||||
public static String toSideBySide(PatchSet.Id diffBase,
|
||||
PatchSet.Id revision, String fileName, DisplaySide side, int line) {
|
||||
return toPatch("", diffBase, revision, fileName, side, line);
|
||||
}
|
||||
|
||||
public static String toUnified(PatchSet.Id diffBase,
|
||||
PatchSet.Id revision, String fileName) {
|
||||
return toPatch("unified", diffBase, revision, fileName);
|
||||
return toPatch("unified", diffBase, revision, fileName, null, 0);
|
||||
}
|
||||
|
||||
public static String toPatchUnified(final Patch.Key id) {
|
||||
@@ -126,11 +132,11 @@ public class Dispatcher {
|
||||
}
|
||||
|
||||
private static String toPatch(String type, PatchSet.Id diffBase, Patch.Key id) {
|
||||
return toPatch(type, diffBase, id.getParentKey(), id.get());
|
||||
return toPatch(type, diffBase, id.getParentKey(), id.get(), null, 0);
|
||||
}
|
||||
|
||||
private static String toPatch(String type, PatchSet.Id diffBase,
|
||||
PatchSet.Id revision, String fileName) {
|
||||
PatchSet.Id revision, String fileName, DisplaySide side, int line) {
|
||||
Change.Id c = revision.getParentKey();
|
||||
StringBuilder p = new StringBuilder();
|
||||
p.append("/c/").append(c).append("/");
|
||||
@@ -141,6 +147,11 @@ public class Dispatcher {
|
||||
if (type != null && !type.isEmpty()) {
|
||||
p.append(",").append(type);
|
||||
}
|
||||
if (side == DisplaySide.A && line > 0) {
|
||||
p.append("@a").append(line);
|
||||
} else if (line > 0) {
|
||||
p.append("@").append(line);
|
||||
}
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
@@ -521,8 +532,21 @@ public class Dispatcher {
|
||||
}
|
||||
|
||||
if (!rest.isEmpty()) {
|
||||
DisplaySide side = DisplaySide.B;
|
||||
int line = 0;
|
||||
int at = rest.lastIndexOf('@');
|
||||
if (at > 0) {
|
||||
String l = rest.substring(at+1);
|
||||
if (l.startsWith("a")) {
|
||||
side = DisplaySide.A;
|
||||
l = l.substring(1);
|
||||
}
|
||||
line = Integer.parseInt(l);
|
||||
rest = rest.substring(0, at);
|
||||
}
|
||||
Patch.Key p = new Patch.Key(ps, KeyUtil.decode(rest));
|
||||
patch(token, base, p, 0, null, null, panel);
|
||||
patch(token, base, p, side, line, 0,
|
||||
null, null, null, panel);
|
||||
} else {
|
||||
if (panel == null) {
|
||||
Gerrit.display(token, isChangeScreen2()
|
||||
@@ -580,17 +604,12 @@ public class Dispatcher {
|
||||
public static void patch(String token, PatchSet.Id base, Patch.Key id,
|
||||
int patchIndex, PatchSetDetail patchSetDetail,
|
||||
PatchTable patchTable, PatchScreen.TopView topView) {
|
||||
patch(token, base, id, patchIndex, patchSetDetail, patchTable, topView, null);
|
||||
}
|
||||
|
||||
public static void patch(String token, PatchSet.Id base, Patch.Key id,
|
||||
int patchIndex, PatchSetDetail patchSetDetail,
|
||||
PatchTable patchTable, String panelType) {
|
||||
patch(token, base, id, patchIndex, patchSetDetail, patchTable,
|
||||
null, panelType);
|
||||
patch(token, base, id, null, 0, patchIndex,
|
||||
patchSetDetail, patchTable, topView, null);
|
||||
}
|
||||
|
||||
public static void patch(String token, final PatchSet.Id baseId, final Patch.Key id,
|
||||
final DisplaySide side, final int line,
|
||||
final int patchIndex, final PatchSetDetail patchSetDetail,
|
||||
final PatchTable patchTable, final PatchScreen.TopView topView,
|
||||
final String panelType) {
|
||||
@@ -633,7 +652,8 @@ public class Dispatcher {
|
||||
baseId //
|
||||
);
|
||||
}
|
||||
return new SideBySide2(baseId, id.getParentKey(), id.get());
|
||||
return new SideBySide2(baseId, id.getParentKey(), id.get(),
|
||||
side, line);
|
||||
} else if ("".equals(panel) || "sidebyside".equals(panel)) {
|
||||
return new PatchScreen.SideBySide(//
|
||||
id, //
|
||||
|
@@ -53,7 +53,7 @@ class FileComments extends Composite {
|
||||
}
|
||||
});
|
||||
for (CommentInfo c : list) {
|
||||
comments.add(new LineComment(clp, c));
|
||||
comments.add(new LineComment(clp, ps, c));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,9 +14,13 @@
|
||||
|
||||
package com.google.gerrit.client.change;
|
||||
|
||||
import com.google.gerrit.client.Dispatcher;
|
||||
import com.google.gerrit.client.changes.CommentInfo;
|
||||
import com.google.gerrit.client.changes.Util;
|
||||
import com.google.gerrit.client.diff.DisplaySide;
|
||||
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||
import com.google.gerrit.client.ui.InlineHyperlink;
|
||||
import com.google.gerrit.common.changes.Side;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
@@ -29,18 +33,36 @@ class LineComment extends Composite {
|
||||
interface Binder extends UiBinder<HTMLPanel, LineComment> {}
|
||||
private static final Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
@UiField Element location;
|
||||
@UiField Element fileLoc;
|
||||
@UiField Element lineLoc;
|
||||
@UiField InlineHyperlink line;
|
||||
@UiField Element message;
|
||||
|
||||
LineComment(CommentLinkProcessor clp, CommentInfo info) {
|
||||
LineComment(CommentLinkProcessor clp, PatchSet.Id ps, CommentInfo info) {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
location.setInnerText(info.has_line()
|
||||
? Util.M.lineHeader(info.line())
|
||||
: Util.C.fileCommentHeader());
|
||||
if (info.has_line()) {
|
||||
fileLoc.removeFromParent();
|
||||
fileLoc = null;
|
||||
|
||||
line.setTargetHistoryToken(url(ps, info));
|
||||
line.setText(Integer.toString(info.line()));
|
||||
|
||||
} else {
|
||||
lineLoc.removeFromParent();
|
||||
lineLoc = null;
|
||||
line = null;
|
||||
}
|
||||
|
||||
if (info.message() != null) {
|
||||
message.setInnerSafeHtml(clp.apply(new SafeHtmlBuilder()
|
||||
.append(info.message().trim()).wikify()));
|
||||
}
|
||||
}
|
||||
|
||||
private static String url(PatchSet.Id ps, CommentInfo info) {
|
||||
return Dispatcher.toSideBySide(null, ps, info.path(),
|
||||
info.side() == Side.PARENT ? DisplaySide.A : DisplaySide.B,
|
||||
info.line());
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
-->
|
||||
<ui:UiBinder
|
||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:c='urn:import:com.google.gerrit.client'
|
||||
xmlns:c='urn:import:com.google.gerrit.client.ui'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:style>
|
||||
.box {
|
||||
@@ -34,7 +34,8 @@ limitations under the License.
|
||||
</ui:style>
|
||||
|
||||
<g:HTMLPanel styleName='{style.box}'>
|
||||
<div class='{style.location}' ui:field='location'/>
|
||||
<div class='{style.location}' ui:field='fileLoc'><ui:msg>File Comment</ui:msg></div>
|
||||
<div class='{style.location}' ui:field='lineLoc'><ui:msg>Line <c:InlineHyperlink ui:field='line'/>:</ui:msg></div>
|
||||
<div class='{style.message}' ui:field='message'/>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
|
@@ -15,6 +15,6 @@
|
||||
package com.google.gerrit.client.diff;
|
||||
|
||||
/** Enum representing the side on a side-by-side view */
|
||||
enum DisplaySide {
|
||||
public enum DisplaySide {
|
||||
A, B
|
||||
}
|
||||
|
@@ -119,6 +119,8 @@ public class SideBySide2 extends Screen {
|
||||
private final PatchSet.Id base;
|
||||
private final PatchSet.Id revision;
|
||||
private final String path;
|
||||
private final DisplaySide startSide;
|
||||
private final int startLine;
|
||||
private DiffPreferences prefs;
|
||||
|
||||
private CodeMirror cmA;
|
||||
@@ -155,11 +157,15 @@ public class SideBySide2 extends Screen {
|
||||
public SideBySide2(
|
||||
PatchSet.Id base,
|
||||
PatchSet.Id revision,
|
||||
String path) {
|
||||
String path,
|
||||
DisplaySide startSide,
|
||||
int startLine) {
|
||||
this.base = base;
|
||||
this.revision = revision;
|
||||
this.changeId = revision.getParentKey();
|
||||
this.path = path;
|
||||
this.startSide = startSide;
|
||||
this.startLine = startLine;
|
||||
|
||||
prefs = DiffPreferences.create(Gerrit.getAccountDiffPreference());
|
||||
unsaved = new HashSet<DraftBox>();
|
||||
@@ -267,7 +273,15 @@ public class SideBySide2 extends Screen {
|
||||
});
|
||||
diffTable.sidePanel.adjustGutters(cmB);
|
||||
|
||||
if (diff.meta_b() != null) {
|
||||
if (startSide != null && startLine > 0) {
|
||||
int line = startLine - 1;
|
||||
CodeMirror cm = getCmFromSide(startSide);
|
||||
if (cm.lineAtHeight(height - 20) < line) {
|
||||
cm.scrollToY(cm.heightAtLine(line, "local") - 0.5 * height);
|
||||
}
|
||||
cm.setCursor(LineCharacter.create(line));
|
||||
cm.focus();
|
||||
} else if (diff.meta_b() != null) {
|
||||
int line = 0;
|
||||
if (!diffChunks.isEmpty()) {
|
||||
DiffChunkInfo d = diffChunks.get(0);
|
||||
|
Reference in New Issue
Block a user