[Nushell] Oh My Posh を使ってNushellコンソールをおしゃれにカスタマイズする

[Nushell] Oh My Posh を使ってNushellコンソールをおしゃれにカスタマイズする

Clock Icon2024.11.03

しばたです。

私は以前からOh My Poshを使ってPowerShellのコンソールをカスタマイズして利用しています。

https://dev.classmethod.jp/articles/customize-your-powershell-console-with-oh-my-posh3/

今年に入りNushellを常用する様になったので、NushellでOh My Poshを使う手順について本記事で共有したいと思います。

Oh My PoshのNushellサポート状況

https://ohmyposh.dev/

Oh My Poshは元々PowerShell専用のモジュールでしたが、ちょうど前の記事を書いた頃に内部実装をGo言語に置き替えたVer.3がリリースされPowerShell以外のシェルもサポートする様になりました。
Ver.3以降は頻繁にメジャーバージョンを更新する様になり、本日(2024年11月3日)時点でVer.23.20.3が最新になっています。

本日時点でサポートしているシェルは

となっており、PowerShellやNushell以外にも多様なシェルで利用可能です。

Nushellは Ver.0.93.0 以降である必要があります。

設定方法

次にインストールと初期設定までの手順を解説します。

0. 検証環境

今回は私の開発PCを検証環境とします。

  • Windows 11 Pro (23H2) + WSL2上のUbuntu 22.04
  • Nushell 0.99.1

Nushellのインストール方法は割愛します。

1. Oh My Poshのインストール

Oh My Poshのインストールは各種パッケージマネージャから可能なっています。

Windows環境であればWinGet、Scoop、Chocolateyからインストールできます。
Windows 11であればWinGetを使うのが一番手っ取り早いでしょう。

Nushell on Windows
# WinGetから OhMyPosh をインストール
winget install JanDeDobbeleer.OhMyPosh -s winget

Linux環境の場合はHomebrew on Linuxが使えますが、初期状態でHomebrewがインストール済みの環境はそこまで多くないでしょうし、手動でインストールスクリプトを実行するのが手っ取り早いと思います。

Nushell on Linux
# インストールスクリプトを実行してインストール
curl -s https://ohmyposh.dev/install.sh | bash -s

この場合$HOME/bin$HOME/.local/binの優先度で実行バイナリがダウンロードされます。
ちなみにインストール先にPATHが通って無くても問題ありません。[1]

また、今回は試しませんが、macOSの場合はHomeBrewかMacPortsからインストール可能です。

Nushell on macOS
# HomeBrewからインストールする場合
brew install jandedobbeleer/oh-my-posh/oh-my-posh

2. Nerd Fontのインストール

Oh My Posh等のPowerlineツールでは独自のフォント(Nerd Font)を使って特殊な表示を実現しています。

以前の記事では手動でフォントをダウンロードしましたが、現在はoh-my-posh font installコマンドからインストール可能になっています。

Nushell
# 対話的にNerd Fontをインストール
oh-my-posh font install

customize-your-nushell-console-with-oh-my-posh-01

インストールしたいフォントを選び、エラー無く完了すればOKです。

customize-your-nushell-console-with-oh-my-posh-02

あとは各種ターミナルの設定で利用フォントを切り替えれば完了です。
Windows Terminalの場合であれば「設定」→「既定値」→「外観」→「フォントフェイス」から設定します。

customize-your-nushell-console-with-oh-my-posh-03

3. プロンプト初期設定

続けてプロンプト表示を切り替えるための初期設定を行います。

Nushellの場合、oh-my-posh init nuコマンドを実行するとホームディレクトに.oh-my-posh.nuファイルを生成します。

Nushell
# 初期設定用ファイルを生成 : デフォルト ~/.oh-my-posh.nu
oh-my-posh init nu

customize-your-nushell-console-with-oh-my-posh-04

生成された内容は以下の内容であり、プロンプト表示変更用のカスタムコマンド等が定義されています。

.oh-my-posh.nu
# make sure we have the right prompt render correctly
if ($env.config? | is-not-empty) {
    $env.config = ($env.config | upsert render_right_prompt_on_last_line true)
}

$env.POWERLINE_COMMAND = 'oh-my-posh'
$env.POSH_THEME = (echo '')
$env.PROMPT_INDICATOR = ""
$env.POSH_SESSION_ID = (echo "4a1012a0-7ecb-4a5e-98e7-b77ecf680210")
$env.POSH_SHELL_VERSION = (version | get version)

let _omp_executable: string = (echo "C:/Users/your-name/AppData/Local/Programs/oh-my-posh/bin/oh-my-posh.exe")

# PROMPTS

def --wrapped _omp_get_prompt [
    type: string,
    ...args: string
] {
    mut execution_time = -1
    mut no_status = true
    # We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`, which is an official setting.
    # See https://github.com/nushell/nushell/discussions/6402#discussioncomment-3466687.
    if $env.CMD_DURATION_MS != '0823' {
        $execution_time = $env.CMD_DURATION_MS
        $no_status = false
    }

    (
        ^$_omp_executable print $type
            --save-cache
            --shell=nu
            $"--shell-version=($env.POSH_SHELL_VERSION)"
            $"--status=($env.LAST_EXIT_CODE)"
            $"--no-status=($no_status)"
            $"--execution-time=($execution_time)"
            $"--terminal-width=((term size).columns)"
            ...$args
    )
}

$env.PROMPT_MULTILINE_INDICATOR = (
    ^$_omp_executable print secondary
        --shell=nu
        $"--shell-version=($env.POSH_SHELL_VERSION)"
)

$env.PROMPT_COMMAND = {||
    # hack to set the cursor line to 1 when the user clears the screen
    # this obviously isn't bulletproof, but it's a start
    mut clear = false
    if $nu.history-enabled {
        $clear = (history | is-empty) or ((history | last 1 | get 0.command) == "clear")
    }

    if ($env.SET_POSHCONTEXT? | is-not-empty) {
        do --env $env.SET_POSHCONTEXT
    }

    _omp_get_prompt primary $"--cleared=($clear)"
}

$env.PROMPT_COMMAND_RIGHT = {|| _omp_get_prompt right }

$env.TRANSIENT_PROMPT_COMMAND = {|| _omp_get_prompt transient }
^$_omp_executable notice

ここにある$env.POSH_THEMEに設定のファイルパスを設定すると独自のテーマを適用できます。

.oh-my-posh.nu
# ここにテーマ用設定ファイルのパスを記載
$env.POSH_THEME = (echo '~/your-custom-theme.json')

最後にNushellの設定ファイルconfig.nuに追記してやれば完了です。
(設定ファイルの場所は$nu.default-config-dirから確認できます)

nu.config
# ~/.oh-my-posh.nu の呼び出しを追記
source ~/.oh-my-posh.nu

これでNushellを起動し直すと下図の様な感じでおしゃれ[2]なコンソール表示になります。

customize-your-nushell-console-with-oh-my-posh-05

ちなみに上図はテーマ指定しなかった場合のデフォルト表示です。

補足 : テーマ設定

本記事では詳細に触れませんが、テーマ設定については以下のドキュメントをご覧ください。

昔はJSONしか使えませんでしたが、今はJSON、YAML、TOMLで設定を記述できます。

設定例

私は元々PowerShellでOh My Poshを利用し、今はNushellでも使っています。
利用環境はWinodwsクライアントとWSL上のUbuntuになります。

複数シェル・複数環境を一つのテーマで共用しているのですが、そのためのポイントを私の実例から説明したいと思います。

設定ファイル

こちらが私が実際に使用している設定ファイル(の一部)となります。

下記設定の他にAWS Tools for PowerShell向けの独自セグメントを作ってもいるですが、設定ファイル単品だと意味不明になってしまうので本記事では除外しています。
また、フォントはCaskaydiaCove Nerd Font前提となっています。

クリックして展開
テーマ設定.json (2024年11月現在)
{
  "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
  "blocks": [
    {
      "alignment": "left",
      "segments": [
        {
          "background": "#FF9900",
          "foreground": "#100e23",
          "powerline_symbol": "\ue0b0",
          "style": "powerline",
          "template": " \udb83\ude0f {{.Profile}}{{if .Region}} @ {{.Region}}{{end}} ",
          "type": "aws"
        },
        {
          "background": "#6e6ed0",
          "foreground": "#100e23",
          "powerline_symbol": "\ue0b0",
          "style": "powerline",
          "template": "{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }} \ue73c venv ({{ .Major }}.{{ .Minor }}) {{ end }}{{ end }}",
          "type": "python"
        },
        {
          "background": "#8ae099",
          "foreground": "#100e23",
          "powerline_symbol": "\ue0b0",
          "style": "powerline",
          "template": " \ued0d v{{ .Major }}.{{ .Minor }} ",
          "properties": {
            "fetch_package_manager": false
          },
          "type": "node"
        },
        {
          "background": "#ffffff",
          "foreground": "#100e23",
          "powerline_symbol": "\ue0b0",
          "properties": {
            "display_host": true
          },
          "style": "powerline",
          "template": " {{ if .SSHSession }}\uf817 {{ .UserName }}@{{ .HostName }}{{ else }}{{ .HostName }}{{ end }} ",
          "type": "session"
        },
        {
          "background": "#91ddff",
          "foreground": "#100e23",
          "powerline_symbol": "\ue0b0",
          "properties": {
            "folder_icon": "\uf115",
            "folder_separator_icon": " \ue0b1 ",
            "home_icon": "\uf7db",
            "style": "agnoster"
          },
          "style": "powerline",
          "template": " {{ .Path }} ",
          "type": "path"
        },
        {
          "background": "#95ffa4",
          "foreground": "#193549",
          "powerline_symbol": "\ue0b0",
          "style": "powerline",
          "background_templates": [
            "{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}",
            "{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}",
            "{{ if gt .Ahead 0 }}#B388FF{{ end }}",
            "{{ if gt .Behind 0 }}#B388FB{{ end }}"
          ],
          "template": "{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \uf0c7 {{ .StashCount }}{{ end }}",
          "properties": {
            "fetch_status": true,
            "fetch_upstream_icon": true,
            "source": "cli",
            "mapped_branches": {
              "feat/*": "🚀 ",
              "bug/*": "🐛 "
            }
          },
          "type": "git"
        }
      ],
      "type": "prompt"
    },
    {
      "alignment": "right",
      "segments": [
        {
          "foreground": "#007ACC",
          "properties": {
            "windows": "\ue70f"
          },
          "style": "plain",
          "template": " {{ if .WSL }}WSL at {{ end }}{{.Icon}} ",
          "type": "os"
        },
        {
          "foreground": "#007ACC",
          "properties": {
            "time_format": "15:04:05"
          },
          "style": "plain",
          "template": "[{{ .CurrentDate | date .Format }}]",
          "type": "time"
        }
      ],
      "type": "prompt"
    },
    {
      "alignment": "left",
      "segments": [
        {
          "foreground": "#ffff66",
          "powerline_symbol": "\ue0b0",
          "properties": {
            "root_icon": "\uf071 (root)"
          },
          "style": "plain",
          "template": " \uf0e7 ",
          "type": "root"
        },
        {
          "type": "shell",
          "style": "powerline",
          "foreground": "#CCCCCC",
          "properties": {
            "mapped_shell_names": {
              "pwsh": " PS",
              "nu": " nu"
            }
          }
        },
        {
          "foreground": "#CCCCCC",
          "style": "plain",
          "template": "❯ ",
          "type": "text"
        }
      ],
      "type": "prompt"
    }
  ],
  "version": 2
}

スクリーンショット

このテーマを適用した結果が次の通りになります。

Nushell on Windows

基本的に2行のプロンプトで、左上はホスト名やパスに加え個別の機能を表示する様にしており、下図の例ではAWSプロファイルの設定状態を表示させています。
右上に利用プラットフォームと現在時刻を表示させています。
2行目が入力用で、ここでシェルの種別が分かる様にしています。(Nushell → nu, PowerShell → PS)

customize-your-nushell-console-with-oh-my-posh-06

入力しているコマンドはNushellのバージョンと利用プラットフォームが分かる様にしています。

あと適当にNushellっぽいコマンドを足しています。
仕事柄AWS CLIをよく使うのでその利用イメージを例にしてみました。
現在設定しているプロファイルとデフォルトリージョンが表示され、適用環境を誤認する可能性を激減できるので非常に役立っています。

Nushell on Ubuntu

Ubuntu環境も概ね同じ表示になっていますが、右上のプラットフォームの表記が異なっており識別可能となっています。
(WSL環境では「WSL at」の表示に)

customize-your-nushell-console-with-oh-my-posh-07

入力コマンドの内容は以前書いた記事の結果をふまえてNode.jsのバージョンを表示してみました。

https://dev.classmethod.jp/articles/how-to-use-fnm-on-nushell-202409/

PowerShell on Windows

PowerShell環境では2行目のプロンプトが「 PS ❯」になっており識別可能です。
また、Windows Terminalのアイコンでも利用環境別にアイコンが分かれているので、これだけで十分実用可能となっています。

customize-your-nushell-console-with-oh-my-posh-08

こちらも入力コマンドの内容は以前書いた記事の結果をふまえてPythonの仮想環境を表示してみました。

https://dev.classmethod.jp/articles/how-to-use-uv-on-nushell-202410/

共用ポイント

Oh My Poshの大抵の設定(セグメント)はプラットフォーム共通です。
このため環境ごとの使い分けは少なく、各環境の情報をどの様に記載し区別可能にするかがポイントとなります。

1. OSセグメント

OSセグメントで現在利用中のOS情報を表示できます。

私の設定はほぼ公式のサンプル通りです。

{
    "foreground": "#007ACC",
    "properties": {
        "windows": "\ue70f"
    },
    "style": "plain",
    "template": " {{ if .WSL }}WSL at {{ end }}{{.Icon}} ",
    "type": "os"
},

2. Shellセグメント

Shellセグメントで現在実行中のシェルを取得できます。

私の場合、Nushellでは「nu」、PowerShellでは「PS」を表示して区別できる様にしました。

{
    "type": "shell",
    "style": "powerline",
    "foreground": "#CCCCCC",
    "properties": {
        "mapped_shell_names": {
            "pwsh": " PS",
            "nu": " nu"
        }
    }
},

3. .oh-my-posh.nu ファイル

最後に.oh-my-posh.nuファイルのカスタマイズについて触れておきます。

oh-my-posh init nuコマンドで自動生成されたファイルではOh My Poshのバイナリファイル指定が環境別にフルパスで記載されます。
このため複数環境で同じファイルを共用するにはこの指定も共用可能にしておく必要があります。

ファイル中の_omp_executable変数の定義を以下の様に変えてやり、どのOS環境でも適切になる様にします。

.oh-my-posh.nu
# Oh My Poshのバイナリ指定をクロスプラットフォーム対応させる
let _omp_executable = match $nu.os-info.name {
    "windows" => $"($nu.home-path)/AppData/Local/Programs/oh-my-posh/bin/oh-my-posh.exe",
    _ => $"($nu.home-path)/.local/bin/oh-my-posh",
}

また、テーマ指定も

.oh-my-posh.nu
# テーマ指定もクロスプラットフォーム対応に
$env.POSH_THEME = $"($nu.home-path)/your-custom-theme.json"

という感じでプラットフォームに依存しない形にしてやります。

最後に

以上となります。

常用するシェルをNushellに切り替えてしばらく経ち、コンソールのカスタマイズもひと段落したので記事にしてみました。
Nushellの利用者だとRust製のStarshipを使う方が多いと思いますが、Oh My Poshもいい感じに使えるので興味があればぜひ試してみてください。

脚注
  1. PATHを通してない場合はフルパス指定でoh-my-poshコマンドを実行してください ↩︎

  2. 「おしゃれ」の定義は様々かと思いますが、ここではデフォルト表示よりはきれいで洒落ているという意味で使っています ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.