// Copyright (C) 2013 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package net.codemirror.lib; import com.google.gerrit.client.Gerrit; import com.google.gerrit.client.diff.DisplaySide; import com.google.gerrit.client.rpc.CallbackGroup; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import net.codemirror.lib.TextMarker.FromTo; /** * Glue to connect CodeMirror to be callable from GWT. * * @see <a href="http://codemirror.net/doc/manual.html#api">CodeMirror API</a> */ public class CodeMirror extends JavaScriptObject { public static void preload() { initLibrary(CallbackGroup.<Void>emptyCallback()); } public static void initLibrary(AsyncCallback<Void> cb) { Loader.initLibrary(cb); } interface Style extends CssResource { String activeLine(); String showTabs(); String margin(); } static Style style() { return Lib.I.style(); } public static CodeMirror create(Element p, Configuration cfg) { CodeMirror cm = newCM(p, cfg); Extras.attach(cm); return cm; } private static native CodeMirror newCM(Element p, Configuration cfg) /*-{ return $wnd.CodeMirror(p, cfg); }-*/; public final native void setOption(String option, boolean value) /*-{ this.setOption(option, value) }-*/; public final native void setOption(String option, double value) /*-{ this.setOption(option, value) }-*/; public final native void setOption(String option, String value) /*-{ this.setOption(option, value) }-*/; public final native void setOption(String option, JavaScriptObject val) /*-{ this.setOption(option, val) }-*/; public final native String getStringOption(String o) /*-{ return this.getOption(o) }-*/; public final native String getValue() /*-{ return this.getValue() }-*/; public final native void setValue(String v) /*-{ this.setValue(v) }-*/; public final native int changeGeneration(boolean closeEvent) /*-{ return this.changeGeneration(closeEvent) }-*/ ; public final native boolean isClean(int generation) /*-{ return this.isClean(generation) }-*/; public final native void setWidth(double w) /*-{ this.setSize(w, null) }-*/; public final native void setHeight(double h) /*-{ this.setSize(null, h) }-*/; public final int getHeight() { return getWrapperElement().getClientHeight(); } public final void adjustHeight(int localHeader) { int rest = Gerrit.getHeaderFooterHeight() + localHeader + 5; // Estimate setHeight(Window.getClientHeight() - rest); } public final native String getLine(int n) /*-{ return this.getLine(n) }-*/; public final native double barHeight() /*-{ return this.display.barHeight }-*/; public final native double barWidth() /*-{ return this.display.barWidth }-*/; public final native int lastLine() /*-{ return this.lastLine() }-*/; public final native void refresh() /*-{ this.refresh() }-*/; public final native TextMarker markText(Pos from, Pos to, Configuration options) /*-{ return this.markText(from, to, options) }-*/; public enum LineClassWhere { TEXT { @Override String value() { return "text"; } }, BACKGROUND { @Override String value() { return "background"; } }, WRAP { @Override String value() { return "wrap"; } }; abstract String value(); } public final void addLineClass(int line, LineClassWhere where, String className) { addLineClassNative(line, where.value(), className); } private native void addLineClassNative(int line, String where, String lineClass) /*-{ this.addLineClass(line, where, lineClass) }-*/; public final void addLineClass(LineHandle line, LineClassWhere where, String className) { addLineClassNative(line, where.value(), className); } private native void addLineClassNative(LineHandle line, String where, String lineClass) /*-{ this.addLineClass(line, where, lineClass) }-*/; public final void removeLineClass(int line, LineClassWhere where, String className) { removeLineClassNative(line, where.value(), className); } private native void removeLineClassNative(int line, String where, String lineClass) /*-{ this.removeLineClass(line, where, lineClass) }-*/; public final void removeLineClass(LineHandle line, LineClassWhere where, String className) { removeLineClassNative(line, where.value(), className); } private native void removeLineClassNative(LineHandle line, String where, String lineClass) /*-{ this.removeLineClass(line, where, lineClass) }-*/; public final native void addWidget(Pos pos, Element node) /*-{ this.addWidget(pos, node, false) }-*/; public final native LineWidget addLineWidget(int line, Element node, Configuration options) /*-{ return this.addLineWidget(line, node, options) }-*/; public final native int lineAtHeight(double height) /*-{ return this.lineAtHeight(height) }-*/; public final native int lineAtHeight(double height, String mode) /*-{ return this.lineAtHeight(height, mode) }-*/; public final native double heightAtLine(int line) /*-{ return this.heightAtLine(line) }-*/; public final native double heightAtLine(int line, String mode) /*-{ return this.heightAtLine(line, mode) }-*/; public final native Rect charCoords(Pos pos, String mode) /*-{ return this.charCoords(pos, mode) }-*/; public final native CodeMirrorDoc getDoc() /*-{ return this.getDoc() }-*/; public final native void scrollTo(double x, double y) /*-{ this.scrollTo(x, y) }-*/; public final native void scrollToY(double y) /*-{ this.scrollTo(null, y) }-*/; public final void scrollToLine(int line) { int height = getHeight(); if (lineAtHeight(height - 20) < line) { scrollToY(heightAtLine(line, "local") - 0.5 * height); } setCursor(Pos.create(line, 0)); } public final native ScrollInfo getScrollInfo() /*-{ return this.getScrollInfo() }-*/; public final native Viewport getViewport() /*-{ return this.getViewport() }-*/; public final native void operation(Runnable thunk) /*-{ this.operation(function() { thunk.@java.lang.Runnable::run()(); }) }-*/; public final native void off(String event, RegisteredHandler h) /*-{ this.off(event, h) }-*/; public final native RegisteredHandler on(String event, Runnable thunk) /*-{ var h = $entry(function() { thunk.@java.lang.Runnable::run()() }); this.on(event, h); return h; }-*/; public final native void on(String event, EventHandler handler) /*-{ this.on(event, $entry(function(cm, e) { handler.@net.codemirror.lib.CodeMirror.EventHandler::handle( Lnet/codemirror/lib/CodeMirror; Lcom/google/gwt/dom/client/NativeEvent;)(cm, e); })) }-*/; public final native void on(String event, RenderLineHandler handler) /*-{ this.on(event, $entry(function(cm, h, e) { handler.@net.codemirror.lib.CodeMirror.RenderLineHandler::handle( Lnet/codemirror/lib/CodeMirror; Lnet/codemirror/lib/CodeMirror$LineHandle; Lcom/google/gwt/dom/client/Element;)(cm, h, e); })) }-*/; public final native void on(String event, GutterClickHandler handler) /*-{ this.on(event, $entry(function(cm, l, g, e) { handler.@net.codemirror.lib.CodeMirror.GutterClickHandler::handle( Lnet/codemirror/lib/CodeMirror; I Ljava/lang/String; Lcom/google/gwt/dom/client/NativeEvent;)(cm, l, g, e); })) }-*/; public final native void on(String event, BeforeSelectionChangeHandler handler) /*-{ this.on(event, $entry(function(cm, o) { var e = o.ranges[o.ranges.length-1]; handler.@net.codemirror.lib.CodeMirror.BeforeSelectionChangeHandler::handle( Lnet/codemirror/lib/CodeMirror; Lnet/codemirror/lib/Pos; Lnet/codemirror/lib/Pos;)(cm, e.anchor, e.head); })) }-*/; public final native void on(ChangesHandler handler) /*-{ this.on('changes', $entry(function(cm, o) { handler.@net.codemirror.lib.CodeMirror.ChangesHandler::handle( Lnet/codemirror/lib/CodeMirror;)(cm); })) }-*/; public final native void setCursor(Pos p) /*-{ this.setCursor(p) }-*/; public final native Pos getCursor() /*-{ return this.getCursor() }-*/; public final native Pos getCursor(String start) /*-{ return this.getCursor(start) }-*/; public final FromTo getSelectedRange() { return FromTo.create(getCursor("start"), getCursor("end")); } public final native void setSelection(Pos p) /*-{ this.setSelection(p) }-*/; public final native void setSelection(Pos anchor, Pos head) /*-{ this.setSelection(anchor, head) }-*/; public final native boolean somethingSelected() /*-{ return this.somethingSelected() }-*/; public final native void addKeyMap(KeyMap map) /*-{ this.addKeyMap(map) }-*/; public final native void removeKeyMap(KeyMap map) /*-{ this.removeKeyMap(map) }-*/; public final native LineHandle getLineHandle(int line) /*-{ return this.getLineHandle(line) }-*/; public final native LineHandle getLineHandleVisualStart(int line) /*-{ return this.getLineHandleVisualStart(line) }-*/; public final native int getLineNumber(LineHandle handle) /*-{ return this.getLineNumber(handle) }-*/; public final native void focus() /*-{ this.focus() }-*/; public final native Element getWrapperElement() /*-{ return this.getWrapperElement() }-*/; public final native Element getGutterElement() /*-{ return this.getGutterElement() }-*/; public final native Element sizer() /*-{ return this.display.sizer }-*/; public final native Element mover() /*-{ return this.display.mover }-*/; public final native Element measure() /*-{ return this.display.measure }-*/; public final native Element scrollbarV() /*-{ return this.display.scrollbars.vert.node; }-*/; public final native void execCommand(String cmd) /*-{ this.execCommand(cmd) }-*/; public static final native KeyMap getKeyMap(String name) /*-{ return $wnd.CodeMirror.keyMap[name]; }-*/; public static final native void addKeyMap(String name, KeyMap km) /*-{ $wnd.CodeMirror.keyMap[name] = km }-*/; public static final native void normalizeKeyMap(KeyMap km) /*-{ $wnd.CodeMirror.normalizeKeyMap(km); }-*/; public static final native void addCommand(String name, CommandRunner runner) /*-{ $wnd.CodeMirror.commands[name] = function(cm) { runner.@net.codemirror.lib.CodeMirror.CommandRunner::run( Lnet/codemirror/lib/CodeMirror;)(cm); }; }-*/; public final native Vim vim() /*-{ return this; }-*/; public final DisplaySide side() { return extras().side(); } public final Extras extras() { return Extras.get(this); } public final native LineHandle setGutterMarker(int line, String gutterId, Element value) /*-{ return this.setGutterMarker(line, gutterId, value); }-*/; public final native LineHandle setGutterMarker( LineHandle line, String gutterId, Element value) /*-{ return this.setGutterMarker(line, gutterId, value); }-*/; public final native boolean hasSearchHighlight() /*-{ return this.state.search && !!this.state.search.query; }-*/; protected CodeMirror() {} public static class Viewport extends JavaScriptObject { public final native int from() /*-{ return this.from }-*/; public final native int to() /*-{ return this.to }-*/; public final boolean contains(int line) { return from() <= line && line < to(); } protected Viewport() {} } public static class LineHandle extends JavaScriptObject { protected LineHandle() {} } public static class RegisteredHandler extends JavaScriptObject { protected RegisteredHandler() {} } public interface EventHandler { void handle(CodeMirror instance, NativeEvent event); } public interface RenderLineHandler { void handle(CodeMirror instance, LineHandle handle, Element element); } public interface GutterClickHandler { void handle(CodeMirror instance, int line, String gutter, NativeEvent clickEvent); } public interface BeforeSelectionChangeHandler { void handle(CodeMirror instance, Pos anchor, Pos head); } public interface ChangesHandler { void handle(CodeMirror instance); } public interface CommandRunner { void run(CodeMirror instance); } }