Tips/GooglePrettifyRhino の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Tips/GooglePrettifyRhino へ行く。
- Tips/GooglePrettifyRhino の差分を削除
--- title: Rhinoでgoogle-code-prettifyを実行する author: aterai pubdate: 2011-01-25T23:52:05+09:00 description: Rhino(またはNashorn)でgoogle-prettify.jsを実行し、ソースコードをハイライト済みのHtmlファイルに変換します。 --- #contents * 概要 [#summary] `Rhino`(または`Nashorn`)で`google-prettify.js`を実行し、ソースコードをハイライト済みの`Html`ファイルに変換します。 #ref(https://lh5.googleusercontent.com/-fBSp3mL32JA/T-4FRzdTzYI/AAAAAAAABOc/xDs9vq7gqLw/s800/GooglePrettifyRhinoTest.png) * サンプルコード [#sourcecode] #code{{ 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); } } }} * 解説 [#explanation] 上記のサンプルでは、`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 #code{{ 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. [#u9114222] 以下のようなエラーが出る場合の対処方法について。 org.mozilla.javascript.EcmaError: ReferenceError: "print" is not defined. (env.rhino.1.2.js#1295) - [https://groups.google.com/forum/#!msg/mozilla.dev.tech.js-engine.rhino/EJmJJhftc3g/JELu_XEi5TwJ Use Context.evaluateReader with javascript file - Google グループ] のように`public static`なメソッドを(GooglePrettifyRhinoTestに)追加 #code{{ String[] names = {"print"}; globalScope.defineFunctionProperties(names, GooglePrettifyRhinoTest.class, ScriptableObject.DONTENUM); }} #code{{ public static void print(String str) { System.out.println(str); } }} - [http://ka-ka-xyz.hatenablog.com/entry/20120411/1334160190 RhinoでjQuery - ka-ka_xyzの日記] のように`org.mozilla.javascript.tools.shell.Global`を使用 #code{{ Global globalScope = new Global(); Context cx = ContextFactory.getGlobal().enterContext(); globalScope.init(cx); cx.setOptimizationLevel(-1); cx.setLanguageVersion(Context.VERSION_1_5); }} - [http://snipplr.com/view/38607/rhino-envjs-testing-example/ Rhino env.js testing example - Groovy - Snipplr Social Snippet Repository] のように、`function print`を定義 #code{{ String printFunction = "function print(message) {java.lang.System.out.println(message);}"; cx.evaluateString(scope, printFunction, "print", 1, null); }} ** HTMLPreElement [#l0271013] [https://github.com/google/code-prettify/blob/master/src/prettify.js 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. - [http://www.envjs.com/dist/env.rhino.1.2.js env.rhino.1.2.js]を追加しても、HTMLPreElement が存在しないのでエラー -- 以下を`env.rhino.1.2.js`に追加して、改行を`br`に変更した文字列を`prettyPrintOne`に与えるとうまくいく txt = txt.replace("\n", "<br />"); #code{{ /* * 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]'; } }); }} - [https://github.com/thatcher/env-js thatcher/env-js · GitHub (1.3)] には、`HTMLPreElement`が存在するが、生成された`envjs`以下のファイルの使い方が分からない…。 -- `local_settings.js` : 空のファイルをカレントに作成しておく? -- `arguments` : `cx.evaluateString(scope, "var arguments = [];", "arguments", 1, null);`などで空の配列を作成しておく? -- 何も言わずに落ちる : ???? * 参考リンク [#reference] - [https://docs.oracle.com/javase/jp/8/docs/technotes/guides/scripting/ Scripting for the Java Platform] - [https://github.com/google/code-prettify google/code-prettify: Automatically exported from code.google.com/p/google-code-prettify] - [https://developer.mozilla.org/ja/docs/Rhino Rhino | MDN] - [[JEditorPaneのHTMLEditorKitにCSSを適用>Swing/StyleSheet]] - [[JEditorPaneにソースコードをシンタックスハイライトして表示する>Swing/SyntaxHighlightingEditorPane]] * コメント [#comment] #comment - 新しい`prettify.js`(`prettify-1-Jun-2011.tar.bz2`、[https://github.com/google/code-prettify/blob/0b3341b3e9105ddaecf93cc632284f8db7994faf/src/prettify.js First pass at a way to dodge newline issues in IE.]の修正が入っているバージョン)では、`prettyPrintOne`の内部で`Document`型のオブジェクトが使用されるようになっているので`Rhino`だけ(`Envjs`とか使えば良さそうなんだけど…)では実行できない。このため上記のサンプルでは古い`prettify.js`([https://github.com/google/code-prettify/blob/f5ad44e3253f1bc8e288477a36b2ce5972e8e161/src/prettify.js Fixed prettyPrintOne by removing requirement that a job have a source node. Fixes issues 133 and 134.])を参照するように変更。 -- &user(aterai); &new{2012-03-09 (金) 16:58:03}; - `JEditorPane`でのプレビューを追加。 -- &user(aterai); &new{2012-05-28 (月) 17:45:14}; - `1.8.0`の`Nashorn`を使うとなぜか文字のハイライトがずれる? -- &user(aterai); &new{2013-07-21 (日) 00:21:18}; -- 詳細は不明だが(`regex`あたりのバグ?)、[http://download.java.net/jdk8/changes/jdk8-b100.html jdk8-b100]では正常に動作するようになった。 -- &user(aterai); &new{2013-08-01 (木) 19:20:09}; #comment