Get more keybindings back from VIM mode

The one key that VIM mode doesn't steal is "Alt", with which
we can restore some functionalities.

Implemented navigation among diff chunks.

Change-Id: I6b8b73219cefc123133fd98fb6c407960890461d
This commit is contained in:
Michael Zhou
2013-08-15 09:51:38 -07:00
parent 4c74694915
commit 12f63a5c85
2 changed files with 111 additions and 20 deletions

View File

@@ -62,6 +62,7 @@ import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtexpui.globalkey.client.ShowHelpCommand;
import com.google.gwtexpui.user.client.DialogVisibleEvent;
import com.google.gwtexpui.user.client.DialogVisibleHandler;
import com.google.gwtexpui.user.client.UserAgent;
@@ -127,6 +128,8 @@ public class SideBySide2 extends Screen {
private Map<LineHandle, LinePaddingWidgetWrapper> linePaddingOnOtherSideMap;
private List<DiffChunkInfo> diffChunks;
private List<SkippedLine> skips;
private List<Integer> chunkPositions;
private int currChunkIndex;
private int context;
private KeyCommandSet keysNavigation;
@@ -276,7 +279,34 @@ public class SideBySide2 extends Screen {
.on("'r'", toggleReviewed())
.on("'o'", toggleOpenBox(cm))
.on("Enter", toggleOpenBox(cm))
.on("'c'", insertNewDraft(cm)));
.on("'c'", insertNewDraft(cm))
.on("Alt-U", new Runnable() {
public void run() {
cm.getInputField().blur();
removeActiveLineHighlight(cm);
removeActiveLineHighlight(otherCm(cm));
}
})
.on("Alt-[", new Runnable() {
@Override
public void run() {
header.prev.go();
}
})
.on("Alt-]", new Runnable() {
@Override
public void run() {
header.next.go();
}
})
.on("Shift-Alt-/", new Runnable() {
@Override
public void run() {
new ShowHelpCommand().onKeyPress(null);
}
})
.on("Alt-N", diffChunkNav(cm, false))
.on("Alt-P", diffChunkNav(cm, true)));
}
@Override
@@ -357,6 +387,29 @@ public class SideBySide2 extends Screen {
linePaddingOnOtherSideMap = new HashMap<LineHandle, LinePaddingWidgetWrapper>();
diffChunks = new ArrayList<DiffChunkInfo>();
render(diffInfo);
Collections.sort(diffChunks, new Comparator<DiffChunkInfo>() {
@Override
public int compare(DiffChunkInfo o1, DiffChunkInfo o2) {
if (o1.side == o2.side) {
return o1.start - o2.start;
} else if (o1.side == DisplaySide.A) {
int comp = mapper.lineOnOther(o1.side, o1.start).getLine() - o2.start;
return comp == 0 ? 1 : comp;
} else {
int comp = o1.start - mapper.lineOnOther(o2.side, o2.start).getLine();
return comp == 0 ? -1 : comp;
}
}
});
chunkPositions = new ArrayList<Integer>();
for (int i = 0; i < diffChunks.size();) {
DiffChunkInfo info = diffChunks.get(i);
chunkPositions.add(
info.side == DisplaySide.B
? info.start
: mapper.lineOnOther(DisplaySide.A, info.start).getLine());
i += info.edit ? 2 : 1;
}
lineActiveBoxMap = new HashMap<LineHandle, CommentBox>();
lineLastPublishedBoxMap = new HashMap<LineHandle, PublishedBox>();
linePaddingManagerMap = new HashMap<LineHandle, PaddingManager>();
@@ -461,10 +514,10 @@ public class SideBySide2 extends Screen {
int chunkEndA = mapper.getLineA() - 1;
int chunkEndB = mapper.getLineB() - 1;
if (bLength > 0) {
addDiffChunkAndPadding(cmA, chunkEndA, chunkEndB, bLength);
addDiffChunkAndPadding(cmA, chunkEndA, chunkEndB, bLength, aLength > 0);
}
if (aLength > 0) {
addDiffChunkAndPadding(cmB, chunkEndB, chunkEndA, aLength);
addDiffChunkAndPadding(cmB, chunkEndB, chunkEndA, aLength, bLength > 0);
}
markEdit(cmA, currentA, current.edit_a(), origLineA);
markEdit(cmB, currentB, current.edit_b(), origLineB);
@@ -803,13 +856,13 @@ public class SideBySide2 extends Screen {
}
private void addDiffChunkAndPadding(CodeMirror cmToPad, int lineToPad,
int lineOnOther, int chunkSize) {
int lineOnOther, int chunkSize, boolean edit) {
CodeMirror otherCm = otherCm(cmToPad);
linePaddingOnOtherSideMap.put(otherCm.getLineHandle(lineOnOther),
new LinePaddingWidgetWrapper(addPaddingWidget(cmToPad, DiffTable.style.padding(),
lineToPad, 0, Unit.EM, null), lineToPad, chunkSize));
diffChunks.add(new DiffChunkInfo(getSideFromCm(otherCm),
lineOnOther - chunkSize + 1, lineOnOther));
lineOnOther - chunkSize + 1, lineOnOther, edit));
}
private PaddingWidgetWrapper addPaddingWidget(CodeMirror cm, String style,
@@ -827,6 +880,16 @@ public class SideBySide2 extends Screen {
return new PaddingWidgetWrapper(widget, div);
}
private void removeActiveLineHighlight(CodeMirror cm) {
if (cm.hasActiveLine()) {
LineHandle activeLine = cm.getActiveLine();
cm.removeLineClass(activeLine,
LineClassWhere.WRAP, DiffTable.style.activeLine());
cm.removeLineClass(activeLine,
LineClassWhere.BACKGROUND, DiffTable.style.activeLineBg());
}
}
private Runnable doScroll(final CodeMirror cm) {
final CodeMirror other = otherCm(cm);
return new Runnable() {
@@ -903,20 +966,8 @@ public class SideBySide2 extends Screen {
final CodeMirror other = otherCm(cm);
return new Runnable() {
public void run() {
if (cm.hasActiveLine()) {
LineHandle activeLine = cm.getActiveLine();
cm.removeLineClass(activeLine,
LineClassWhere.WRAP, DiffTable.style.activeLine());
cm.removeLineClass(activeLine,
LineClassWhere.BACKGROUND, DiffTable.style.activeLineBg());
}
if (other.hasActiveLine()) {
LineHandle otherActiveLine = other.getActiveLine();
other.removeLineClass(otherActiveLine,
LineClassWhere.WRAP, DiffTable.style.activeLine());
other.removeLineClass(otherActiveLine,
LineClassWhere.BACKGROUND, DiffTable.style.activeLineBg());
}
removeActiveLineHighlight(cm);
removeActiveLineHighlight(other);
LineHandle handle = cm.getLineHandleVisualStart(cm.getCursor("end").getLine());
cm.setActiveLine(handle);
if (cm.somethingSelected()) {
@@ -1031,6 +1082,36 @@ public class SideBySide2 extends Screen {
};
}
private Runnable diffChunkNav(final CodeMirror cm, final boolean prev) {
return new Runnable() {
@Override
public void run() {
int line = cm.hasActiveLine() ? cm.getLineNumber(cm.getActiveLine()) : 0;
if (cm == cmA) {
line = mapper.lineOnOther(DisplaySide.A, line).getLine();
}
int res = Collections.binarySearch(chunkPositions, line);
if (res < 0) {
res = -res - 2;
}
if (currChunkIndex == chunkPositions.size() - 1 && !prev) {
currChunkIndex = 0;
} else if (currChunkIndex == 0 && prev) {
currChunkIndex = chunkPositions.size() - 1;
} else {
currChunkIndex = res + (prev ? -1 : 1);
}
int target = chunkPositions.get(currChunkIndex);
if (cm == cmA) {
target = mapper.lineOnOther(DisplaySide.B, target).getLine();
}
cm.setCursor(LineCharacter.create(target));
cm.scrollToY(Math.max(0, cm.heightAtLine(target, "local") -
cm.getScrollbarV().getClientHeight() / 2));
}
};
}
private DiffChunkInfo getDiffChunk(DisplaySide side, int line) {
for (DiffChunkInfo info : diffChunks) {
if (info.getSide() == side && info.getStart() <= line &&
@@ -1181,11 +1262,13 @@ public class SideBySide2 extends Screen {
private DisplaySide side;
private int start;
private int end;
private boolean edit;
DiffChunkInfo(DisplaySide side, int start, int end) {
DiffChunkInfo(DisplaySide side, int start, int end, boolean edit) {
this.side = side;
this.start = start;
this.end = end;
this.edit = edit;
}
DisplaySide getSide() {
@@ -1199,6 +1282,10 @@ public class SideBySide2 extends Screen {
int getEnd() {
return end;
}
boolean isEdit() {
return edit;
}
}
private static class NoOpKeyCommand extends KeyCommand {

View File

@@ -287,6 +287,10 @@ public class CodeMirror extends JavaScriptObject {
return this.display.sizer;
}-*/;
public final native Element getInputField() /*-{
return this.getInputField();
}-*/;
public final native Element getScrollbarV() /*-{
return this.display.scrollbarV;
}-*/;