PsParserを使ってソースを色付きHTMLに変換する
はてなにはスーパーpre記法という、ソースコードをシンタックスハイライトして表示する機能があるのですが、これはPowerShellに対応していないようです。予約語の似ているRubyモードで貼り付けていこうかとも思ったのですが、PowerShell 2.0CTPではパーサを利用できるので、ファイルをパーサーに食わせて結果をハイライトつきのHTMLに変換するスクリプトを書いてみました。引数に、変換するスクリプトファイル名を渡します。エンコーディングはutf8きめうちにしているので、上手くいかなかったら修正してみてください。
パーサの返すトークンには、Unknown、Command、CommandParameter、CommandArgument、Number、String、Variable、Member、LoopLabel、Attribute、Type、Operator、GroupStart、GroupEnd、Keyword、Comment、StatementSeparator、NewLine、LineContinuation、Positionという種別があるのですが、それぞれの名前に"Ps"を付けたクラスのspanタグで括って出力するので、対応するクラスをCSSに定義しておけば、好みの色で表示する事が出来ます。
$cont = Get-Content $args[0] -enc utf8$sb = New-Object System.Text.StringBuilder
$cont | % { [void]$sb.Append($_ + "`n") }
$src = $sb.ToString()Set-Variable err # エラー出力 / 使わないけど宣言してないと怒られるので
$parse = [System.Management.Automation.PsParser]::Tokenize($src, [ref]$err)$html = New-Object System.Text.StringBuilder
[void]$html.Append('<html><head><link rel="stylesheet" type="text/css" href="ps.css"><title>out</title></head><body>')
[void]$html.Append("<pre style='font-family: monospace; padding: 3px;'>`n")function TokenToHtml($t){
if($t.Type -eq "NewLine"){ [void]$html.Append("`n"); return }$w = (Get-Src ($t.StartLine - 1) ($t.StartColumn - 1) ($t.EndLine- 1) ($t.EndColumn - 1) )
# Tokenのタイプ別に何か処理変えるなら
switch($t.Type) {
default { [void]$html.Append('<span class="Ps' + $t.Type + '">' + $w + '</span>') }
}
}# 変換元ソースの該当箇所を取得 / 0スタートなので、Tokenの返す値から-1する
function Get-Src($s_line, $s_col, $e_line, $e_col){
for($line = $s_line; $line -le $e_line; $line++){
if($line -eq $s_line) { $s = $s_col }
else { $s = 0 }
if($line -eq $e_line) { $e = $e_col }
else { $e = $cont[$line].Length }
$ret += $cont[$line].Substring($s, $e - $s)
}
return $ret.Replace('&', '&').Replace('<', '<').Replace('>', '>')
}$pre = $null
$parse | % {
if($pre -ne $null -and ($pre.EndLine -ne $_.StartLine -or $pre.EndColumn -ne $_.StartColumn)){
$w = (Get-Src ($pre.EndLine - 1) ($pre.EndColumn - 1) ($_.StartLine - 1) ($_.StartColumn - 1) )
[void]$html.Append($w)
}TokenToHtml $_
$pre = $_
}[void]$html.Append("</pre></body></html>`n")
$html.ToString()