/ 最近 .rdf 追記 設定 本棚

log[SHJS: 2010-07-30]



20100730()

最終更: 2012-11-01T13:41+0900

[SakuraEditor][SHJS][Ruby] Ruby%リテラルの色分けを修正

説明が面倒なのと誰も知りたくないだろうから適当に備忘のためだけに

  1. まさか %{literal}literal部分で \{\} を使う人間がいるとは思わなかった(違う種類の括弧を使えばいいじゃない開閉の釣り合いがとれてれば同じ種類の括弧でもエスケープ不要だ)
  2. だのに Ruby1.9rake.rbにこんなパターンが……

    %r{[*?\[\{]}
  3. エスケープされた { 2のはの考慮がないから閉じ括弧が足りないとしてファイル末尾まで正規表現として色分けされてしまう
  4. ょちょちょいと .rkw2ァイルにエスケープ文字を追加してサクラエタに対する修正は完了
  5. SHJSlang/sh_ruby.js(自作)への対応も同じですむはずが入力の末尾に達した時点で意図せぬバトラックが発動し閉じ括弧が足りなくても色分けが適当な閉じ括弧で終了してしまう現象に遭遇これは自業自得(20090808p01)なので自分でなんとかせねば間違いが埋没してしまうのはよろしくない
  6. こうした

    %r{余分な開き括弧{。間違いはインタープリタを通す前から目立つように}

2のは Rubyインタープリタに対するエスケープと同時に正規表現パターンとしてのエスケープですよ%r[\[]/\[/ が同じパターンになって%r[[]Rubyのシンタックスエラ/[/ がパターンのコンパイルエラーになるんだから(ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mswin32] / ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32])


20091120() DDセイバーオルタはやばい限定販売でよかったね

最終更: 2010-04-08T22:28+0900

[SHJS][SakuraEditor] 色分けにこんな機能があると便利

参照(説明の丸投げ)> タの Lex 周り - miau's blog?

SHJSと萌共通の泣き所そもそも論を言えば入力に対応した stateを一つ一つ定義していけば対応できなくもないしRubyの括弧を使った %記法%r(pattern)flag のようなものでは括弧に分類される文字種が 4つしかなかったために実際そうしたのだが非英数1ト文字や識別子が使えるとなると状態数があっという間にふくれあがってしまう

SHJSの場合はJavaScriptであることと eval()で評価されることを利用してネイブの RegExpオブジトの代わりに execメソドと lastIndexプロパを定義したオブジトを登録することで抜け道を用意できるように感じたがどんな形で特定のキャプチャを参照するのか決めかねた

今日試しにダウンロドしてみた K2Editorではヒドキュメトの色分けが可能なようだ配布パッケージに含まれる Ruby.txtK2Editor.chmによると書式はこう

・<<(["'`]?)(\w+)\1 .... ^$2$
    ヒアドキュメント1。後ろのディスクリプターは行内に唯一でなければ
    ならない。

右側の検索文字列には後方参照が使えます。 左側で()でくくってグルーピングしたマッチ文字列を 右側の検索文字列の中で取得できます。

取得するには K2Editorの置換機構の 後方参照と同じように$1,$2などを使います。

\1\2でなくて $1$2だから右側のパターンは左側のパターンマッチングが終わった後で置換されてからコンパイルされるのかも

SHJS(と萌)にあてはめた場合$1$2がどのマッチングのキャプチャを指しているのかが明らかではないというところで二の足を踏んでいる次第

 @2010-04-08: くわえて

  formatted_text = <<TEXT.strip.gsub(/\t/, " "*8)
TEXT
  texts = [<<TEXT1, <<TEXT2]
TEXT1
TEXT2

こんなんどうする?


20090808() docs.tdiary.orgがルトから 403 Forbiddenで読めないプラグインの説明が読めない

最終更: 2019-12-01T02:10+0900

[SHJS] shjs-0.6にバトラックを

20090525に書いたことをやってみたsh_ruby.jsは巨大なのでとりあえず 0.6/sh_main.js0.6/lang/sh_javascript.js (lang/sh_javascript.js)どちらの sh_javascript.jsトラックのないーマル sh_main.jsと組み合わせることもできるつもり(2種類の langァイルをメンテナスするのは面倒くさいもんね)0.6/sh_main.jsが自分でも見直したくないソースになっているのは否定できない(だからおおっぴらにリンクしていない)そういう人間はこう言うので「動いたもんが勝ち

 "正しい\
  文字列(ECMAScript 5th ed.の場合)"
 "不正な
  文字列(ですらない)"
 /* 正しい
    コメント */
 /* 閉じていない
    コメント?

ーマルージョン 0.6SHJSと違うのは一つの正規表現で始まりから終わりまでマッチングできない対象(複数行にまたがるものとか)に対して最初の文"」や/*を見て文字列だコメトだと決めてかかった結果を後で修正できること

/*があったここからコメトらしい*/が見つからないっぱりコメトではないという判断が改行をまたいでできる


 @2010-04-13 文字列リテラル内の改行は不正らしい

NOTE 文字 LineTerminatorそれにバックスラッシ\ を先行させても文字列リテラル内には出現できない

http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/7_Lexical_Conventions.html#section-7.8.4

以前っちなんだろう?と調べたとき\(改行)は空文字列と解釈されるシーケスだと書かれてるの(そういうエスケープシーケスの一覧表)を見たんだけど実際は違ったらしい

一次情報にあたらなければ同じミスをおかすんじゃないかと手許にあFinal final final final draft Standard ECMA-262 5th editionというタトルの pdfを開いてみた(3rd ed.ではなく 5th ed.だということに注)

A line terminator cannot occur within any token except a StringLiteral. Line terminators may only occur within a StringLiteral token as part of a LineContinuation.

Final final final final draft Standard ECMA-262 5th edition(pdf) 7.3

NOTE A line terminator character cannot appear in a string literal, except as part of a LineContinuation to produce the empty character sequence. The correct way to cause a line terminator character to be part of the String value of a string literal is to use an escape sequence such as \n or \u000A.

Final final final final draft Standard ECMA-262 5th edition(pdf) 7.8.4

日本語にもそういう罠があるけど英語だとうっかり正反対の意味にとってしまうことがあって恐いそれでも行継続の意味に \(改行)を使う(それは空文字列として解釈される)ことは exception(例外)として認められているように読める

3rdから 5thに更新するにあたり現状を追認するように書き換わったのかもしれないけど……ECMAScript3の仕様はどこ?


面倒くさがらずにダウンロドしてきた

NOTE A 'LineTerminator' character cannot appear in a string literal, even if preceded by a backslash \. The correct way to cause a line terminator character to be part of the string value of a string literal is to use an escape sequence such as \n or \u000A.

Microsoft Word - Ecma-262.doc(pdf) 7.8.4

5thexceptった部分に even ifが使われている現バージョンでは文字列リテラル内で\(改行)の使用は明確に否定されてた

というわけで上のサンプルソースの記述を正しくなるように変更しました


20090313()

最終更: 2014-12-24T10:54+0900

[SHJS] SHJSに行番号表示機能を

個人的にはなくても不便はないけども番号を表示する方法のアテができたので

 番号を表示する方法

求める条件は

  • 選択&コピーで(改行コドまでは無理にしても)元のソースコドが手に入ること余分に行番号までコピーされるなんてもってのほ
  • 開始行番号が指定できることできれば非推奨な <ol start="555">以外の方法で(Chili 2.2はこの方法だ)

SyntaxHighlighterのように "view source", "copy to clipboard"機能を用意して行番号が一緒にコピーされる欠点をカバーするのは次善の策

WP-Syntaxっているように12列のテーブルを作って左の列に行番号を右の列にハイラトされたソースコドを配置するのはサポトするブラウザも多そうで良さげ。

でも行番号あり・なしで二通りの出力フーマトを用意するのはスクリトのサイズの面から避けたい何と言っても、忘れていたけどshjs-0.4.2をいじくったものであるこの日記の /shjs/sh_main.js はハイラトするついでに、各行に <span class="odd"><span class="even">というタグをかぶせていたのだった(しかも 3行の追加だけで)その方面でいくことにする

つまりCSS2counter-reset, counter-increment, counter に全面的に頼った方法contentで追加した文字列がコピペ不能なのがかえって幸いしたFx 3.0.7Safari 3.2.2Opera 9.64IE8で期待通りの表示を確認した(※末尾に追記あ)

 スタイルシトに追加したルール

pre.sh_sourceCode.sh_numbered .odd:before,
pre.sh_sourceCode.sh_numbered .even:before {
  counter-increment: sh_sourceCode;
  content: counter(sh_sourceCode, decimal-leading-zero) ": ";
}

 sh_main.js (version 0.4.2)に加えた変更

--- sh_main.js-0.4.2	Mon May 12 23:07:40 2008
+++ sh_main.js	Fri Mar 13 23:29:34 2009
@@ -60,6 +60,8 @@
     currentStyle = style;
   };
 
+  var oddLine = false;
+
   var endOfLinePattern = /\r\n|\r|\n/g;
   endOfLinePattern.lastIndex = 0;
   var inputStringLength = inputString.length;
@@ -78,6 +80,7 @@
     }
 
     var line = inputString.substring(start, end);
+    builder.startElement((oddLine = !oddLine) ? 'odd' : 'even');
 
     var matchCache = null;
     var matchCacheState = -1;
@@ -158,6 +161,7 @@
       builder.endElement();
     }
     currentStyle = undefined;
+    builder.endElement();
     if (endOfLineMatch) {
       builder.text(endOfLineMatch[0]);
     }
@@ -307,8 +311,13 @@
 @param  element  a DOM <pre> element containing the source code to be highlighted
 @param  language  a language definition object
 */
-function sh_highlightElement(htmlDocument, element, language) {
+function sh_highlightElement(htmlDocument, element, language, firstline) {
   sh_addClass(element, "sh_sourceCode");
+  if (firstline !== null && ! isNaN(firstline)) {
+    // cssのセレクタで区別できるように。
+    this.sh_addClass(element, "sh_numbered");
+    element.style.counterReset = "sh_sourceCode " + (parseInt(firstline) - 1);
+  }
   var inputString;
   if (element.childNodes.length === 0) {
     return;
@@ -345,7 +354,8 @@
       if (prefix === "sh_") {
         var language = htmlClass.substring(3);
         if (language in sh_languages) {
-          sh_highlightElement(htmlDocument, element, sh_languages[language]);
+        // firstlineなんて非標準属性をでっちあげないで
+        // スクリプトにパラメータを渡す方法は?
+        // (class属性を乱用するのは気に入らない)
+          sh_highlightElement(htmlDocument, element, sh_languages[language], element.getAttribute("firstline"));
         }
         else {
           throw "Found <pre> element with class='" + htmlClass + "', but no such language exists";

sh_main.js (version 0.5)への変更も似たようなものだけどsh_load()の中にも変更すべき場所がある

sh_main.js (version 0.6)を対応させるのは面倒なので省略0.4.2も実はそうだったんだけどshjsはスタイルのネトを想定していない例えばこれ

// URL inside comment. <http://vvvvvv.sakura.ne.jp>

ハイラトされた結果の HTMLはこうなる

<span class="sh_comment">// URL inside comment. &lt;</span><span class="sh_url"><a class="sh_url" href="http://vvvvvv.sakura.ne.jp">http://vvvvvv.sakura.ne.jp</a></span><span class="sh_comment">&gt;</span>

フラトな構造でcomment, url, comment3つの要素が並んでいるcommenturlを含むような構造にはならない0.6ではハイラト前後のタグ構造をマージする仕組みになっているから0.4.20.5のように ad hocなごまかしができなくてまずはこの前提を取り払わなければいけない……

 () hikidoc.rb (revision 108) への変更

<<< language, number
>>>

<pre class="sh_language" firstline="number">
</pre>

に変換します。

--- hikidoc.rb.108	Thu Aug 28 22:11:00 2008
+++ hikidoc.rb	Fri Mar 13 23:05:05 2009
@@ -335,7 +378,7 @@
     @output.preformatted(@output.text(text))
   end
 
-  BLOCK_PRE_OPEN_RE = /\A<<<\s*(\w+)?/
+  BLOCK_PRE_OPEN_RE = /\A<<<\s*(.*\S)?/
   BLOCK_PRE_CLOSE_RE = /\A>>>/
 
   def compile_block_pre(f)
@@ -665,9 +706,18 @@
     end
 
     def block_preformatted(str, info)
-      syntax = info ? info.downcase : nil
+      syntax, firstline = *(info ? info.split(/\s*,\s*/) : [])
+      syntax = syntax.downcase if syntax
+      firstline = /\A[-+]?\d+\z/.match(firstline).to_a[0] if firstline
       if syntax
         begin
+          attr_firstline = firstline ? %Q( firstline="#{escape_html_param firstline}") : ""
+          @f.print %Q(<pre class="sh_#{escape_html_param syntax}"#{attr_firstline}>), text(str), "</pre>\n"
+          @f.puts inline_plugin(%Q(shjs #{syntax.dump}))
+          return  
+
           convertor = Syntax::Convertors::HTML.for_syntax(syntax)
           @f.puts convertor.convert(str)
           return

 : コピペまでは試してなかった

お試しください

Firefox> 行番号が選択されたり選択されなかったりする。見た目の選択範囲に関わらず行番号はコピーされない。
Safari> 行番号も選択範囲に入るがコピーはされない。
Opera> 行番号がコピーされる。
IE8> 行番号がコピーされる。
ダメダメだあ(この機能は封印しよ)

 追記@2009-03-27: 最後で全部ひっくりかえしちった

っぱり一行二列の表を作る方法でいくことにした

この方法だとpreを一旦取り除いて tableの下に追加する関係からか同じ preにハイラト処理が二回走ってしまう(getElementsByTagName()で得られる NodeListliveであるということ)sh_sourceCodeというクラス名を目印に二度目以降の処理をスキップするよう動作を変更した

Internet Explorer8になっても一筋縄ではいかないようで……左右の列の<pre>の高さがデフトスタイルシトと同じ font-size:80%でないと揃わないIE8互換表示」やIE7ドだと揃うんだけど

二重処理を防ごうと Array.prototype.sliceを使って NodeListArrayに変換しようと思ったらまたしても IEの壁オブジトを指定してくださいと相変わらずわかりにくいエラーメッセージ(prototype.jsが愚直にループをまわしてるのは IEのせいかも)

<table>を使うとその中の <pre>の幅が内容に同期している(最小にして十分なサイズ)他の <pre>と同じようにいつでも本文と同じ幅に揃えたいな

 追記@2009-04-02: 0-paddingオプションと(暇だな)

<pre class="sh_javascript" firstline="00339">
  このような <pre>を出力すると……
</pre>
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
sh_putLinenumber: function(element, param, inputString) {
  var startline = parseInt(param, 10);
  var opt = /^([-+]?)(0*)(\d+)/.exec(param);
  var opt_explicit_sign = (opt[1] === '+') ? '+' : '';
  var opt_zero_padding = (0 !== opt[2].length) ? new Array(opt[2].length + opt[3].length + 1).join('0') : '';
  var re_zero_padding = new RegExp('^0+(?=\\d{' + opt_zero_padding.length + '})');
  var nums = inputString.match(/(?:\r\n?|\n)(?!$)|$/g);
  if (0 !== opt_explicit_sign.length || 0 !== opt_zero_padding.length) {
    for (var i = 0; i !== nums.length; ++i) {
      nums[i] =
        (0 < startline + i ? opt_explicit_sign : startline + i < 0 ? '-' : '') +
        (opt_zero_padding + Math.abs(startline + i)).replace(re_zero_padding, '') +
        nums[i];
    }
  }
  else {
    for (var i = 0; i !== nums.length; ++i) {
      nums[i] = '' + (startline + i) + nums[i];
    }
  }

  var d = element.ownerDocument;
  var e = {table:'table', tbody:'tbody', tr:'tr', tdLeft:'td', pre:'pre', tdRight:'td'};
  for (var p in e) {
    e[p] = d.createElement(e[p]);
  }
  element.parentNode.replaceChild(e['table'], element);
  e['table'].appendChild(e['tbody']).appendChild(e['tr']);
  e['tr'].appendChild(e['tdLeft']).appendChild(e['pre']).appendChild(d.createTextNode(nums.join('')));
  e['tr'].appendChild(e['tdRight']).appendChild(element);
  e['table'].className = 'sh_sourceTable';
  e['pre'].className = 'sh_sourceCode sh_numbers';
  return element;
},

341-344346-354358行がオプションのために追加した部分(SyntaxHighlighter2.0の行ハイラト機能はこういときにつかうのだなイラネと思っていたのを改めま)

固定幅というわけではなくて0の数以上に繰り上がれば桁が増える上の場合では 99999行目を超えたときトする段で気付いたが最低でも 92行のソースコドを貼らないと恩恵に与れない……

正規表現を持ち出すまでもなく適切な数の 0をくっつけるだけでよかったんだね(> JavaScriptのビトインオブジトの拡張:ゼロパング - 気まぐれショウルーム)先に調べよう過去に適切な数の 0を知るために log(10)をとればいいと無邪気に考えていた苦い記憶があるので最初に正規表現を持ち出してしまった(それもどうだ?)という事情があったりもするんだけど(Number.toString(10).lengthで済んでしまうなんて)

 345行目の /(?:\r\n?|\n)(?!$)|$/g というパターンについて

<pre>直後の改行は存在しないかのように扱われるが</pre>直前の改行は存在する(スクリトで取得できる)ものの表示されない(4つのブラウザで確認)というわけで末尾の空行に行番号を付けてしまうと列の左右で行の数が一致しなくなる(だから除外する)


Google Chrome(1.0.154.53)

<pre>.innerHTML = <pre>.innerHTML

とやるたびに先頭の改行文字を取り除いていってしまうんじゃないか? 個別のブラウザ対応は切りがないし完全対応は不可能なので行番号を付けるときは <pre>の最初と最後の行を空行にしないのが最も安全

トンデモ IEさんは <pre>.innerHTML= だろうと <tag style="white-space:pre">.innerHTML= だろうと空白トリミングしてくれますしね

 追記@2009-04-04: 一行二列の TABLE方式にしたら shjs-0.6での対応も簡単だったので

トが不十分なのでlangァイルの自動読み込み部分など一度も実行されていない部分が動くかは不明

最小化方法は JSMinためしに YUI Compressorにもかけてみたがローカル変数の短縮を全くやってくれなくて JSMinと大差ない結果だった一番外側の無名関数の実行部分をとりのぞいたらちゃんとローカル変数名の短縮もやってくれた

小手先の変更もいくつか加えた(ブラウザ判別コドの実行を一度だけにしたり << 関数の中で分岐するんでなく判別結果で関数を取り換え)


20081223() 新☆はてブ < スクロールが重いからピンを抜いたのにカテゴリを選び直すだけで元に戻る鳥頭そこは Cookieを使うべきところです。(潔癖症の人はどうせ拒否設定してるでし)

[SHJS][javascript] SHJS-0.6がリリースされていた(20081215)

アナウスされている変更点は…… (: 日本語部分は俺の勝手な訳のような注釈のようなも)

December 15, 2008 - SHJS 0.6

SHJS 0.6 is available for download.

SHJS 0.6 includes several new features, improvements and bug fixes:

  • SHJS is now distributed under version 3 of the GNU General Public License. (Older releases of SHJS were distributed under version 2 of the GNU GPL.)

    ライセスが GPLv2から GPLv3へ変更

  • Markup inside pre elements is now preserved.

    PREタグの中の HTMLークアップが保存される(以前は Node.dataを再帰的に取り出したもの乱暴にいうと PRE.{innerText|textContent}に相当するものが利用されていたver.0.5ではマークアップとして <br>のみが考慮されていた)

  • Several new languages (from the latest release of GNU Source-highlight) are included: S-Lang, Scala, Java properties files, Desktop files, LSM (Linux Software Map) files, Xorg configuration files, RPM spec files, Haxe, LDAP files, GLSL, Objective Caml, Standard ML, JavaScript with DOM, and C (separate from the C++ language file).

    最新の GNU Source-highlightから新しい言語ファイルを追加JavaScriptには DOMーワドを含んだ lang/sh_javascript_dom.jsが追加された(sh_javascript_dom = sh_javascript + applicationCache|closed|Components|content|controllers|crypto|defaultStatus|dialogArguments|directories|document|frameElement|frames|fullScreen|globalStorage|history|innerHeight|innerWidth|length|location|locationbar|menubar|name|navigator|opener|outerHeight|outerWidth|pageXOffset|pageYOffset|parent|personalbar|pkcs11|returnValue|screen|availTop|availLeft|availHeight|availWidth|colorDepth|height|left|pixelDepth|top|width|screenX|screenY|scrollbars|scrollMaxX|scrollMaxY|scrollX|scrollY|self|sessionStorage|sidebar|status|statusbar|toolbar|top|window + alert|addEventListener|atob|back|blur|btoa|captureEvents|clearInterval|clearTimeout|close|confirm|dump|escape|find|focus|forward|getAttention|getComputedStyle|getSelection|home|moveBy|moveTo|open|openDialog|postMessage|print|prompt|releaseEvents|removeEventListener|resizeBy|resizeTo|scroll|scrollBy|scrollByLines|scrollByPages|scrollTo|setInterval|setTimeout|showModalDialog|sizeToContent|stop|unescape|updateCommands|onabort|onbeforeunload|onblur|onchange|onclick|onclose|oncontextmenu|ondragdrop|onerror|onfocus|onkeydown|onkeypress|onkeyup|onload|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onpaint|onreset|onresize|onscroll|onselect|onsubmit|onunload)

  • Many other languages have minor improvements.

    言語ファイルのアップデ

  • Compressed .min.css stylesheets are now included in the distribution.

    最小化した CSSァイルを同梱(.js.cssYUI Compressorを使用ver.0.5までは .jsのみが JSMinで処理されてい)

Please note that the format of language-specific JavaScript files has changed in SHJS 0.6. JavaScript language files from version 0.6 will not work with sh_main.js from previous releases, and vice versa. Make sure you upgrade both the sh_main.js file and language-specific files.

古い言語ファイル(lang/*.js)と新しいメイスクリ(sh_main.js)は互換性がない(逆も同じ)両方入れ替えるべし

大きな変更は <pre></pre>内の HTMLークアップがシンタックスハイラト後も保存されること(タグがたすき掛けになるときはどうするんだろ)

言語ファイルの変更は小さくて"next""regex""style""exit"というプロパを持ったパターンオブジトが3要素の配列になっている

 異種document対応が必要では? (sh_main.js)

function sh_highlightElement(element, language) {
  sh_addClass(element, 'sh_sourceCode');
  var originalTags = [];
  var inputString = sh_extractTags(element, originalTags);
  var highlightTags = sh_highlightString(inputString, language);
  var tags = sh_mergeTags(originalTags, highlightTags);
  // この documentFragmentはグローバル変数の document由来。
  var documentFragment = sh_insertTags(tags, inputString);
  while (element.hasChildNodes()) {
    element.removeChild(element.firstChild);
  }
  // element.ownerDocument != documentFragment.ownerDocumentのとき失敗しませんか?
  element.appendChild(documentFragment);
}

コメトを参照のことIEのバージョンが 5.5くらいだった時に失敗したような記憶が根拠で確証はないしレアケースだとは思うけど(フレームをまたいで sh_highlightElement(element, language)を呼び出したとき(=スクリトとエレメトが異なドキュメトに属するとき)に起こるかな)

 タグのたすき掛けの結果

 before
<pre class="sh_ruby">
require 'sqlite3'
<strong>require</strong> 'sqlite3'
<strong>req</strong>uire 'sqlite3'
</pre>
<pre class="sh_javascript">
/*
http://example.com
http://example<em>.</em>com
*/
</pre>
 after
<pre class="sh_ruby sh_sourceCode">
<span class="sh_preproc">require</span> <span class="sh_string">'sqlite3'</span>
<strong><span class="sh_preproc">require</span></strong> <span class="sh_string">'sqlite3'</span>
<strong><span class="sh_preproc">req</span></strong><span class="sh_preproc">uire</span> <span class="sh_string">'sqlite3'</span>
</pre>
<pre class="sh_javascript sh_sourceCode">
<span class="sh_comment">/*</span>
<a href="http://example.com" class="sh_url">http://example.com</a>
<a href="http://example.com" class="sh_url">http://example</a><em><a href="http://example.com" class="sh_url">.</a></em><a href="http://example.com" class="sh_url">com</a>
<span class="sh_comment">*/</span>
</pre>

SHJSの挿入するタグは必要に応じてぶつ切りにされるみたい

 追記@2009-02-25: 手製の言語ファイル( rubyjavascript)0.6ーマトに変換した(最小化方法は依然として JSMin)

移行スクリトはこれ( migrate_05_06.js )shjs-0.5までの lang/sh_*.jsァイルドロップすると lang/sh_*.06.jsというファイルができてくるという寸法ちなみに JScript

トもかねてバージョン 0.6を走らせてみたけど軽くなってる道理がない*のでこの日記では shjs-0.4.2に手を入れたものを使い続けている

 追記@2009-04-06: 0.6いいね

言語ファイルのフーマト変更は速度的に有利

パターンマッチの結果を Stateをまたいで保存するようになっているのでこの日記の sh_ruby.jsのようにあっちこっち跳びまわる言語ファイルに有利に働くいちばん時間を消費しているのが RegExp.exec()DOMツリーへの HTML断片の追加なのでパターンマッチ結果のキッシュは大事(っとも 0.4.2のときからキッシュの拡大は個人的にやってい)

* <pre>内のマークアップを保存するためにハイラト前と後の二つの HTML文字列をマージしているでもその機能俺個人はいらないのよね


20080820() [Firefox] CSScontentで追加した文字はコピペできないアイタタタ

[SHJS] SHJS-0.5 がリリースされてた(2008-08-18)

  • SHJS can now automatically load language script files (feature request #2007022 - thanks to Michal Nazarewicz and Eugene Marcotte).
  • Highlighting of C/C++ and JavaScript has been improved.
  • A new language file for Oracle SQL has been added (thanks to Mike Breeze).
  • Case-insensitive regular expressions are now handled more efficiently.
  • SHJS now treats <br> tags as line terminators in input (bug #2054144 - thanks to Altforweilerer).
  • Compressed .min.js files are now generated with YUI Compressor.
http://shjs.sourceforge.net/doc/news.html

 メモ

  • languageァイルの自動読み込みは Msxml2.XMLHTTPXMLHttpRequestを利用する

    <script>タグを挿入するのかも*と思っていたが今風のやり方だった(SourceForgeFeature Requestsで両派の議論があったようで0.5では Asynchronous XMLHttpRequestを採用したけど将来かわるかも)

  • lang/sh_javascript.jsの全変更点(多分)

    • import, package, prototypeーワドのハイラトがなくなった
    • 正規表現リテラルのハイラトルールが追加された
    • class, interfaceのハイラトルールがなくなった
    • $を含む関数名に対応した
    • /**コメ*//*コメ*/ のネトに対応しなくなった

    新たに対応したものも対応が外れたものもあるがどちらも JavaScriptの仕様に近づくための変更という点は共通

    それでもやっぱり Javaっぽいのはjava.langまるごとインクルドだった前バージョンの source-highlight-lang/javascript.langjava.langの中身をベースに足し引きしたものに変わったに過ぎないから

  • 「大文字小文字を無視する正規表現を効率的にっていうのは lang/sh_sql.jsを見るにこういうこと

    /[Vv][Aa][Rr][Cc][Hh][Aa][Rr]/ // ver. 0.4.2
    /VARCHAR/i                     // ver. 0.5

    ……

  • YUI Compressorはローカル変数名を縮めることで JSMin以上の圧縮を図る

    他にもobj["prop"]obj.prop(可能なら)したり連結されるリテラル文字列を予め一つにしたりオブジーテイション(って言うの?)のプロパ名部分の引用符を取り除いたり({"p1":v1, "p2":v2} -> {p1:v1, p2:v2})するらしい

    おれは JSMinでアグレッシブ(level 3 of 3)に最小化する(不要な空白と全ての改行が取り除かれるのでセミコロンインサーションの余地がなくなって一つのセミコロンも省略できなくなる)のが好きなんだけど何より Javaの実行環境がないからYUI Compressorは動かない……

 SHJSについて (勝手に宣)

  •  JavaScriptで実装されています

    ブラウザ(クライアトサ)で実行されるのでサーバーの負荷が増えません

  •  ダウンロド量は最小限に保たれます

    メイスクリ(最小化されたものが数KB)は必須ですが各言語ファイルはオプションです。名前も知らない言語の定義ファイルまでブラウザにダウンロドしてもらう必要はありません

  •  ハイラト対象の言語名の指定が必須です

    自動認識のような不確かなものに頼りません(自分の書いているものが何語なのか知らない人は少ないでしょうあえて情報を削ってスクリトの仕事を増やす必要はありませ)

  •  言語の定義はなんでもありです

    言語ファイルは、状態オブジトの配列です。状態は正規表現のパターンを一つ以上持ちッチしたパターンにより配色と遷移先を決定しま状態が増えるのをいとわなければ何でもできます

    ダブルクーテーション文字列や数字や URLなどにマッチする正規表現を並べて順番にマッチングさせるだけのハイライターより一段上のパターン認識が可能です。(有名どころの SyntaxHighlighter 2.0XRegExpというライブラリを使用していてこれが Perl5や鬼車や .NET並の正規表現を JavaScriptでも使用可能にしています。これも一歩踏み出す一つの方法ですがほとんど XMLのハイラトでしか使われてないようにも見えるのがもったいな)

 この日記で使っているお手製の SHJS言語ファイル(RubyJavaScript)*4

JavaScriptの方は letみたいな新しいキーワドには対応していないが、JScript5.5(ECMAScript3)に準拠したスクリトのハイラトに可能な限り対応しているJavaもどきの実装とは全然違います。

Rubyの方もがんばったけどこちらは正規表現による字句解析レベルでは判断の付かない要素が多くて例えば

  str1 = % hoge ; #=> "hoge"
  str2 = "%04d-%02d-%02d" % [2008, 8, 20] #=> "2008-08-20"

% をメソドと判断する(下段)%!string! とする(上段)かは文脈がないと決められない現在は後者が誤って %!string! と判断されている(%!string!記法の区切り文字としてスペースを認めなければより多くのケースで妥当な表示が得られるのはわかっているが……)また、改行を含む %!string! リテラルにも対応していない(はてなはこれができる悔しい)っこを使った %記法( %[string]など )では改行を含むことができる

既知の不具合はこれだ(知らないだ)

* その場合スクリトが実行されないことがあったような……(検索結果>http://la.ma.la/blog/diary_200612061928.htm ) と思ったがIEinnerHTMLを使った場合の話だったとはいえDOM<script>エレメトを作成することは可能で実行もされるというのだろうか?

 厳密ではない感覚的な言葉

 この文では普通の正規表現以上の表現力(例えばかっこの対応を調べられる)があるのを説明できていないような(ある状態から別の状態へ移動するだけでなく後戻りすることもできるからというのでは説明になっているだろうか?

*4 200812月にリリースされた shjs-0.6でフーマトが変更になったので shjs-0.5


20080530() ViewVCURLをパラメータとして与えて外部の生Subversionリポトリに ViewVCの皮をかぶせたい

[SHJS] shjs-0.4.2: 重箱の隅っつきます

$GREPしてみたらこういうものが無数に見つかっただいたいが一行コメトの中に対応した state終了条件は行末でURLを含んでいれば sh_urlとしてマークする

    {
      'exit': true,
      'regex': /$/g
    },
    {
      'regex': /(?:<?)[A-Za-z0-9_\.\/\-_]+@[A-Za-z0-9_\.\/\-_]+(?:>?)/g,
      'style': 'sh_url'
    },

URLが改行の直前まで続いていれば終了条件としての行末の検出がスキップされて一行コメトが次の行まで継続するまさしく 20080513p01の問題の繰り返し

結局sh_main.jsに非互換な変更を加えるのは問題大ありだと判明したので sh_javascript.jsで対応することにしましたよ

  [ // state 2: in "string"
    {
      regex: /\\[\\"]/g
    },
    {
      next: 6,
      regex: /\\$/gm
    },
    {
      exit: true,
      regex: /"|$/gm
    }
  ],
  [ // state 6: eat an end-of-line ※空行は食べられないよ
    {
      exit: true,
      regex: /^/gm
    }
  ]

動作確認は昨日の日記


20080529() 内容と関係のない画一的な帯は間違いなくゴミ(コバト文庫のことです)帯の下を意識させるデザインのときの帯もゴミ役に立つ文字が書いていない帯もゴミ帯を外すと間抜けなカバーはダメダメ(最近は買った本の帯をカバーの下に隠すことが多い<でも捨てられな)

[SHJS] shjs-0.4.2: 重箱の隅っつきます

例えばJavaScriptのリテラル文字列では \ と改行のシークスは空文字を意味しているつまりこういうこと

var str = "空白を含まない\
ひとつながりの文字列です";

このシークスを認めるようにダブルクーテーション文字列の終了条件として次のようなものを shjs/lang/sh_javascript.js に含めてみたがうまくいかなかった

  [ // "string"
    {
      // \\ と \" と \(改行) を 1つのシークェンスとして
      // 食べてしまう。終了位置を見誤らないためであって、
      // 特に何をするということもない。/\\(.|$)/gm でも構わない。
      regex: /\\(?:[\\"]|$)/gm
    },
    {
      // エスケープされていない " に出会ったら "~" の中に
      // いるという状態(state)から exitする。
      // " がないまま行末に達したら、終端されていない不正な
      // 文字列だと判断して、やはり exitする。
      exit: true,
      regex: /"|$/gm
    }
  ],

少し前行末に達した時点でマッチングを打ち切っていたのが間違い$は空文字列にもマッチする全てのマッチに失敗するまで続ける必要があった(20080513p01)と自分のミスを書いてこれを修正したのだがshjs-0.4.2はもちろん正しく全てのマッチが失敗するまで続けている

そうすると何が起こる/\\$/gm にマッチした後でも /"|$/gm のマッチに成功してしまい結果行末に \ があろうがなかろうが exitしてしまう

もちろん行末に達したからといってすぐにマッチングを打ち切っては 20080513p01と同じ間違いを犯すことになるので同一 state内で*二回以上*行末にマッチすることがないように sh_main.jsを変更した

内の方のループの頻繁に実行される部分に if が増えたのが気に入らないものの悪影響のある非互換でもないし首尾は上々だし(冒頭の文字列のハイラト結果が見本)悪くない

var str = "終端されていない
不正な文字列です";

 追記@2008-05-30: この場合はどうする?

var str = "終端されていない\"
不正な文字列です";

*たまたま*行末にある \" にマッチしたことで終了条件である行末の検出がスキップされて次の行までが文字列だと判断されている*\" とのマッチは \$ と違い行末を要求していないからこの場合は一行目で exitしてほしい

* 20080530p01で修正したので文章とハイラト結果が食い違っているかもしれない


20080527() [Firefox] 領域を選択してのソース表示はスクリトに書き換えられた最新の HTMLを反映しているのが便利

[Firefox][javascript][SHJS] <pre>が真っ白になり黒色の領域が出現する

例えばこのページ http://vvvvvv.sakura.ne.jp/ds14050/diary/20080112-7.html Endーで末尾に移動して PageUpで戻っていくと空白の PREが目に入ると思うその少し上にはページの内容を覆い隠す黒い領域があるはず。(そうでなければ修正されたのだろうFirefox2で最初に確認しFirefox3.0RC1でも直っていなかった)

大量の PREが存在したり一つだけでも巨大な PREが存在する場合に起こる様子innerHTMLPREの内容を置き換えているのも原因になっているかもしれない

画面の末端にスクロールした状態でページをリロ(F5 or Ctrl+R)すると下方の PREが正常に表示される反面上端付近の PREに同じ問題が生じる遠方の PREの書き換えに問題があるのでは?

っ白の PREの中で右クリックしたりテキトを選択したりといったアクションを起こせば正常に表示されることが多い


あとPREの中から開始した選択は PREの外に出られなかったり(これは TEXTAREAと違い PREでは Ctrl+Aで全文選択ができないために用意された代替手段だという気もす)


20080513() qr//と同じものは Rubyにないと思っていたが Regexp#to_sがそれ正規表現リテラルの式展開と組み合わせて使おうhikidoc.rbでは昔から使われていたのに何を見ていたの

[SHJS] URLのハイパーリンク化とバグ潰し

オリジナルの sh_javascript.jsはコメトの中の URLっぽい部分とメールっぽい部分をハイパーリンクにしていた機能が劣るのは遺憾なので sh_javascript.jssh_ruby.jsコメトと文字列の中の URLっぽい部分をハイパーリンク化する機能を追加した

その過程で気付いた一行コメトの終了条件などに使われている $アンカーのマッチングが行われない場合があったのを修正した(行末に達した時点でマッチングを打ち切っていたのが間違い$は空文字列にもマッチする全てのマッチに失敗するまで続ける必要があった)これは自分が 2008-02-25に持ち込んだバグでオリジナルには存在しない

 サンプル /トケース

  • 一行目:コメト内の URLはリンクになっているか?
  • 二行目:一行目のコメトの続きだと誤認されていないか?
# http://vvvvvv.sakura.ne.jp/ds14050/badboy/log/
How is this line highlighted ?

 最新の未来において変更されている可能性のあるファイルへのリンク


20080508() [Vista] 「プログラムから開くが便利なんだけどフォルダを対象にできないのが玉に瑕Unknown\shell\openasdirectory\shell\openasにコピーするとダイアログを開くことはできるがプログラムのリトがコンテクトメニーに展開されたりはしない

最終更: 2009-09-01T05:05+0900

[SHJS][Ruby] '%04d-%02d-%02d' % [2008, 5, 8] がうまくハイラトできない理由

このようにハイラトされます。

'%04d-%02d-%02d' % [2008, 5, 8]

(整形した)HTMLースはこう

<span class="sh_string">'%04d-%02d-%02d'</span> 
<span class="sh_string">% [2008, </span>
<span class="sh_number">5</span>
<span class="sh_symbol">,</span> 
<span class="sh_number">8</span>
<span class="sh_cbracket">]</span>

% [2008, が一つの文字列にされてしまっているどういう判断なのかと調べれば%!string! と同じものだと見なされていた(そのルールは自分で書いたんだけど)

っていたでしょうか? %リテラルの区切りには空白(改行も!)が使えるのでした(alnummbchar以外なら OKっぽい変態すぎる)


20080212() エクスプローラがメモリを放さないプライベトワーキングセトは 14MBでもVistaより前のタスクマネージャが表示していた数字では 215MBになる仮想メモリ不足ってメッセージが何度も出るんですけど

最終更: 2010-03-21T03:27+0900

[javascript][SHJS] JSLint <http://www.jslint.com>

SHJSsh_main.jsを高速化したことを以前書いた(20080204p01)

 対応ブラウザ

SHJSのページには動作を確認したブラウザとして以下が挙げられている

  • Firefox 2
  • Internet Explorer 6
  • Internet Explorer 7
  • Opera 9
  • Safari 3

sh_main.jsの修正版は Firefox2IE7Opera9で正しく動作することの確認と速度の比較を行っている

IE6での確認は IE7から戻すのが面倒なので省略する

Sarari3Vistaで動くものがダウンロドできるので確認してみたところ動いた(表示も正)

いじったことで対応ブラウザが減っていなくて良かった(IE6)

 JSLint

SHJSの作者は Code Conventions for the JavaScript Programming Languagejslint: The JavaScript Verifier かそれに類似した文書を読んでいるに違いない(これらのページを今日発見し)

というのもsh_main.jsJSLintでチックしてみたがこういうエラーしか出なかった

Error:

Implied global: document 362, sh_languages 347, window 332

このエラーは JSLint向けにコメトを埋め込めば取り除けるものだしそうしないと不可避だともいえるもの

 さてさて自分がいじったことでどれだけお行儀の悪いスタイルが混入したのでしょうか
Error:

Implied global: document 207 360, sh_languages 332, window 329

Problem at line 73 character 48: Use the array literal notation [].

   matchCaches = language.matchCaches = new Array(language.length);

Problem at line 86 character 17: 'i' is already defined.

   for(var i = matchCaches.length-1; i !== -1; --i) {

Problem at line 97 character 22: 'i' is already defined.

   for (var i = state.length-1; i !== -1; --i) {

Problem at line 110 character 17: 'i' is already defined.

   var i = (pair[0] & 0x3F);

Problem at line 280 character 15: Use '!==' to compare with '0'.

   while(0 != this._currentStyles.length) {

Problem at line 389 character 14: 'node' is already defined.

   var node = this.free_;
 いいわけ
  • ーカル変数の再宣言に関するものは全て forープで初期化される変数が原因(inode)
  • var array = new Array(length);」をvar array = []; array.length = length;」やvar array = Array.prototype.slice.call({length:length}, 0); と書き換えることは拒否する

    (new Array(length)が一番簡潔で自然な書き)

    (JavaScript 1.7配列内包に書き換えるのには吝かでな)

  • != 0 の代わりに !== 0 と書け? 書き換えましたm( __ __ )m

(一つを除い) 無視できる警告*ばかりで良かった

* 無視したら警告の意味がないforープの変数なんて(古い VC使い以外には)スコープの誤解を招きやすいという理由で避けなければいけないものの筆頭ともいえる


20080204()

[SHJS][javascript] sh_main.jsの高速化

SHJSのブラウザでの実行時間を削るには sh_main.js(SHJSのメイスクリ)を速くするか正規表現を効率的なものにする方法がある(>遅い正規表現(20080116p01))

正規表現に関してできることは限られるうえ知識も少ない(『詳説 正規表現 第三版待ち)ので可能な限り文字クラスや文字集合といわれるものを使うように気を付けただけにとどまる(sh_ruby.js, sh_javascript.js)

メイスクリトの sh_main.jsに対してできることは多いこの日記の現在?の最新ページ(2008112日から7)を表示してsh_highlightDocument()前後での経過時間を表示したところこのようになった

Firefox2IE7(64-bit)IE7(32-bit)Opera9.25
sh_main.js (0.4.2)935ms1050ms1270ms1260±150ms
改変版600ms680ms865ms1200±150ms
削減率36%35%32%5%

ハイラト対象が少なくて数ミリ秒で処理が終わるような場合はオーバーヘドのために改変版の方が 1-2ミリ秒遅くなるがそれよりもスクリトがブラウザをロックする時間が長くなるような場合にこそ速度改善が必要なので OK

代償としてファイルサイズが sh_main.js10.5KiBから 12.7KiB+2.2KiBjsmin圧縮後の sh_main.min.js6.22KiBから 7.82KiB+1.60KiBApacheによる gzip圧縮やブラウザのキッシュに期待します。

 () Operaについて

普段は全く Operaを使わないし詳しくもないむしろ Operaではキーボドを使ったブラウジングもままならないそんな人間が Firefox+Firebugを頼りに sh_main.jsの修正を行ったので Operaの速度が改善しないのは仕方のない部分がある(IEは改善したが)(あんだけいじータルで変わらない方がすごいどこが足を引っぱっているのだろう)リテラル文字列と Stringオブジトの差が他のブラウザより大きいらしいがそれが原因?

EfficientJavaScript - Dev.Opera - 効率的な JavaScript (www.hyuki.com)

Operaでの JavaScriptの実行時間が他のブラウザに比べて長いのははっきりした理由があってOperaはスクリトが全力疾走中であってもユーザーの操作に対する反応を後回しにしたりしないこれは偉いーザーを待たせない代わりにスクリトが遅れるのは当然の代償で仕方がない

スクリトでなく再描画が律速してるから改善しないということ?

 (かんせいしたへびのえにあしをかきくわえるこういとまでは言わない) この日記で使用中のファイルへのリンク

(常に最新版だが一時的にバグが混入していることがあるか)

 追記@日:sh_main.jsをちっと修正

すぐ上のリンク先はすでに変更が反映されている

これら二つの記事を参考に escapeHTML()を変更した測定に使ったページでは 9000回ちかく呼び出されるメソドなので影響はバカにならないといっても 600msったのが 590msを切るようになったというレベルむしろ下請けfunctionを隠蔽できたことの方が嬉しい

escapeHTML()自体sh_builderのインターフェイスではないので外部から呼び出せないようにすべきかもしれないがfunctionをかぶせるたびに呼び出しのオーバーヘドが増える気がしてそうはしていない

 追記@今日

SHJSpatternStackオブジトは外部と完全に独立して動作するのにsh_highlightString()が呼ばれるたびに無名クラスとそのイスタスを作成するような方法がとられているトラクタと prototypeを書こう(sh_highlightString()HTML文書内の <pre class="sh_XXX">の数だけしか呼ばれないから影響は小さい件のページでは 58)

sh_highlightString()からしか使われないのにスタックの可視範囲が広がるのが気になるならっき覚えた無名functionで二つをくるんでしまえば良い

var sh_highlightString = (function(){
  var Stack = function(){
    this.stack_ = [];
  };
  Stack.prototype.getLength = function(){/* ... */};
  // ……
  return function(){
    var patternStack = new Stack();
    /* sh_highlightStringの中身がつづく…… */
  };
})();

まあ速度が改善するわけではないので書き直さないんだけど

 追記@2008-02-25

innerHTMLtextContentinnerTextの使用は堕落だという気もするが冗長な上に呼び出しを重ねることで遅くなる DOMメソドがいけない