打造一个好看又实用的Windows终端

10,470 阅读3分钟

曾经非常羡慕Mac平台上的iTerm2+oh-my-zsh组合,可以实现一个非常好看又实用的终端,十分希望Windows平台上也有类似的东西,然而在很长时间里都没有出现,以前最好的方案还是cmder,直到微软发布了Windows Terminal。

Windows Terminal

Windows Terminal正式版已经发布了,可以直接通过Windows商店安装,现在已经支持可视化的设置界面了,大多数的美化教程可能都会介绍Windows Terminal结合WSL使用,但我个人使用下来发现几个问题:一个是WSL启动较慢,二是开启WSL后vmmem会占用大量内存,第三是通过vscode访问WSL有时会出现断开连接,所以我放弃了WSL这个方案。

WindowsTerminal.png

oh-my-posh

oh-my-posh是PowerShell的一套主题,听名字就知道和oh-my-zsh是类似的,最新版本是 Oh My Posh 3

开始安装

oh-my-posh的安装还是比较简单的

  • 通过管理员权限打开PowerShell

  • 绕过PowerShell执行策略,使其可以执行脚本文件

Set-ExecutionPolicy Bypass
  • 安装oh-my-posh主题
Install-Module oh-my-posh -Scope CurrentUser
  • 安装posh-git将git信息添加到提示中
Install-Module posh-git -Scope CurrentUser

注意:如果中途有询问,直接Y或A就好了

  • 通过这个 地址 下载安装字体,推荐安装DejaVuSansMono Nerd Font(其他的我也没试过)

修改配置

安装完成之后,修改PowerShell的配置文件

  • 启动编辑PowerShell配置文件的引擎
if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force }
  • 使用vscode打开配置文件(也可以用其他方式打开),配置文件地址一般是:C:\Users${username}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
code $PROFILE
  • 添加以下配置内容
Import-Module posh-git # 导入posh-git
Import-Module oh-my-posh # 导入oh-my-posh
Set-PoshPrompt -Theme M365Princess # 设置主题为M365Princess
  • 最终效果如图,也可以通过Get-PoshThemes查看全部可用主题

Oh-My-Posh.png

自定义别名

本来美化教程到这儿就差不多结束了,但是有一说一,这个东西网上的教程其实已经有很多了,在这儿发一个类似的东西属实没啥必要,所以下面要整点不一样的东西。

通过上面那个配置文件,可以自定义一些命令行的别名,类似于一些简单的跳转:

function Go-Up {
    # 跳转上级
    cd ../
}

function Go-Home {
    # 跳转根目录
    cd ~
}

Set-Alias '..' Go-up
Set-Alias '~' Go-Home

在使用PowerShell的过程中,一直有个不太喜欢的点,就是PowerShell查看当前目录下的文件可以使用 lsdirGet-ChildItem,这几个效果都是一样的,如下:

Get-ChildItem.png

而我想要实现类似于bash的文件名称横向排布,并且不同的文件类型显示不同的颜色的输出,类似于下图:

Get-List.png

PowerShell没有提供类似的方法,但我们可以自定义实现,代码如下:

# >>> 移除默认别名 >>>
Remove-Item alias:\ls

# >>> 自定义函数 >>>
function Color-List($str) {
    $regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase-bor [System.Text.RegularExpressions.RegexOptions]::Compiled)
    $fore = $Host.UI.RawUI.ForegroundColor
    $compressed = New-Object System.Text.RegularExpressions.Regex('\.(zip|tar|gz|rar|jar|war|7z)$', $regex_opts)
    $executable = New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|py|ps1|psm1|vbs|rb|reg|sh|zsh)$', $regex_opts)
    $code_files = New-Object System.Text.RegularExpressions.Regex('\.(ini|csv|log|xml|yml|json|java|c|cpp|css|sass|js|ts|jsx|tsx|vue)$', $regex_opts)

    $itemList = @()
    Invoke-Expression ("Get-ChildItem" + " " + $str) | ForEach-Object {
        $item = New-Object object
        if ($_.GetType().Name -eq 'DirectoryInfo') 
        {
            $item | Add-Member NoteProperty name ("`e[34m" + $_.name) # 目录名称蓝色
        }
        elseif ($compressed.IsMatch($_.Name)) 
        {
            $item | Add-Member NoteProperty name ("`e[31m" + $_.name) # 压缩文件红色
        }
        elseif ($executable.IsMatch($_.Name))
        {
            $item | Add-Member NoteProperty name ("`e[36m" + $_.name) # 可执行文件青色
        }
        elseif ($code_files.IsMatch($_.Name))
        {
            $item | Add-Member NoteProperty name ("`e[33m" + $_.name) # 代码文件黄色
        }
        else
        {
            $item | Add-Member NoteProperty name ("`e[37m" + $_.name) # 其他文件默认白色
        } 
        $itemList += $item
    }
    echo $itemList | Format-Wide -AutoSize # 格式化输出
}

function Get-List {
    Color-List "-Exclude .*"
}

function Get-All-List {
    Color-List "$args"
}

# >>> 重新定义别名 >>>
Set-Alias ls Get-List
Set-Alias la Get-All-List

最终效果如下:

Get-Color-List.png