はじめまして、嗣永モモコーラと申します。
編集方法がよくわからず、何回も失敗して変なエントリをあげてしまいました。すいません……。
PowerShellは、2.0 CTPのみだったと思うのですが、パーサが利用できます。これを使って、PowerShellのスクリプトファイルをHTMLへ変換するスクリプトを作成しました。以下は、そのスクリプトを自分自身でHTMLへ変換したものです。
前にも一度作った事があったので、今回は余分な機能として、Alias(コマンドの別名)が設定されている場合に、元の名前に戻した上でHTMLを出力するようにしてみました。たとえば、"gc"はデフォルトで用意されたGet-ContentコマンドレットのAliasなので、スクリプト中に gc "hogehoge.txt" という部分があった場合、Get-Content "hogehoge.txt"に変換して出力します。
Aliasは普段利用しない人にとっては可読性が落ちるかもしれないのと、profile.ps1などで独自に設定したAliasがスクリプトに残っていると、他の環境では動かなかったりしてつらい思いをすることがあるからです。
利用する際は以下のスクリプトをファイルに保存し、第一引数に変換したいスクリプトファイル名を渡してください。変換後のHTMLはそのまま戻り値になるので、リダイレクトしてファイルに保存するなどしてください。
スクリプトファイルの文字コードがutf-8決め打ち、CSSファイルを編集できない環境を想定してスタイル埋め込みになっている、色が好みでない、などの点は適宜改造していただけるとありがたいです。ではでは。
追記:ここ(PowerShell from Japan!!)が空行や空スペースに手を入れる?仕組みのようなので、改行やスペースを全て実体参照に変更しました
追々記:<br /><br />も変換されてしまうようなので、<br /> <br />に変換してます。
# Token単位でHTMLへ変換
function TokenToHtml($t){
# NewLineは単に改行
if($t.Type -eq "NewLine"){ return "<br />" }
# 該当部分のソースを取得
$w = (Get-Src $t.StartLine $t.StartColumn $t.EndLine $t.EndColumn)
# Tokenのタイプ別にhtmlへ
switch($t.Type) {
"Comment" { return '<span style="color: rgb(0, 255, 0);">' + $w + '</span>' }
"Keyword" { return '<span style="color: rgb(160, 160, 255);">' + $w + '</span>' }
"Operator" { return '<span style="color: rgb(255, 165, 0);">' + $w + '</span>' }
"String" { return '<span style="font-weight: bold;">' + $w + '</span>' }
"Type" { return '<span style="font-weight: bold; color: rgb(46, 139, 87);">' + $w + '</span>' }
"Command" { return '<span style="color:rgb(160, 160, 255); ">' + (ToDefinition $w) + '</span>' }
default { return $w }
}
}
# エイリアスだったら元の名前を返す。なければそのまま
function ToDefinition($name){
$def = (Get-Alias -Name $name -ErrorAction SilentlyContinue)
if($def -ne $null){
return $def.Definition
}
return $name
}
# 変換元ソースの該当箇所を取得 / 0スタートなので、Tokenの返す値から-1する
function Get-Src($s_line, $s_col, $e_line, $e_col){
$s_line -= 1; $s_col -= 1; $e_line -= 1; $e_col -= 1;
# 複数行にわたる場合があるため、ループ
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 = $src[$line].Length }
$ret += $src[$line].Substring($s, $e - $s) + "`n"
}
$ret = $ret.Substring(0, $ret.Length - 1);
return $ret.Replace('&', '&').Replace('<', '<').Replace('>', '>').Replace(' ', ' ').Replace("`n", "<br />")
}
# ヘッダ
$header =
@"
<html>
<head>
<title>out</title>
</head>
<body>
<pre class="pssource" style="background-color: rgb(0, 0, 0); color: rgb(0, 255, 255); padding: 3px; font-family: consolas;">
"@
# フッタ
$footer =
@"
</pre>
</body>
</html>
"@
##############################################
# ここからMain
##############################################
# 変換するPSのソース
$src = Get-Content $args[0] -enc utf8
# parserへ渡せる形式へ変換
$sb = New-Object System.Text.StringBuilder
$src | ForEach-Object { [void]$sb.Append($_ + "`n") }
# エラー出力 / 使わないけど宣言してないと怒られるので
Set-Variable err
# パース
$token = [System.Management.Automation.PsParser]::Tokenize($sb.ToString(), [ref]$err)
# HTMLへ出力する文字列
$html = New-Object System.Text.StringBuilder
[void]$html.Append($header)
$pre = $null
# Tokenごとに出力
$token | ForEach-Object {
# Tokenに含まれないもの(空白など)を出力
if($pre -ne $null -and ($pre.EndLine -ne $_.StartLine -or $pre.EndColumn -ne $_.StartColumn)){
[void]$html.Append((Get-Src $pre.EndLine $pre.EndColumn $_.StartLine $_.StartColumn))
}
# Tokenを出力
[void]$html.Append((TokenToHtml $_))
$pre = $_
}
[void]$html.Append($footer)
$html.ToString().Replace("<br /><br />", "<br /> <br />")