Rhinoでgoogle-code-prettifyを実行する
Total: 6528
, Today: 1
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
Rhino
(またはNashorn
)でgoogle-prettify.js
を実行し、ソースコードをハイライト済みのHtml
ファイルに変換します。
サンプルコード
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.script.*;
import javax.swing.*;
import javax.swing.text.html.*;
public class GooglePrettifyRhinoTest {
private final JTextArea src = new JTextArea();
private final JTextArea dst = new JTextArea();
private final JEditorPane editor = new JEditorPane();
private final ScriptEngine engine = createEngine();
public JComponent makeUI() {
try (Reader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("GooglePrettifyRhinoTest.java"), "UTF-8"))) {
src.read(reader, "");
} catch(Exception ex) {
ex.printStackTrace();
}
StyleSheet styleSheet = new StyleSheet();
styleSheet.addRule(".str {color:#008800}");
styleSheet.addRule(".kwd {color:#000088}");
styleSheet.addRule(".com {color:#880000}");
styleSheet.addRule(".typ {color:#660066}");
styleSheet.addRule(".lit {color:#006666}");
styleSheet.addRule(".pun {color:#666600}");
styleSheet.addRule(".pln {color:#000000}");
styleSheet.addRule(".tag {color:#000088}");
styleSheet.addRule(".atn {color:#660066}");
styleSheet.addRule(".atv {color:#008800}");
styleSheet.addRule(".dec {color:#660066}");
HTMLEditorKit htmlEditorKit = new HTMLEditorKit();
htmlEditorKit.setStyleSheet(styleSheet);
editor.setEditorKit(htmlEditorKit);
JButton b = new JButton((new AbstractAction("Convert to google sites") {
String pre = "<pre>";
@Override public void actionPerformed(ActionEvent e) {
String txt = src.getText();
txt = txt.replace("&", "&").replace("<", "<").replace(">", ">");
String str = prettify(engine, txt);
editor.setText(pre + str + "\n</pre>");
str = str.replace("class=\"str\"", "style=\"color:#080\"");
str = str.replace("class=\"kwd\"", "style=\"color:#008\"");
str = str.replace("class=\"com\"", "style=\"color:#800\"");
str = str.replace("class=\"typ\"", "style=\"color:#606\"");
str = str.replace("class=\"lit\"", "style=\"color:#066\"");
str = str.replace("class=\"pun\"", "style=\"color:#660\"");
str = str.replace("class=\"pln\"", "style=\"color:#000\"");
str = str.replace("class=\"tag\"", "style=\"color:#008\"");
str = str.replace("class=\"atn\"", "style=\"color:#606\"");
str = str.replace("class=\"atv\"", "style=\"color:#080\"");
str = str.replace("class=\"dec\"", "style=\"color:#606\"");
dst.setText(pre + str + "\n</pre>");
}
}));
JTabbedPane tab = new JTabbedPane();
tab.addTab("Google sites html", new JScrollPane(dst));
tab.addTab("JEditorPane preview", new JScrollPane(editor));
JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
sp.setResizeWeight(.5);
sp.setTopComponent(new JScrollPane(src));
sp.setBottomComponent(tab);
JPanel p = new JPanel(new BorderLayout());
p.add(b, BorderLayout.SOUTH);
p.add(sp);
return p;
}
public static ScriptEngine createEngine() {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// ScriptEngineFactory factory = engine.getFactory();
// String name = factory.getEngineName();
// String version = factory.getEngineVersion();
// System.out.printf("\tScript Engine: %s (%s)\n", name, version);
//String p = "https://raw.githubusercontent.com/google/code-prettify/master/src/prettify.js";
//String p = "http://google-code-prettify.googlecode.com/svn-history/r120/trunk/src/prettify.js";
String p = "https://raw.githubusercontent.com/google/code-prettify/f5ad44e3253f1bc8e288477a36b2ce5972e8e161/src/prettify.js";
try (Reader reader = new BufferedReader(new InputStreamReader(new URL(p).openStream()))) {
engine.eval("var window={}, navigator=null;");
engine.eval(reader);
return engine;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String prettify(ScriptEngine engine, String src) {
try {
Object w = engine.get("window");
return (String) ((Invocable) engine).invokeMethod(w, "prettyPrintOne", src);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new GooglePrettifyRhinoTest().makeUI());
f.setSize(640, 640);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
解説
上記のサンプルでは、new ScriptEngineManager().getEngineByName("JavaScript");
で取得したJavaScript
エンジン(Rhino
)に、prettify.js
(r120
) を読み込んで、prettify.js
のprettyPrintOne
メソッドを実行しています。
google sites
では、css
ファイルも使用できないので、replace("class=\"kwd\"", "style=\"color:#008\"");
のように、クラスをスタイルの色に全部置換しています。
org.mozilla.javascript.Context
などを使用する場合
> "%JAVA_HOME%\bin\javac" -cp .;rhino-1.7R4.jar GooglePrettifyRhinoTest.java > "%JAVA_HOME%\bin\java" -cp .;rhino-1.7R4.jar GooglePrettifyRhinoTest
import org.mozilla.javascript.*;
// ...
String txt = src.getText();
txt = txt.replace("&", "&").replace("<", "<").replace(">", ">");
txt = txt.replace("\n", "<br />");
// ...
public static String prettifyOne(String txt) {
txt = txt.replace("\n", "<br />"); //???
String str = "";
//String p = "https://raw.githubusercontent.com/google/code-prettify/master/src/prettify.js";
//String q = "http://www.envjs.com/dist/env.rhino.1.2.js";
//try (Reader reader1 = new BufferedReader(new InputStreamReader(new URL(p).openStream()));
// Reader reader2 = new BufferedReader(new InputStreamReader(new URL(q).openStream()))) {
try (Reader reader1 = new BufferedReader(new FileReader("env.rhino.1.2.js"));
Reader reader2 = new BufferedReader(new FileReader("prettify.js"))) {
ContextFactory contextFactory = new ContextFactory();
Context cx = contextFactory.enterContext();
cx.setOptimizationLevel(-1);
cx.setLanguageVersion(Context.VERSION_1_5);
ScriptableObject globalScope = cx.initStandardObjects();
//String[] names = {"print"};
//globalScope.defineFunctionProperties(names, GooglePrettifyRhinoTest.class, ScriptableObject.DONTENUM);
String printFunction = "function print(message) {java.lang.System.out.println(message);}";
cx.evaluateString(globalScope, printFunction, "print", 1, null);
Scriptable scope = cx.newObject(globalScope);
scope.setPrototype(globalScope);
scope.setParentScope(null);
//Global global = new Global();
//Context cx = ContextFactory.getGlobal().enterContext();
//global.init(cx);
//cx.setOptimizationLevel(-1);
//cx.setLanguageVersion(Context.VERSION_1_5);
//Scriptable scope = cx.initStandardObjects(global);
//cx.evaluateString(scope, "var arguments = ['envjs/rhino.js', 'prettify.js'];", "arguments", 1, null);
//cx.evaluateString(scope, "var arguments = [];", "arguments", 1, null);
Script envjs = cx.compileReader(reader1, "env.rhino.1.2.js", 1, null);
envjs.exec(cx, scope);
Script prettify = cx.compileReader(reader2, "prettify.js", 1, null);
prettify.exec(cx, scope);
//Object ooo = cx.evaluateString(scope, "document.createElement('div');", "<output>", 1, null);
//System.out.println(Context.toString(ooo));
//Object result = cx.evaluateReader(scope, r, "env.rhino.js", 1, null);
//System.out.println(result);
//Object result = cx.evaluateReader(scope, reader0, "", 1, null);
//result = cx.evaluateReader(scope, reader1, "", 1, null);
//result = cx.evaluateReader(scope, reader2, "prettify.js", 1, null);
Function fct = (Function) scope.get("prettyPrintOne", scope);
Object result = fct.call(cx, scope, scope, new Object[] {txt, "java", false});
str = Context.toString(result);
} catch(Exception ex) {
ex.printStackTrace();
} finally {
Context.exit();
}
return str;
}
org.mozilla.javascript.EcmaError: ReferenceError: "print" is not defined.
以下のようなエラーが出る場合の対処方法について。
org.mozilla.javascript.EcmaError: ReferenceError: "print" is not defined. (env.rhino.1.2.js#1295)
- Use Context.evaluateReader with javascript file - Google グループ のように
public static
なメソッドを(GooglePrettifyRhinoTestに)追加
String[] names = {"print"};
globalScope.defineFunctionProperties(names, GooglePrettifyRhinoTest.class, ScriptableObject.DONTENUM);
public static void print(String str) {
System.out.println(str);
}
- RhinoでjQuery - ka-ka_xyzの日記 のように
org.mozilla.javascript.tools.shell.Global
を使用
Global globalScope = new Global();
Context cx = ContextFactory.getGlobal().enterContext();
globalScope.init(cx);
cx.setOptimizationLevel(-1);
cx.setLanguageVersion(Context.VERSION_1_5);
- Rhino env.js testing example - Groovy - Snipplr Social Snippet Repository のように、
function print
を定義
String printFunction = "function print(message) {java.lang.System.out.println(message);}";
cx.evaluateString(scope, printFunction, "print", 1, null);
HTMLPreElement
prettify.js(最新)では、prettyPrintOne
が、以下のようにDOM
を使用するのでエラーになる。
var container = document.createElement('pre'); // This could cause images to load and onload listeners to fire. // E.g. <img onerror="alert(1337)" src="nosuchimage.png">. // We assume that the inner HTML is from a trusted source.
- env.rhino.1.2.jsを追加しても、HTMLPreElement が存在しないのでエラー
- 以下を
env.rhino.1.2.js
に追加して、改行をbr
に変更した文字列をprettyPrintOne
に与えるとうまくいく
- 以下を
txt = txt.replace("\n", "<br />");
/*
* HTMLPreElement - DOM Level 2
* HTML5: 4.5.12 The Pre Element
* http://dev.w3.org/html5/spec/Overview.html#the-pre-element
*/
HTMLPreElement = function(ownerDocument) {
HTMLElement.apply(this, arguments);
};
HTMLPreElement.prototype = new HTMLElement();
__extend__(HTMLPreElement.prototype, {
toString: function() {
return '[object HTMLPreElement]';
}
});
- thatcher/env-js · GitHub (1.3) には、
HTMLPreElement
が存在するが、生成されたenvjs
以下のファイルの使い方が分からない…。local_settings.js
: 空のファイルをカレントに作成しておく?arguments
:cx.evaluateString(scope, "var arguments = [];", "arguments", 1, null);
などで空の配列を作成しておく?- 何も言わずに落ちる : ????
参考リンク
- Scripting for the Java Platform
- google/code-prettify: Automatically exported from code.google.com/p/google-code-prettify
- Rhino | MDN
- JEditorPaneのHTMLEditorKitにCSSを適用
- JEditorPaneにソースコードをシンタックスハイライトして表示する