Windows PowerShell ISE の色とフォントの設定をCSSとして出力する

以下の画像のような、Windows PowerShell ISEのオプションの「スクリプト ウィンドウ トークン」と「フォント ファミリ」などの情報をPowerShellでCSS化してみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142842/976ff8b7-0caf-cd75-cf22-5934093e58d9.png)

# 基本

Windows PowerShell ISEの各種設定は、ISEをホストとしたときに使用できる自動変数`$psISE`の`Options`から参照できます。

PowerShell v2.0では上記の画像のようなダイアログはありませんが、`$psISE.Options`を直接編集することで設定の変更などが行えます。

# CSS化

## フォント

フォント関連の情報は、`$psISE.Options.FontSize`及び`$psISE.Options.FontName`から取得できます。

```powershell
$psISE.Options.FontSize
$psISE.Options.FontName
```

これを適当に文字列に埋め込んでしまいます。

```powershell
[string]$prefix = 'ps-'

@"
.${prefix}font {font-size: $($psISE.Options.FontSize)px; font-family: "$($psISE.Options.FontName)",monospace;}
"@
```

```css
.ps-font {font-size: 12px; font-family: "Consolas",monospace;}
```

## トークン

トークン毎の色の情報は`$psISE.Options.TokenColors`に辞書として格納されています。

各トークンの種類をCSSのクラス名として生成する場合は以下のような感じになります。

`$_.Value`（[Color Struct(System.Windows.Media)](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.color?view=netframework-4.7.2 "Color Struct (System.Windows.Media) | Microsoft Docs")）をCSSの色表現にする方法がちょっと微妙な感じがしますが……

```powershell
[string]$prefix = 'ps-'

$psISE.Options.TokenColors.GetEnumerator() |
    ForEach-Object -Process {
        # $_.Key -is System.Management.Automation.PSTokenType
        [string]$class = ".${prefix}{0}" -f $_.Key.ToString().ToLower()
        # $_.Value -is System.Windows.Media.Color
        [string]$color = $_.Value.ToString().SubString(3) # `#AARRGGBB`->`RRGGBB`
            
        Write-Output -InputObject "$class {color: #$color;}"
    }
```

```css
.ps-attribute {color: #00BFFF;}
.ps-command {color: #0000FF;}
.ps-commandargument {color: #8A2BE2;}
.ps-commandparameter {color: #000080;}
.ps-comment {color: #006400;}
.ps-groupend {color: #000000;}
.ps-groupstart {color: #000000;}
.ps-keyword {color: #00008B;}
.ps-linecontinuation {color: #000000;}
.ps-looplabel {color: #00008B;}
.ps-member {color: #000000;}
.ps-newline {color: #000000;}
.ps-number {color: #800080;}
.ps-operator {color: #A9A9A9;}
.ps-position {color: #000000;}
.ps-statementseparator {color: #000000;}
.ps-string {color: #8B0000;}
.ps-type {color: #008080;}
.ps-unknown {color: #000000;}
.ps-variable {color: #FF4500;}
```

## 書き出し

必要に応じてこれらを書き出します。

```powershell
[string]$prefix = 'ps-'

[string]$fontCss = @"
.${prefix}font {font-size: $($psISE.Options.FontSize)px; font-family: "$($psISE.Options.FontName)",monospace;}
"@

[string[]]$css = 
    $psISE.Options.TokenColors.GetEnumerator() |
        # Beginに$fontCssを渡すことで全体で一つの配列とする
        ForEach-Object -Begin {$fontCss} -Process {
            # $_.Key -is System.Management.Automation.PSTokenType
            [string]$class = ".${prefix}{0}" -f $_.Key.ToString().ToLower()
            # $_.Value -is System.Windows.Media.Color
            [string]$color = $_.Value.ToString().SubString(3) # `#AARRGGBB`->`RRGGBB`
            
            Write-Output -InputObject "$class {color: #$color;}"
        }

# カレントディレクトリにBOMなしUTF8で書き出し
[IO.File]::WriteAllText( #
    [IO.Path]::Combine($PWD, 'psISE_Fomat.css'),
    $css -join "`r`n",
    [Text.UTF8Encoding]$false
)
```

```css:psISE_Fomat.css
.ps-font {font-size: 12px; font-family: "Consolas",monospace;}
.ps-attribute {color: #00BFFF;}
.ps-command {color: #0000FF;}
.ps-commandargument {color: #8A2BE2;}
.ps-commandparameter {color: #000080;}
.ps-comment {color: #006400;}
.ps-groupend {color: #000000;}
.ps-groupstart {color: #000000;}
.ps-keyword {color: #00008B;}
.ps-linecontinuation {color: #000000;}
.ps-looplabel {color: #00008B;}
.ps-member {color: #000000;}
.ps-newline {color: #000000;}
.ps-number {color: #800080;}
.ps-operator {color: #A9A9A9;}
.ps-position {color: #000000;}
.ps-statementseparator {color: #000000;}
.ps-string {color: #8B0000;}
.ps-type {color: #008080;}
.ps-unknown {color: #000000;}
.ps-variable {color: #FF4500;}
```