2008/01/31


vim_html 普段vimを使っていらっしゃる方は、ソースコードや/etcにある設定ファイル等をブログに書きたいと思う事が多いかと思います。
私のブログでもほぼ7割方ソースコードが含まれるブログ記事となっています。

ソースコードをブログにアップする際、やはりテキストエディタの様にシンタックスに色が付いた常態だと分かりやすいですよね。
世の中には色んな方法があるようです。

ただ、私としてはやはり静的ファイルでHTMLを出力したいし、なるべく多くのフォーマットで、かつマルチバイトに対応していてほしい。
私は普段テキストエディタとしてvimを使っていますが、vimのソースコードハイライト機能はタダモノではなく、かつ対応しているファイルフォーマットの数も :echo len(split(globpath(&rtp, "syntax/*.vim"),"\n"))
とするだけでも500個以上のファイルフォーマットに対応している事が分かります。
さらにvimのオフィシャルサイトに行けば世の中に存在するプログラミング言語のほぼ全てのsyntaxファイルが揃うでしょう。
vimにも、HTML出力の機能が無いわけではありません。「tohtml.vim」を使えば現在ハイライトされているバッファの中身をHTMLファイルにしてくれる機能があります。
#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("Hello, World\n");
    return 0;
}
こんなファイルであれば :TOHtml
とする事で <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>C:/temp/helloworld.c.html</title>
<meta name="Generator" content="Vim/7.1">
</head>
<body bgcolor="#000000" text="#c0c0c0"><font face="monospace">
<font color="#ff6060">#include </font><font color="#ff40ff">&lt;stdio.h&gt;</font><br>
<br>
<font color="#00ff00">int</font>&nbsp;main(<font color="#00ff00">int</font>&nbsp;argc, <font color="#00ff00">char</font>* argv[]) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;printf(<font color="#ff40ff">&quot;Hello, World</font><font color="#008080">\n</font><font color="#ff40ff">&quot;</font>);<br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#00ffff">return</font>&nbsp;<font color="#ff40ff">0</font>;<br>
}<br>
</font></body>
</html>
こんなHTMLを出力してくれます。
ただ...<font>はいただけませんね。

最近のHTMLでは御法度です。HTML Validatorも許しません。HTMLに直接色を埋め込むなんて最近ではタブー化しつつあります。(このサイトには沢山ありますが...)

今回は、「tohtml.vim」から実行される「2html.vim」を使用してブログに最適なHTMLを出力出来るコツを説明して行きます。
「2html.vim」は基本動作を変えられるように複数のオプションを持っています。以下そのオプションについて説明します。

use_xhtml

出力するHTMLをXHTMLに強制します。たとえば<br>は<br />と出力されます。
また<DOCTYPE>も合わせて変更されます。

html_number_lines

HTMLを出力する際に行番号を出力してくれます。ただし同一要素内に出力されますのでマウスで選択すると行番号まで選択されてしまいます。

html_font

HTMLのフォントを強制出来ます。通常はmonospaceが使われますが、これよりも優先したいフォントがある場合に使用します。

html_use_css

コードのシンタックスを<font>ではなく<span>で出力します。
class属性は上記「Comment」や「Statement」といった識別が使用されます。

html_use_encoding

metaタグでcharset指定できます。但し現状の「2html.vim」にはencodingが「cp932」の場合の処理がありませんので、以下のパッチを「2html.vim」に当てる必要があります。
*** 2html.vim   Fri Aug 03 13:23:20 2007
--- 2html.vim.org   Tue Jul 31 09:48:00 2007
***************
*** 162,168 ****
      let s:html_encoding = 'iso-8859-1'
    elseif s:vim_encoding =~ "^cp12"
      let s:html_encoding = substitute(s:vim_encoding, 'cp', 'windows-', '')
!   elseif s:vim_encoding == 'sjis' || s:vim_encoding == 'cp932'
      let s:html_encoding = 'Shift_JIS'
    elseif s:vim_encoding == 'big5'
      let s:html_encoding = "Big5"
--- 162,168 ----
      let s:html_encoding = 'iso-8859-1'
    elseif s:vim_encoding =~ "^cp12"
      let s:html_encoding = substitute(s:vim_encoding, 'cp', 'windows-', '')
!   elseif s:vim_encoding == 'sjis'
      let s:html_encoding = 'Shift_JIS'
    elseif s:vim_encoding == 'big5'
      let s:html_encoding = "Big5"
これでWindowsを使っていらっしゃる人でも「charset=Shift_JIS」と出力されます。

html_no_pre

<pre>を使わずHTML出力する際に使用します。最近はRSSで全文配信する風潮もあるみたいで、その際に<![CDATA[...]]>使いたくない人には有用かもしれません。

html_start_line

ソースからHTMLを生成する際の開始行番号を指定します。

html_end_ilne

ソースからHTMLを生成する際の終了行番号を指定します。

html_ignore_folding

ソースコードがfoldingされていても内部をHTML出力するように設定します。
設定せずにfoldingされているソースをHTML出力すると以下のようなHTMLが出力されます。
#include <stdio.h>

int main(int argc, char* argv[]) {
+---  2 行:printf("Hello, World\n");
}

html_whole_filler

foldingモード時に、追加された行を意味する行「... inserted lines」を表示したく無い場合に設定します。

以上が「2html.vim」で使用できるオプションです。
通常は何も設定されていませんが、以下ではブログ等に貼り付ける際の私なりのコツを示します。
  • スタイルシートを定義する
  • CSSファイルやHTMLファイルの<style>部に以下のコードを追加しておきます。
    .code {
     border-bottom    : 1px solid #777777;
     border-left      : 5px solid #777777;
     border-right     : 1px solid #777777;
     border-top       : 1px solid #777777;
     background       : #555555;
     color            : #ffffff;
     overflow-x       : auto;
     white-space      : nowrap;
     font-family      : monospace;
    }

    /* source code */
    .code>.Comment {
     color: #aaaaaa;
    }
    .code>.Constant,
    .code>.String,
    .code>.Character,
    .code>.Number,
    .code>.Boolean,
    .code>.Float {
      color: #aa7777;
    }
    .code>.Identifier,
    .code>.Function {
     color: #77aa77;
    }
    .code>.Statement,
    .code>.Conditional,
    .code>.Repeat,
    .code>.Label,
    .code>.Operator,
    .code>.Keyword,
    .code>.Exception {
     color: #77aaaa;
    }
    .code>.PreProc,
    .code>.Include,
    .code>.Define,
    .code>.Macro,
    .code>.PreCondit {
     color: #aaffff;
    }
    .code>.Type,
    .code>.StorageClass,
    .code>.Structure,
    .code>.Typedef {
     color: #aaaa55;
    }
    .code>.Special,
    .code>.SpecialChar,
    .code>.Tag,
    .code>.Delimiter,
    .code>.SpecialComment,
    .code>.Debug {
     color: #777777;
    }
    .code>.Underlined {
     color: #00ff00;
     text-decoration: underline;
    }
    .code>.Ignore {
     color: #777777;
    }
    .code>.Error {
     color: #ff0000;
    }
    .code>.Todo {
     color: #0000ff;
    }
    .code>.Folded {
     color: #aaffff;
     background-color: #aaaaaa;
    }
    Internet Explorer6ではセレクタが正しく動作しないかと思いますので修正が必要です。
  • オプションをXHTML使用,CSS使用,PRE未使用モードに設定する
  • ~/_vimrc(un*xでは~/.vimrc)に以下を追加します。
    let g:use_xhtml = 1
    let g:html_use_css = 1
    let g:html_no_pre = 1
  • ソースコードをHTML化する
  • 全体をHTML出力するならば何も選択せず、また部分的にHTML出力するならば行選択(linewise-visual)して
    :TOHtml
    と実行します。
    HTMLには<html>や<body>も含まれますので、実際には<body>から</body>を切り取るといいでしょう。

これで色んなソースコードを皆に見てもらうことが出来るようになります。この方法はあくまでmattnが良いと思った方法ですので、もしかしたらより便利な方法があるかもしれません。
一度CSSさえ設定してあれば、上記の手順1つで簡単にHTML出力出来ます。ぜひコードを晒け出してみて下さい。

mattn the OSS fan.
Posted at by




前のエントリで気づいたのですが、実はJSONとvimって愛称がよいのでは?と気づきました。
確かに複雑なJSON(例えばif文等を含んだりしているもの)は扱えませんが、JSONPが実行出来るならばメソッド引数にデータ本体が渡る為、簡単なものなら解釈出来る事が分かりました。

例えば、以下のメソッドを定義します。
scriptencoding utf-8
function! JsonHandler(data)
  return a:data
endfunction
function! GetJsonP(url)
  let ret = system("curl -s \"" . a:url . "?callback=JsonHandler\"")
  let org = &enc
  let &enc = "utf-8"
  let ret = substitute(ret, '\\u\([0-9a-zA-Z]\{4\}\)', '\=nr2char("0x".submatch(1))', 'g')
  exe "let val = " . iconv(ret, "utf-8", org)
  let &enc = org
  return val
endfunction
function! GetJson(url)
  let ret = system("curl -s \"" . a:url . "\"")
  let org = &enc
  let &enc = "utf-8"
  let ret = substitute(ret, '\\u\([0-9a-zA-Z]\{4\}\)', '\=nr2char("0x".submatch(1))', 'g')
  exe "let val = " . iconv(ret, "utf-8", org)
  let &enc = org
  return val
endfunction

GetJsonメソッドはURLを指定してJSONオブジェクトを取得する関数です。
はてブのコメント一覧であれば、以下のような処理で取得出来ます。
if exists("json")
  unlet json
endif
if exists("jvar")
  unlet jvar
endif
let json = GetJson("http://b.hatena.ne.jp/entry/json/?url=http://mattn.kaoriya.net/web/hatena/20070726110753.htm")
for jvar in json["bookmarks"]
  echo jvar["user"] . " - " . jvar["comment"]
endfor
実行結果は以下の通り(参考:はてブでアーーーーッ!!!)
yheld - アーーーーッ!!!フヒヒ、サーセンwwww
parkbench -
ku0522 - アーーッ!!
tyoro1210 - アーーーーッ!!!
mattn - 自分でアーーーーッ!!!
また、del.icio.usの場合は通常のJSONにデフォルトのコールバックが含まれてしまいますので、vimでは解釈出来ません。しかしJSONPならばメソッドを指定する事で左記javascriptが消えてくれます。専用にGetJsonPという関数を用意しました。
はてブと同様に if exists("json")
  unlet json
endif
if exists("jvar")
  unlet jvar
endif
let json = GetJsonP("http://del.icio.us/feeds/json/mattn.jp")
for jvar in json
  echo jvar["d"] . " - " . jvar["u"]
endfor
とする事で(参考:mattn.jp in del.icio.us) FlashVillage.com - FREE Flash Templates - http://www.flashvillage.com/
その対応に意味はあるのか (Yak blog) - http://www.greenspace.info/mt/2007/07/31/post_38.html
Top Rated - Free Stock Photos - http://public-domain-photos.com/
Niconorati (ニコノラティ) - ブログで今話題のニコニコ動画 - http://pulpsite.net/niconorati/
SourceForge、「優秀なオープンメ[スプロジェクト」の投票結果を発・- ZDNet Japan - http://japan.zdnet.com/oss/story/0,3800075264,20353786,00.htm
IT戦記 - style.cssText の使い処に関する考察 - http://d.hatena.ne.jp/amachang/20070730/1185788557
void GraphicWizardsLair( void ); // Ustream.tvの凄いところは、Flashで実用的なIRCクライアントを作っちゃったところ - http://www.otsune.com/diary/2007/07/30/1.html#200707301
カイ氏伝: Wikipediaの「RSSリーダー」がとんでもない件 - http://blogging.from.tv/archives/000564.html
美輪明宏のチンコの有無を返すAPI作った | dzfl::blog - http://dzfl.jp/blog/2007/07/29/miwa-mojo-api/
美輪明宏のチンコの有無を配信するRSS作った - PRESS RELEASE on VOX - http://asada.vox.com/library/post/%E7%BE%8E%E8%BC%AA%E6%98%8E%E5%AE%8F%E3%81%AE%E3%83%81%E3%83%B3%E3%82%B3%E3%81%AE%E6%9C%89%E7%84%A1%E3%82%92%E9%85%8D%E4%BF%A1%E3%81%99%E3%82%8Brss%E4%BD%9C%E3%81%A3%E3%81%9F.html
Cookie Manager | Javascript Code | All Things Webby - http://insin.woaf.net/code/javascript/cookiemanager.html
[N] 無料で使える18のアプリケーション&ウェブサービス - http://netafull.net/lifehack/021313.html
flivpee - Google Code - http://code.google.com/p/flivpee/
MOONGIFT: ≫ オープンメ[スのFlashムービープレーヤ「Flivpee」:オープンメ[スを毎日紹介 - http://www.moongift.jp/2007/07/flivpee/
TechCrunch Japanese アーカイブ ≫ Pownceが、ついにAPIを公開 - http://jp.techcrunch.com/archives/pownce-moving-to-open-api-eventually/
といった結果が得られます。
本来ならcallbackもvimscriptを呼ばせるべきかもしれませんね。
vimを使ってマッシュアップアプリを作ってみたい人には、便利なtipsかも知れません。
私はライブラリ化するつもりはありませんが、してみたい人がいるならばぜひvimscriptsに登録してみて下さい。
まぁ、「意外と知られていない」という割には自分も知らなかった訳ですが...

the half of mattn is composed of fondness.
Posted at by




まきこみ計画のcozymaxさんに、「blosxom bookmarks plugin」を紹介頂きました。
【Blosxom】bookmarksプラグインを導入

いやぁ我ながら「適当クオリティ」とは恐いものです。コラ
どんどん修正して良い物にしてあげてください。
そしてフィードバックだけはお忘れなく。コラ

御指摘は、ありがたく頂き、速攻でbookmarksプラグインを修正致します。
普段もコマンドプロンプトで生きている程un*x生活が浸透してしまっているので、GUIなftpツールでダウンロードして、修正してアップして...なんて事しませんよ。
vimmerならば、リモート直編集っす。

:e ftp://user@server/path/to/file/file.txt
Enter Password:

ちなみにvim、ftp以外にもscp、http、webdav、rsync、sftp等が使えます。ファイルへのパスが仮想でない分、webdav(URLはdav://)なんか、かなり便利です。
工夫すればsmbclient使って「smb://」にも対応出来るんじゃないですかね。

しかしながら最近、vimのオフィシャルへは一つもパッチを送っていないというありさま。 かろうじてチュートリアルの翻訳を進めているくらいです。
:help mbyte
で出てくるメアドも既に使えません。

シャキっとします。シャキっと。はい。
Posted at by