├── img ├── posh.png ├── wt_0.png ├── wt_1.png ├── wt_2.png ├── wt_3.png └── wt_4.png ├── themes ├── foxkid.json └── foxkid-customized-ohmyposh.json ├── README.md └── profile_and_settings ├── settings.json └── $profile.ps1 /img/posh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/posh.png -------------------------------------------------------------------------------- /img/wt_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/wt_0.png -------------------------------------------------------------------------------- /img/wt_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/wt_1.png -------------------------------------------------------------------------------- /img/wt_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/wt_2.png -------------------------------------------------------------------------------- /img/wt_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/wt_3.png -------------------------------------------------------------------------------- /img/wt_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshFahim/powershell-customization-ohmyposh-themes/HEAD/img/wt_4.png -------------------------------------------------------------------------------- /themes/foxkid.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", 3 | "blocks": [ 4 | { 5 | "alignment": "left", 6 | "segments": [ 7 | { 8 | "background": "#ffa510", 9 | "foreground": "#ffffff", 10 | "leading_diamond": "\ue0b6", 11 | "powerline_symbol": "\ue0b0", 12 | "properties": { 13 | "style": "folder", 14 | "template": " \ue5ff {{ .Path }} " 15 | }, 16 | "style": "diamond", 17 | "trailing_diamond": "\ue0b0", 18 | "type": "path" 19 | }, 20 | { 21 | "background": "#fffb38", 22 | "foreground": "#193549", 23 | "powerline_symbol": "\ue0b0", 24 | "properties": { 25 | "fetch_stash_count": true, 26 | "fetch_status": true, 27 | "fetch_upstream_icon": true, 28 | "template": " {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}} \uf692 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} " 29 | }, 30 | "style": "powerline", 31 | "type": "git" 32 | }, 33 | { 34 | "background": "#6CA35E", 35 | "foreground": "#ffffff", 36 | "powerline_symbol": "\ue0b0", 37 | "properties": { 38 | "fetch_version": true, 39 | "template": " \ue70c {{ if .Unsupported }}\uf071{{ else }}{{ .Full }}{{ end }} " 40 | }, 41 | "style": "powerline", 42 | "type": "dotnet" 43 | }, 44 | { 45 | "background": "#516BEB", 46 | "foreground": "#193549", 47 | "powerline_symbol": "\ue0b0", 48 | "properties": { 49 | "template": " \uf85a MEM:{{ round .PhysicalPercentUsed .Precision }}%|" 50 | }, 51 | "style": "diamond", 52 | "trailing_diamond": "\ue0b0", 53 | "type": "sysinfo" 54 | }, 55 | { 56 | "background": "#2e9599", 57 | "background_templates": ["{{ if gt .Code 0 }}#f1184c{{ end }}"], 58 | "foreground": "#ffffff", 59 | "powerline_symbol": "\ue0b0", 60 | "properties": { 61 | "always_enabled": true, 62 | "template": " {{ if gt .Code 0 }}\uf421 \uf119 {{ else }}\uf469 \u2665{{ end }} " 63 | }, 64 | "style": "powerline", 65 | "trailing_diamond": "\ue0b4", 66 | "type": "exit" 67 | } 68 | ], 69 | "type": "prompt" 70 | } 71 | ], 72 | "console_title": true, 73 | "console_title_style": "folder", 74 | "final_space": true, 75 | "version": 1 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hi! 2 | 3 | A lot of people asked me about my Windows terminal (Powershell) looks and theme and how to customize it. Here I will try to give you a detailed description of how you can customize your **PowerShell** but you can also use similar methods to your **Zshell** or any **Linux shell**. So let's get started. 4 | ![Screenshot of customized PowerShell in terminal windows11 with transparency on.](/img/posh.png) 5 |

Example of end results

6 |
7 |
8 | 9 | ## 1. Install Windows Terminal 10 | First of all you need to install **Windows Terminal**. You can download it from [here](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab) or search it in **Microsoft Store**. It's built-in in Windows 11. After you install it you can open it and you will see something like this: 11 | ![Screenshot of Windows Terminal](/img/wt_0.png) 12 |

Windows Terminal

13 |
14 | 15 | ## 2. Get PowerShell 16 | Now you need to get **PowerShell**. You can download it from [here](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) or search it in **Microsoft Store**. Now you will be able yo select it in **Windows Terminal**. You can do it by clicking on the down arrow in the top bar and selecting PowerShell**. If you don't see it in the menu, just restart it. Now you will see something like this: 17 | ![Screenshot of Windows Terminal with PowerShell](/img/wt_1.png) 18 |

Windows Terminal dropdown menu with PowerShell

19 |
20 | 21 | Now go to your terminal settings and set **PowerShell** as your default shell. Also set **Windows Terminal** as your default terminal. You can do it by clicking on the down arrow in the top bar and select **Settings**. Now you will see something like this: 22 | ![Screenshot of Windows Terminal settings](/img/wt_2.png) 23 | 24 | 25 | 26 |
27 | 28 | ## 3. Font 29 | Now you need to install a font that will support all the icons and characters that we will use. I use **Cascadia Cove Nerd Font Complete**. You can download it from [here](https://www.nerdfonts.com/). 30 | Download it and install it. After installing restart your Terminal app and select **CascadiaCove NF** as your default font. You can do it by clicking on the down arrow in the top bar and select **Settings**. Now you will see something like this: 31 | 32 | ![Screenshot of Windows Terminal settings](/img/wt_3.png) 33 |
34 | 35 | ## 4. Install Oh My Posh 36 | Now you need to install **Oh My Posh**. You can do it by running this command in your terminal: 37 | ```powershell 38 | winget install JanDeDobbeleer.OhMyPosh 39 | ``` 40 | Read the Oh My Posh documentation [here](https://ohmyposh.dev/docs/). 41 |
42 | 43 | After this restart the Terminal app and edit $profile file. You can open $profile by running this command in your terminal: 44 | ```powershell 45 | notepad $PROFILE 46 | ``` 47 | if you want to edit in VS Code run this command: 48 | ```powershell 49 | code $PROFILE 50 | ``` 51 | Edit the $profile file and add this line: 52 | ``` 53 | oh-my-posh --init --shell pwsh --config ~/jandedobbeleer.omp.json | Invoke-Expression 54 | ``` 55 | If you want you can use my profile file and just replace it with yours. You can download it from this repo. Your $profile file will be different. change the path and adjust your settings. You can find more information about $profile file [here](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.1). After changing $profile file restart your Terminal app. Now you will see something like this: 56 | 57 |
58 | 59 | ## 5. Install Oh My Posh Themes 60 | Now you need to install **Oh My Posh Themes**. You can do it from [here](https://ohmyposh.dev/docs/themes). I added the theme I use in this repo and you can download it from here. You can also create your own theme. You can find more information about themes [here](https://ohmyposh.dev/docs/themes). After you download the theme you want you need to import it. 61 | 62 | ## 6. Terminal Icons 63 | Now you need to install **Terminal Icons**. You can do it by running this command in your terminal: 64 | ```powershell 65 | Install-Module -Name Terminal-Icons -Repository PSGallery 66 | ``` 67 | Read the Terminal Icons documentation [here]() 68 | Add this line in your $profile file: 69 | ```powershell 70 | Import-Module -Name Terminal-Icons 71 | ``` 72 | After this restart the Terminal app. Now you will see something like this (your theme will look different): 73 | ![Screenshot of Windows Terminal with PowerShell](/img/wt_4.png) 74 | 75 |
76 | 77 | ## 7. Install PsReadLine 78 | **PsReadLine** is my favourite. It will suggest your commands and autocomplete them depending on your previous commands. You can do it by running this command in your terminal: 79 | ```powershell 80 | Install-Module -Name PSReadLine -Repository PSGallery -Force 81 | ``` 82 | Read the PsReadLine documentation [here](https://docs.microsoft.com/en-us/powershell/module/psreadline/?view=powershell-7.1). 83 | Add this line in your $profile file: 84 | ```powershell 85 | Import-Module -Name PSReadLine 86 | ``` 87 | I will suggest you to go and read a blog by Scott Hanselman about [PsReadLine](https://www.hanselman.com/blog/how-to-make-a-pretty-prompt-in-windows-terminal-with-powerline-nerd-fonts-cascadia-code-wsl-and-ohmyposh). He is one of my favorite internet people. He is a great developer and you can learn a lot from his videos. You can find his videos on [YouTube](https://www.youtube.com/c/shanselman/videos). 88 | 89 | ## 8. Terminal Customization 90 | Windows Terminal is very customizable. You can change the background, the font, the opacity, the color scheme, and a lot more. You can find more information about Windows Terminal customization [here](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-appearance). You can also find a lot of themes [here](https://windowsterminalthemes.dev/). You can also create your own theme. You can find more information about themes [here](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/color-schemes). I included my settings.json file in this repo. You can check it for reference. 91 |
92 |
93 | This doc is still in progress. Everything till now covers the basics of Windows terminal customization. I will soon add more details... 94 | -------------------------------------------------------------------------------- /themes/foxkid-customized-ohmyposh.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", 3 | "blocks": [ 4 | { 5 | "alignment": "left", 6 | "segments": [ 7 | { 8 | "background": "#FF9B9B", 9 | "foreground": "#ffffff", 10 | "leading_diamond": "\u256d\u2500\ue0b6", 11 | "style": "diamond", 12 | "template": "\uf120 {{ .Name }} ", 13 | "type": "shell" 14 | }, 15 | { 16 | "background": "#ef5350", 17 | "foreground": "#FFFB38", 18 | "style": "diamond", 19 | "template": "\ue0b0 \uf292 ", 20 | "type": "root" 21 | }, 22 | { 23 | "background": "#FFD6A5", 24 | "foreground": "#2d3436", 25 | "powerline_symbol": "\ue0b0", 26 | "properties": { 27 | "folder_icon": " \uf07b ", 28 | "home_icon": "\uf7dd", 29 | "style": "folder" 30 | }, 31 | "style": "powerline", 32 | "template": " \uf07b\uf553{{ .Path }} ", 33 | "type": "path" 34 | }, 35 | { 36 | "background": "#CBFFA9", 37 | "background_templates": [ 38 | "{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb95{{ end }}", 39 | "{{ if and (gt .Ahead 0) (gt .Behind 0) }}#c5e478{{ end }}", 40 | "{{ if gt .Ahead 0 }}#C792EA{{ end }}", 41 | "{{ if gt .Behind 0 }}#C792EA{{ end }}" 42 | ], 43 | "foreground": "#011627", 44 | "powerline_symbol": "\ue0b0", 45 | "properties": { 46 | "branch_icon": "\ue725 ", 47 | "fetch_status": true, 48 | "fetch_upstream_icon": true 49 | }, 50 | "style": "powerline", 51 | "template": " {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#ef5350> \uf046 {{ .Staging.String }}{{ end }} ", 52 | "type": "git" 53 | }, 54 | { 55 | "background": "#83769c", 56 | "foreground": "#F2D8D8", 57 | "properties": { 58 | "style": "roundrock", 59 | "threshold": 0 60 | }, 61 | "style": "diamond", 62 | "template": " \ufa1e{{ .FormattedMs }}\u2800", 63 | "trailing_diamond": "\ue0b4", 64 | "type": "executiontime" 65 | } 66 | ], 67 | "type": "prompt" 68 | }, 69 | { 70 | "alignment": "right", 71 | "segments": [ 72 | { 73 | "background": "#374259", 74 | "foreground": "#F2D8D8", 75 | "leading_diamond": "\ue0b6", 76 | "properties": { 77 | "fetch_package_manager": true, 78 | "npm_icon": " <#cc3a3a>\ue5fa ", 79 | "yarn_icon": " <#348cba>\uf61a" 80 | }, 81 | "style": "diamond", 82 | "template": "\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}", 83 | "trailing_diamond": "\ue0b4 ", 84 | "type": "node" 85 | }, 86 | { 87 | "background": "#306998", 88 | "foreground": "#FFE873", 89 | "leading_diamond": "\ue0b6", 90 | "style": "diamond", 91 | "template": "\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}", 92 | "trailing_diamond": "\ue0b4 ", 93 | "type": "python" 94 | }, 95 | { 96 | "background": "#0e8ac8", 97 | "foreground": "#ec2729", 98 | "leading_diamond": "\ue0b6", 99 | "style": "diamond", 100 | "template": "\ue738 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 101 | "trailing_diamond": "\ue0b4 ", 102 | "type": "java" 103 | }, 104 | { 105 | "background": "#0e0e0e", 106 | "foreground": "#0d6da8", 107 | "leading_diamond": "\ue0b6", 108 | "style": "diamond", 109 | "template": "\ue77f {{ if .Unsupported }}\uf071{{ else }}{{ .Full }}{{ end }}", 110 | "trailing_diamond": "\ue0b4 ", 111 | "type": "dotnet" 112 | }, 113 | { 114 | "background": "#ffffff", 115 | "foreground": "#06aad5", 116 | "leading_diamond": "\ue0b6", 117 | "style": "diamond", 118 | "template": "\ufcd1 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 119 | "trailing_diamond": "\ue0b4 ", 120 | "type": "go" 121 | }, 122 | { 123 | "background": "#f3f0ec", 124 | "foreground": "#925837", 125 | "leading_diamond": "\ue0b6", 126 | "style": "diamond", 127 | "template": "\ue7a8 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 128 | "trailing_diamond": "\ue0b4 ", 129 | "type": "rust" 130 | }, 131 | { 132 | "background": "#e1e8e9", 133 | "foreground": "#055b9c", 134 | "leading_diamond": " \ue0b6", 135 | "style": "diamond", 136 | "template": "\ue798 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 137 | "trailing_diamond": "\ue0b4 ", 138 | "type": "dart" 139 | }, 140 | { 141 | "background": "#ffffff", 142 | "foreground": "#ce092f", 143 | "leading_diamond": " \ue0b6", 144 | "style": "diamond", 145 | "template": "\ue753 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 146 | "trailing_diamond": "\ue0b4 ", 147 | "type": "angular" 148 | }, 149 | { 150 | "background": "#1e293b", 151 | "foreground": "#ffffff", 152 | "leading_diamond": " \ue0b6", 153 | "style": "diamond", 154 | "template": "{{ if .Error }}{{ .Error }}{{ else }}Nx {{ .Full }}{{ end }}", 155 | "trailing_diamond": "\ue0b4 ", 156 | "type": "nx" 157 | }, 158 | { 159 | "background": "#945bb3", 160 | "foreground": "#359a25", 161 | "leading_diamond": " \ue0b6", 162 | "style": "diamond", 163 | "template": "<#ca3c34>\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 164 | "trailing_diamond": "\ue0b4 ", 165 | "type": "julia" 166 | }, 167 | { 168 | "background": "#ffffff", 169 | "foreground": "#9c1006", 170 | "leading_diamond": "\ue0b6", 171 | "style": "diamond", 172 | "template": "\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 173 | "trailing_diamond": "\ue0b4 ", 174 | "type": "ruby" 175 | }, 176 | { 177 | "background": "#ffffff", 178 | "foreground": "#5398c2", 179 | "leading_diamond": "\ue0b6", 180 | "style": "diamond", 181 | "template": "\uf104<#f5bf45>\uf0e7\uf105 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}", 182 | "trailing_diamond": "\ue0b4 ", 183 | "type": "azfunc" 184 | }, 185 | { 186 | "background": "#565656", 187 | "foreground": "#faa029", 188 | "leading_diamond": "\ue0b6", 189 | "style": "diamond", 190 | "template": "\ue7ad {{.Profile}}{{if .Region}}@{{.Region}}{{end}}", 191 | "trailing_diamond": "\ue0b4 ", 192 | "type": "aws" 193 | }, 194 | { 195 | "background": "#316ce4", 196 | "foreground": "#ffffff", 197 | "leading_diamond": "\ue0b6", 198 | "style": "diamond", 199 | "template": "\ufd31 {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}", 200 | "trailing_diamond": "\ue0b4", 201 | "type": "kubectl" 202 | }, 203 | { 204 | "background": "#b2bec3", 205 | "foreground": "#222222", 206 | "leading_diamond": "\ue0b6", 207 | "properties": { 208 | "linux": "\ue712", 209 | "macos": "\ue711", 210 | "windows": "\ue70f" 211 | }, 212 | "style": "diamond", 213 | "template": " {{ if .WSL }}WSL at {{ end }}{{.Icon}}<#262626> \ue0b2", 214 | "type": "os" 215 | }, 216 | { 217 | "background": "#f36943", 218 | "background_templates": [ 219 | "{{if eq \"Charging\" .State.String}}#b8e994{{end}}", 220 | "{{if eq \"Discharging\" .State.String}}#fff34e{{end}}", 221 | "{{if eq \"Full\" .State.String}}#33DD2D{{end}}" 222 | ], 223 | "foreground": "#262626", 224 | "invert_powerline": true, 225 | "leading_diamond": "\ue0b2", 226 | "properties": { 227 | "charged_icon": "\uf58e ", 228 | "charging_icon": "\uf1e6 ", 229 | "discharging_icon": "\ue234 " 230 | }, 231 | "style": "diamond", 232 | "template": " {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\uf295 <#262626>\ue0b2", 233 | "type": "battery" 234 | }, 235 | { 236 | "background": "#374259", 237 | "foreground": "#F2D8D8", 238 | "invert_powerline": true, 239 | "leading_diamond": "\ue0b2", 240 | "properties": { 241 | "time_format": "Jan 2,3:04 PM" 242 | }, 243 | "style": "diamond", 244 | "template": " \uf5ef {{ .CurrentDate | date .Format }} ", 245 | "trailing_diamond": "\ue0b4", 246 | "type": "time" 247 | } 248 | ], 249 | "type": "prompt" 250 | }, 251 | { 252 | "alignment": "left", 253 | "newline": true, 254 | "segments": [ 255 | { 256 | "foreground": "#21c7c7", 257 | "style": "plain", 258 | "template": "\u2570\u2500", 259 | "type": "text" 260 | }, 261 | { 262 | "foreground": "#e0f8ff", 263 | "foreground_templates": ["{{ if gt .Code 0 }}#ef5350{{ end }}"], 264 | "properties": { 265 | "always_enabled": true 266 | }, 267 | "style": "plain", 268 | "template": "\ue285\ufb00 ", 269 | "type": "exit" 270 | } 271 | ], 272 | "type": "prompt" 273 | } 274 | ], 275 | "version": 3 276 | } 277 | -------------------------------------------------------------------------------- /profile_and_settings/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$help": "https://aka.ms/terminal-documentation", 3 | "$schema": "https://aka.ms/terminal-profiles-schema", 4 | "actions": 5 | [ 6 | { 7 | "command": 8 | { 9 | "action": "splitPane", 10 | "split": "auto", 11 | "splitMode": "duplicate" 12 | }, 13 | "keys": "alt+shift+d" 14 | }, 15 | { 16 | "command": "find", 17 | "keys": "ctrl+shift+f" 18 | }, 19 | { 20 | "command": "paste", 21 | "keys": "ctrl+v" 22 | }, 23 | { 24 | "command": 25 | { 26 | "action": "copy", 27 | "singleLine": false 28 | }, 29 | "keys": "ctrl+c" 30 | } 31 | ], 32 | "copyFormatting": "none", 33 | "copyOnSelect": false, 34 | "defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", 35 | "newTabMenu": 36 | [ 37 | { 38 | "type": "remainingProfiles" 39 | } 40 | ], 41 | "profiles": 42 | { 43 | "defaults": 44 | { 45 | "font": 46 | { 47 | "face": "CaskaydiaCove Nerd Font" 48 | }, 49 | "opacity": 20, 50 | "useAcrylic": true 51 | }, 52 | "list": 53 | [ 54 | { 55 | "font": 56 | { 57 | "face": "CaskaydiaCove Nerd Font" 58 | }, 59 | "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", 60 | "hidden": false, 61 | "name": "PowerShell", 62 | "source": "Windows.Terminal.PowershellCore" 63 | }, 64 | { 65 | "colorScheme": "Campbell", 66 | "commandline": "ssh root@192.168.1.1", 67 | "guid": "{205a405f-c1ca-49c2-8697-b7334d9c7924}", 68 | "hidden": false, 69 | "icon": "C:\\Users\\fahim\\openwrt.ico", 70 | "name": "FoxKid Router", 71 | "startingDirectory": "%USERPROFILE%" 72 | }, 73 | { 74 | "commandline": "%SystemRoot%\\System32\\cmd.exe", 75 | "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", 76 | "hidden": false, 77 | "name": "Command Prompt" 78 | }, 79 | { 80 | "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", 81 | "hidden": false, 82 | "name": "Azure Cloud Shell", 83 | "source": "Windows.Terminal.Azure" 84 | }, 85 | { 86 | "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", 87 | "hidden": false, 88 | "name": "Windows PowerShell" 89 | }, 90 | { 91 | "guid": "{c59733c4-f1e8-5275-9e1f-6d1db4da0a43}", 92 | "hidden": false, 93 | "name": "Developer Command Prompt for VS 2022", 94 | "source": "Windows.Terminal.VisualStudio" 95 | }, 96 | { 97 | "guid": "{96ce2d53-692b-5fc8-b82f-937d2f25460f}", 98 | "hidden": false, 99 | "name": "Developer PowerShell for VS 2022", 100 | "source": "Windows.Terminal.VisualStudio" 101 | }, 102 | { 103 | "guid": "{51855cb2-8cce-5362-8f54-464b92b32386}", 104 | "hidden": false, 105 | "name": "Ubuntu", 106 | "source": "CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc" 107 | }, 108 | { 109 | "guid": "{2c4de342-38b7-51cf-b940-2309a097f518}", 110 | "hidden": true, 111 | "name": "Ubuntu", 112 | "source": "Windows.Terminal.Wsl" 113 | } 114 | ] 115 | }, 116 | "schemes": 117 | [ 118 | { 119 | "background": "#0C0C0C", 120 | "black": "#0C0C0C", 121 | "blue": "#0037DA", 122 | "brightBlack": "#767676", 123 | "brightBlue": "#3B78FF", 124 | "brightCyan": "#61D6D6", 125 | "brightGreen": "#16C60C", 126 | "brightPurple": "#B4009E", 127 | "brightRed": "#E74856", 128 | "brightWhite": "#F2F2F2", 129 | "brightYellow": "#F9F1A5", 130 | "cursorColor": "#FFFFFF", 131 | "cyan": "#3A96DD", 132 | "foreground": "#CCCCCC", 133 | "green": "#13A10E", 134 | "name": "Campbell", 135 | "purple": "#881798", 136 | "red": "#C50F1F", 137 | "selectionBackground": "#FFFFFF", 138 | "white": "#CCCCCC", 139 | "yellow": "#C19C00" 140 | }, 141 | { 142 | "background": "#012456", 143 | "black": "#0C0C0C", 144 | "blue": "#0037DA", 145 | "brightBlack": "#767676", 146 | "brightBlue": "#3B78FF", 147 | "brightCyan": "#61D6D6", 148 | "brightGreen": "#16C60C", 149 | "brightPurple": "#B4009E", 150 | "brightRed": "#E74856", 151 | "brightWhite": "#F2F2F2", 152 | "brightYellow": "#F9F1A5", 153 | "cursorColor": "#FFFFFF", 154 | "cyan": "#3A96DD", 155 | "foreground": "#CCCCCC", 156 | "green": "#13A10E", 157 | "name": "Campbell Powershell", 158 | "purple": "#881798", 159 | "red": "#C50F1F", 160 | "selectionBackground": "#FFFFFF", 161 | "white": "#CCCCCC", 162 | "yellow": "#C19C00" 163 | }, 164 | { 165 | "background": "#282C34", 166 | "black": "#282C34", 167 | "blue": "#61AFEF", 168 | "brightBlack": "#5A6374", 169 | "brightBlue": "#61AFEF", 170 | "brightCyan": "#56B6C2", 171 | "brightGreen": "#98C379", 172 | "brightPurple": "#C678DD", 173 | "brightRed": "#E06C75", 174 | "brightWhite": "#DCDFE4", 175 | "brightYellow": "#E5C07B", 176 | "cursorColor": "#FFFFFF", 177 | "cyan": "#56B6C2", 178 | "foreground": "#DCDFE4", 179 | "green": "#98C379", 180 | "name": "One Half Dark", 181 | "purple": "#C678DD", 182 | "red": "#E06C75", 183 | "selectionBackground": "#FFFFFF", 184 | "white": "#DCDFE4", 185 | "yellow": "#E5C07B" 186 | }, 187 | { 188 | "background": "#FAFAFA", 189 | "black": "#383A42", 190 | "blue": "#0184BC", 191 | "brightBlack": "#4F525D", 192 | "brightBlue": "#61AFEF", 193 | "brightCyan": "#56B5C1", 194 | "brightGreen": "#98C379", 195 | "brightPurple": "#C577DD", 196 | "brightRed": "#DF6C75", 197 | "brightWhite": "#FFFFFF", 198 | "brightYellow": "#E4C07A", 199 | "cursorColor": "#4F525D", 200 | "cyan": "#0997B3", 201 | "foreground": "#383A42", 202 | "green": "#50A14F", 203 | "name": "One Half Light", 204 | "purple": "#A626A4", 205 | "red": "#E45649", 206 | "selectionBackground": "#FFFFFF", 207 | "white": "#FAFAFA", 208 | "yellow": "#C18301" 209 | }, 210 | { 211 | "background": "#002B36", 212 | "black": "#002B36", 213 | "blue": "#268BD2", 214 | "brightBlack": "#073642", 215 | "brightBlue": "#839496", 216 | "brightCyan": "#93A1A1", 217 | "brightGreen": "#586E75", 218 | "brightPurple": "#6C71C4", 219 | "brightRed": "#CB4B16", 220 | "brightWhite": "#FDF6E3", 221 | "brightYellow": "#657B83", 222 | "cursorColor": "#FFFFFF", 223 | "cyan": "#2AA198", 224 | "foreground": "#839496", 225 | "green": "#859900", 226 | "name": "Solarized Dark", 227 | "purple": "#D33682", 228 | "red": "#DC322F", 229 | "selectionBackground": "#FFFFFF", 230 | "white": "#EEE8D5", 231 | "yellow": "#B58900" 232 | }, 233 | { 234 | "background": "#FDF6E3", 235 | "black": "#002B36", 236 | "blue": "#268BD2", 237 | "brightBlack": "#073642", 238 | "brightBlue": "#839496", 239 | "brightCyan": "#93A1A1", 240 | "brightGreen": "#586E75", 241 | "brightPurple": "#6C71C4", 242 | "brightRed": "#CB4B16", 243 | "brightWhite": "#FDF6E3", 244 | "brightYellow": "#657B83", 245 | "cursorColor": "#002B36", 246 | "cyan": "#2AA198", 247 | "foreground": "#657B83", 248 | "green": "#859900", 249 | "name": "Solarized Light", 250 | "purple": "#D33682", 251 | "red": "#DC322F", 252 | "selectionBackground": "#FFFFFF", 253 | "white": "#EEE8D5", 254 | "yellow": "#B58900" 255 | }, 256 | { 257 | "background": "#000000", 258 | "black": "#000000", 259 | "blue": "#3465A4", 260 | "brightBlack": "#555753", 261 | "brightBlue": "#729FCF", 262 | "brightCyan": "#34E2E2", 263 | "brightGreen": "#8AE234", 264 | "brightPurple": "#AD7FA8", 265 | "brightRed": "#EF2929", 266 | "brightWhite": "#EEEEEC", 267 | "brightYellow": "#FCE94F", 268 | "cursorColor": "#FFFFFF", 269 | "cyan": "#06989A", 270 | "foreground": "#D3D7CF", 271 | "green": "#4E9A06", 272 | "name": "Tango Dark", 273 | "purple": "#75507B", 274 | "red": "#CC0000", 275 | "selectionBackground": "#FFFFFF", 276 | "white": "#D3D7CF", 277 | "yellow": "#C4A000" 278 | }, 279 | { 280 | "background": "#FFFFFF", 281 | "black": "#000000", 282 | "blue": "#3465A4", 283 | "brightBlack": "#555753", 284 | "brightBlue": "#729FCF", 285 | "brightCyan": "#34E2E2", 286 | "brightGreen": "#8AE234", 287 | "brightPurple": "#AD7FA8", 288 | "brightRed": "#EF2929", 289 | "brightWhite": "#EEEEEC", 290 | "brightYellow": "#FCE94F", 291 | "cursorColor": "#000000", 292 | "cyan": "#06989A", 293 | "foreground": "#555753", 294 | "green": "#4E9A06", 295 | "name": "Tango Light", 296 | "purple": "#75507B", 297 | "red": "#CC0000", 298 | "selectionBackground": "#FFFFFF", 299 | "white": "#D3D7CF", 300 | "yellow": "#C4A000" 301 | }, 302 | { 303 | "background": "#300A24", 304 | "black": "#171421", 305 | "blue": "#0037DA", 306 | "brightBlack": "#767676", 307 | "brightBlue": "#08458F", 308 | "brightCyan": "#2C9FB3", 309 | "brightGreen": "#26A269", 310 | "brightPurple": "#A347BA", 311 | "brightRed": "#C01C28", 312 | "brightWhite": "#F2F2F2", 313 | "brightYellow": "#A2734C", 314 | "cursorColor": "#FFFFFF", 315 | "cyan": "#3A96DD", 316 | "foreground": "#FFFFFF", 317 | "green": "#26A269", 318 | "name": "Ubuntu-ColorScheme", 319 | "purple": "#881798", 320 | "red": "#C21A23", 321 | "selectionBackground": "#FFFFFF", 322 | "white": "#CCCCCC", 323 | "yellow": "#A2734C" 324 | }, 325 | { 326 | "background": "#000000", 327 | "black": "#000000", 328 | "blue": "#000080", 329 | "brightBlack": "#808080", 330 | "brightBlue": "#0000FF", 331 | "brightCyan": "#00FFFF", 332 | "brightGreen": "#00FF00", 333 | "brightPurple": "#FF00FF", 334 | "brightRed": "#FF0000", 335 | "brightWhite": "#FFFFFF", 336 | "brightYellow": "#FFFF00", 337 | "cursorColor": "#FFFFFF", 338 | "cyan": "#008080", 339 | "foreground": "#C0C0C0", 340 | "green": "#008000", 341 | "name": "Vintage", 342 | "purple": "#800080", 343 | "red": "#800000", 344 | "selectionBackground": "#FFFFFF", 345 | "white": "#C0C0C0", 346 | "yellow": "#808000" 347 | } 348 | ], 349 | "themes": [], 350 | "useAcrylicInTabRow": true 351 | } -------------------------------------------------------------------------------- /profile_and_settings/$profile.ps1: -------------------------------------------------------------------------------- 1 | using namespace System.Management.Automation 2 | using namespace System.Management.Automation.Language 3 | 4 | if ($host.Name -eq 'ConsoleHost') 5 | { 6 | Import-Module PSReadLine 7 | } 8 | #Import-Module PSColors 9 | #Import-Module posh-git 10 | Import-Module -Name Terminal-Icons 11 | #Import-Module oh-my-posh 12 | set-alias desktop "Desktop.ps1" 13 | #Set-Theme ParadoxGlucose 14 | #Set-PoshPrompt -theme "D:\Dropbox\poshv3.json" 15 | 16 | oh-my-posh --init --shell pwsh --config C:\Users\fahim\AppData\Local\Programs\oh-my-posh\themes\foxkid.json | Invoke-Expression 17 | 18 | 19 | Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock { 20 | param($wordToComplete, $commandAst, $cursorPosition) 21 | [Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new() 22 | $Local:word = $wordToComplete.Replace('"', '""') 23 | $Local:ast = $commandAst.ToString().Replace('"', '""') 24 | winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object { 25 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 26 | } 27 | } 28 | 29 | # PowerShell parameter completion shim for the dotnet CLI 30 | Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock { 31 | param($commandName, $wordToComplete, $cursorPosition) 32 | dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object { 33 | [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) 34 | } 35 | } 36 | 37 | # --- 38 | 39 | 40 | # This is an example profile for PSReadLine. 41 | # 42 | # This is roughly what I use so there is some emphasis on emacs bindings, 43 | # but most of these bindings make sense in Windows mode as well. 44 | 45 | # Searching for commands with up/down arrow is really handy. The 46 | # option "moves to end" is useful if you want the cursor at the end 47 | # of the line while cycling through history like it does w/o searching, 48 | # without that option, the cursor will remain at the position it was 49 | # when you used up arrow, which can be useful if you forget the exact 50 | # string you started the search on. 51 | Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward 52 | Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward 53 | 54 | # This key handler shows the entire or filtered history using Out-GridView. The 55 | # typed text is used as the substring pattern for filtering. A selected command 56 | # is inserted to the command line without invoking. Multiple command selection 57 | # is supported, e.g. selected by Ctrl + Click. 58 | Set-PSReadLineKeyHandler -Key F7 ` 59 | -BriefDescription History ` 60 | -LongDescription 'Show command history' ` 61 | -ScriptBlock { 62 | $pattern = $null 63 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$pattern, [ref]$null) 64 | if ($pattern) 65 | { 66 | $pattern = [regex]::Escape($pattern) 67 | } 68 | 69 | $history = [System.Collections.ArrayList]@( 70 | $last = '' 71 | $lines = '' 72 | foreach ($line in [System.IO.File]::ReadLines((Get-PSReadLineOption).HistorySavePath)) 73 | { 74 | if ($line.EndsWith('`')) 75 | { 76 | $line = $line.Substring(0, $line.Length - 1) 77 | $lines = if ($lines) 78 | { 79 | "$lines`n$line" 80 | } 81 | else 82 | { 83 | $line 84 | } 85 | continue 86 | } 87 | 88 | if ($lines) 89 | { 90 | $line = "$lines`n$line" 91 | $lines = '' 92 | } 93 | 94 | if (($line -cne $last) -and (!$pattern -or ($line -match $pattern))) 95 | { 96 | $last = $line 97 | $line 98 | } 99 | } 100 | ) 101 | $history.Reverse() 102 | 103 | $command = $history | Out-GridView -Title History -PassThru 104 | if ($command) 105 | { 106 | [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() 107 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert(($command -join "`n")) 108 | } 109 | } 110 | 111 | 112 | # CaptureScreen is good for blog posts or email showing a transaction 113 | # of what you did when asking for help or demonstrating a technique. 114 | Set-PSReadLineKeyHandler -Chord 'Ctrl+d,Ctrl+c' -Function CaptureScreen 115 | 116 | # The built-in word movement uses character delimiters, but token based word 117 | # movement is also very useful - these are the bindings you'd use if you 118 | # prefer the token based movements bound to the normal emacs word movement 119 | # key bindings. 120 | Set-PSReadLineKeyHandler -Key Alt+d -Function ShellKillWord 121 | Set-PSReadLineKeyHandler -Key Alt+Backspace -Function ShellBackwardKillWord 122 | Set-PSReadLineKeyHandler -Key Alt+b -Function ShellBackwardWord 123 | Set-PSReadLineKeyHandler -Key Alt+f -Function ShellForwardWord 124 | Set-PSReadLineKeyHandler -Key Alt+B -Function SelectShellBackwardWord 125 | Set-PSReadLineKeyHandler -Key Alt+F -Function SelectShellForwardWord 126 | 127 | #region Smart Insert/Delete 128 | 129 | # The next four key handlers are designed to make entering matched quotes 130 | # parens, and braces a nicer experience. I'd like to include functions 131 | # in the module that do this, but this implementation still isn't as smart 132 | # as ReSharper, so I'm just providing it as a sample. 133 | 134 | Set-PSReadLineKeyHandler -Key '"',"'" ` 135 | -BriefDescription SmartInsertQuote ` 136 | -LongDescription "Insert paired quotes if not already on a quote" ` 137 | -ScriptBlock { 138 | param($key, $arg) 139 | 140 | $quote = $key.KeyChar 141 | 142 | $selectionStart = $null 143 | $selectionLength = $null 144 | [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) 145 | 146 | $line = $null 147 | $cursor = $null 148 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 149 | 150 | # If text is selected, just quote it without any smarts 151 | if ($selectionStart -ne -1) 152 | { 153 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $quote + $line.SubString($selectionStart, $selectionLength) + $quote) 154 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) 155 | return 156 | } 157 | 158 | $ast = $null 159 | $tokens = $null 160 | $parseErrors = $null 161 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$parseErrors, [ref]$null) 162 | 163 | function FindToken 164 | { 165 | param($tokens, $cursor) 166 | 167 | foreach ($token in $tokens) 168 | { 169 | if ($cursor -lt $token.Extent.StartOffset) { continue } 170 | if ($cursor -lt $token.Extent.EndOffset) { 171 | $result = $token 172 | $token = $token -as [StringExpandableToken] 173 | if ($token) { 174 | $nested = FindToken $token.NestedTokens $cursor 175 | if ($nested) { $result = $nested } 176 | } 177 | 178 | return $result 179 | } 180 | } 181 | return $null 182 | } 183 | 184 | $token = FindToken $tokens $cursor 185 | 186 | # If we're on or inside a **quoted** string token (so not generic), we need to be smarter 187 | if ($token -is [StringToken] -and $token.Kind -ne [TokenKind]::Generic) { 188 | # If we're at the start of the string, assume we're inserting a new string 189 | if ($token.Extent.StartOffset -eq $cursor) { 190 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote ") 191 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) 192 | return 193 | } 194 | 195 | # If we're at the end of the string, move over the closing quote if present. 196 | if ($token.Extent.EndOffset -eq ($cursor + 1) -and $line[$cursor] -eq $quote) { 197 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) 198 | return 199 | } 200 | } 201 | 202 | if ($null -eq $token -or 203 | $token.Kind -eq [TokenKind]::RParen -or $token.Kind -eq [TokenKind]::RCurly -or $token.Kind -eq [TokenKind]::RBracket) { 204 | if ($line[0..$cursor].Where{$_ -eq $quote}.Count % 2 -eq 1) { 205 | # Odd number of quotes before the cursor, insert a single quote 206 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote) 207 | } 208 | else { 209 | # Insert matching quotes, move cursor to be in between the quotes 210 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote") 211 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) 212 | } 213 | return 214 | } 215 | 216 | # If cursor is at the start of a token, enclose it in quotes. 217 | if ($token.Extent.StartOffset -eq $cursor) { 218 | if ($token.Kind -eq [TokenKind]::Generic -or $token.Kind -eq [TokenKind]::Identifier -or 219 | $token.Kind -eq [TokenKind]::Variable -or $token.TokenFlags.hasFlag([TokenFlags]::Keyword)) { 220 | $end = $token.Extent.EndOffset 221 | $len = $end - $cursor 222 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace($cursor, $len, $quote + $line.SubString($cursor, $len) + $quote) 223 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($end + 2) 224 | return 225 | } 226 | } 227 | 228 | # We failed to be smart, so just insert a single quote 229 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote) 230 | } 231 | 232 | Set-PSReadLineKeyHandler -Key '(','{','[' ` 233 | -BriefDescription InsertPairedBraces ` 234 | -LongDescription "Insert matching braces" ` 235 | -ScriptBlock { 236 | param($key, $arg) 237 | 238 | $closeChar = switch ($key.KeyChar) 239 | { 240 | <#case#> '(' { [char]')'; break } 241 | <#case#> '{' { [char]'}'; break } 242 | <#case#> '[' { [char]']'; break } 243 | } 244 | 245 | $selectionStart = $null 246 | $selectionLength = $null 247 | [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) 248 | 249 | $line = $null 250 | $cursor = $null 251 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 252 | 253 | if ($selectionStart -ne -1) 254 | { 255 | # Text is selected, wrap it in brackets 256 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $key.KeyChar + $line.SubString($selectionStart, $selectionLength) + $closeChar) 257 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) 258 | } else { 259 | # No text is selected, insert a pair 260 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)$closeChar") 261 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) 262 | } 263 | } 264 | 265 | Set-PSReadLineKeyHandler -Key ')',']','}' ` 266 | -BriefDescription SmartCloseBraces ` 267 | -LongDescription "Insert closing brace or skip" ` 268 | -ScriptBlock { 269 | param($key, $arg) 270 | 271 | $line = $null 272 | $cursor = $null 273 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 274 | 275 | if ($line[$cursor] -eq $key.KeyChar) 276 | { 277 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) 278 | } 279 | else 280 | { 281 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)") 282 | } 283 | } 284 | 285 | Set-PSReadLineKeyHandler -Key Backspace ` 286 | -BriefDescription SmartBackspace ` 287 | -LongDescription "Delete previous character or matching quotes/parens/braces" ` 288 | -ScriptBlock { 289 | param($key, $arg) 290 | 291 | $line = $null 292 | $cursor = $null 293 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 294 | 295 | if ($cursor -gt 0) 296 | { 297 | $toMatch = $null 298 | if ($cursor -lt $line.Length) 299 | { 300 | switch ($line[$cursor]) 301 | { 302 | <#case#> '"' { $toMatch = '"'; break } 303 | <#case#> "'" { $toMatch = "'"; break } 304 | <#case#> ')' { $toMatch = '('; break } 305 | <#case#> ']' { $toMatch = '['; break } 306 | <#case#> '}' { $toMatch = '{'; break } 307 | } 308 | } 309 | 310 | if ($toMatch -ne $null -and $line[$cursor-1] -eq $toMatch) 311 | { 312 | [Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2) 313 | } 314 | else 315 | { 316 | [Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg) 317 | } 318 | } 319 | } 320 | 321 | #endregion Smart Insert/Delete 322 | 323 | # Sometimes you enter a command but realize you forgot to do something else first. 324 | # This binding will let you save that command in the history so you can recall it, 325 | # but it doesn't actually execute. It also clears the line with RevertLine so the 326 | # undo stack is reset - though redo will still reconstruct the command line. 327 | Set-PSReadLineKeyHandler -Key Alt+w ` 328 | -BriefDescription SaveInHistory ` 329 | -LongDescription "Save current line in history but do not execute" ` 330 | -ScriptBlock { 331 | param($key, $arg) 332 | 333 | $line = $null 334 | $cursor = $null 335 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 336 | [Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($line) 337 | [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() 338 | } 339 | 340 | # Insert text from the clipboard as a here string 341 | Set-PSReadLineKeyHandler -Key Ctrl+V ` 342 | -BriefDescription PasteAsHereString ` 343 | -LongDescription "Paste the clipboard text as a here string" ` 344 | -ScriptBlock { 345 | param($key, $arg) 346 | 347 | Add-Type -Assembly PresentationCore 348 | if ([System.Windows.Clipboard]::ContainsText()) 349 | { 350 | # Get clipboard text - remove trailing spaces, convert \r\n to \n, and remove the final \n. 351 | $text = ([System.Windows.Clipboard]::GetText() -replace "\p{Zs}*`r?`n","`n").TrimEnd() 352 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n$text`n'@") 353 | } 354 | else 355 | { 356 | [Microsoft.PowerShell.PSConsoleReadLine]::Ding() 357 | } 358 | } 359 | 360 | # Sometimes you want to get a property of invoke a member on what you've entered so far 361 | # but you need parens to do that. This binding will help by putting parens around the current selection, 362 | # or if nothing is selected, the whole line. 363 | Set-PSReadLineKeyHandler -Key 'Alt+(' ` 364 | -BriefDescription ParenthesizeSelection ` 365 | -LongDescription "Put parenthesis around the selection or entire line and move the cursor to after the closing parenthesis" ` 366 | -ScriptBlock { 367 | param($key, $arg) 368 | 369 | $selectionStart = $null 370 | $selectionLength = $null 371 | [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) 372 | 373 | $line = $null 374 | $cursor = $null 375 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 376 | if ($selectionStart -ne -1) 377 | { 378 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, '(' + $line.SubString($selectionStart, $selectionLength) + ')') 379 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) 380 | } 381 | else 382 | { 383 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.Length, '(' + $line + ')') 384 | [Microsoft.PowerShell.PSConsoleReadLine]::EndOfLine() 385 | } 386 | } 387 | 388 | # Each time you press Alt+', this key handler will change the token 389 | # under or before the cursor. It will cycle through single quotes, double quotes, or 390 | # no quotes each time it is invoked. 391 | Set-PSReadLineKeyHandler -Key "Alt+'" ` 392 | -BriefDescription ToggleQuoteArgument ` 393 | -LongDescription "Toggle quotes on the argument under the cursor" ` 394 | -ScriptBlock { 395 | param($key, $arg) 396 | 397 | $ast = $null 398 | $tokens = $null 399 | $errors = $null 400 | $cursor = $null 401 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) 402 | 403 | $tokenToChange = $null 404 | foreach ($token in $tokens) 405 | { 406 | $extent = $token.Extent 407 | if ($extent.StartOffset -le $cursor -and $extent.EndOffset -ge $cursor) 408 | { 409 | $tokenToChange = $token 410 | 411 | # If the cursor is at the end (it's really 1 past the end) of the previous token, 412 | # we only want to change the previous token if there is no token under the cursor 413 | if ($extent.EndOffset -eq $cursor -and $foreach.MoveNext()) 414 | { 415 | $nextToken = $foreach.Current 416 | if ($nextToken.Extent.StartOffset -eq $cursor) 417 | { 418 | $tokenToChange = $nextToken 419 | } 420 | } 421 | break 422 | } 423 | } 424 | 425 | if ($tokenToChange -ne $null) 426 | { 427 | $extent = $tokenToChange.Extent 428 | $tokenText = $extent.Text 429 | if ($tokenText[0] -eq '"' -and $tokenText[-1] -eq '"') 430 | { 431 | # Switch to no quotes 432 | $replacement = $tokenText.Substring(1, $tokenText.Length - 2) 433 | } 434 | elseif ($tokenText[0] -eq "'" -and $tokenText[-1] -eq "'") 435 | { 436 | # Switch to double quotes 437 | $replacement = '"' + $tokenText.Substring(1, $tokenText.Length - 2) + '"' 438 | } 439 | else 440 | { 441 | # Add single quotes 442 | $replacement = "'" + $tokenText + "'" 443 | } 444 | 445 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace( 446 | $extent.StartOffset, 447 | $tokenText.Length, 448 | $replacement) 449 | } 450 | } 451 | 452 | # This example will replace any aliases on the command line with the resolved commands. 453 | Set-PSReadLineKeyHandler -Key "Alt+%" ` 454 | -BriefDescription ExpandAliases ` 455 | -LongDescription "Replace all aliases with the full command" ` 456 | -ScriptBlock { 457 | param($key, $arg) 458 | 459 | $ast = $null 460 | $tokens = $null 461 | $errors = $null 462 | $cursor = $null 463 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) 464 | 465 | $startAdjustment = 0 466 | foreach ($token in $tokens) 467 | { 468 | if ($token.TokenFlags -band [TokenFlags]::CommandName) 469 | { 470 | $alias = $ExecutionContext.InvokeCommand.GetCommand($token.Extent.Text, 'Alias') 471 | if ($alias -ne $null) 472 | { 473 | $resolvedCommand = $alias.ResolvedCommandName 474 | if ($resolvedCommand -ne $null) 475 | { 476 | $extent = $token.Extent 477 | $length = $extent.EndOffset - $extent.StartOffset 478 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace( 479 | $extent.StartOffset + $startAdjustment, 480 | $length, 481 | $resolvedCommand) 482 | 483 | # Our copy of the tokens won't have been updated, so we need to 484 | # adjust by the difference in length 485 | $startAdjustment += ($resolvedCommand.Length - $length) 486 | } 487 | } 488 | } 489 | } 490 | } 491 | 492 | # F1 for help on the command line - naturally 493 | Set-PSReadLineKeyHandler -Key F1 ` 494 | -BriefDescription CommandHelp ` 495 | -LongDescription "Open the help window for the current command" ` 496 | -ScriptBlock { 497 | param($key, $arg) 498 | 499 | $ast = $null 500 | $tokens = $null 501 | $errors = $null 502 | $cursor = $null 503 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) 504 | 505 | $commandAst = $ast.FindAll( { 506 | $node = $args[0] 507 | $node -is [CommandAst] -and 508 | $node.Extent.StartOffset -le $cursor -and 509 | $node.Extent.EndOffset -ge $cursor 510 | }, $true) | Select-Object -Last 1 511 | 512 | if ($commandAst -ne $null) 513 | { 514 | $commandName = $commandAst.GetCommandName() 515 | if ($commandName -ne $null) 516 | { 517 | $command = $ExecutionContext.InvokeCommand.GetCommand($commandName, 'All') 518 | if ($command -is [AliasInfo]) 519 | { 520 | $commandName = $command.ResolvedCommandName 521 | } 522 | 523 | if ($commandName -ne $null) 524 | { 525 | Get-Help $commandName -ShowWindow 526 | } 527 | } 528 | } 529 | } 530 | 531 | 532 | # 533 | # Ctrl+Shift+j then type a key to mark the current directory. 534 | # Ctrj+j then the same key will change back to that directory without 535 | # needing to type cd and won't change the command line. 536 | 537 | # 538 | $global:PSReadLineMarks = @{} 539 | 540 | Set-PSReadLineKeyHandler -Key Ctrl+J ` 541 | -BriefDescription MarkDirectory ` 542 | -LongDescription "Mark the current directory" ` 543 | -ScriptBlock { 544 | param($key, $arg) 545 | 546 | $key = [Console]::ReadKey($true) 547 | $global:PSReadLineMarks[$key.KeyChar] = $pwd 548 | } 549 | 550 | Set-PSReadLineKeyHandler -Key Ctrl+j ` 551 | -BriefDescription JumpDirectory ` 552 | -LongDescription "Goto the marked directory" ` 553 | -ScriptBlock { 554 | param($key, $arg) 555 | 556 | $key = [Console]::ReadKey() 557 | $dir = $global:PSReadLineMarks[$key.KeyChar] 558 | if ($dir) 559 | { 560 | cd $dir 561 | [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() 562 | } 563 | } 564 | 565 | Set-PSReadLineKeyHandler -Key Alt+j ` 566 | -BriefDescription ShowDirectoryMarks ` 567 | -LongDescription "Show the currently marked directories" ` 568 | -ScriptBlock { 569 | param($key, $arg) 570 | 571 | $global:PSReadLineMarks.GetEnumerator() | % { 572 | [PSCustomObject]@{Key = $_.Key; Dir = $_.Value} } | 573 | Format-Table -AutoSize | Out-Host 574 | 575 | [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() 576 | } 577 | 578 | # Auto correct 'git cmt' to 'git commit' 579 | Set-PSReadLineOption -CommandValidationHandler { 580 | param([CommandAst]$CommandAst) 581 | 582 | switch ($CommandAst.GetCommandName()) 583 | { 584 | 'git' { 585 | $gitCmd = $CommandAst.CommandElements[1].Extent 586 | switch ($gitCmd.Text) 587 | { 588 | 'cmt' { 589 | [Microsoft.PowerShell.PSConsoleReadLine]::Replace( 590 | $gitCmd.StartOffset, $gitCmd.EndOffset - $gitCmd.StartOffset, 'commit') 591 | } 592 | } 593 | } 594 | } 595 | } 596 | 597 | # `ForwardChar` accepts the entire suggestion text when the cursor is at the end of the line. 598 | # This custom binding makes `RightArrow` behave similarly - accepting the next word instead of the entire suggestion text. 599 | Set-PSReadLineKeyHandler -Key RightArrow ` 600 | -BriefDescription ForwardCharAndAcceptNextSuggestionWord ` 601 | -LongDescription "Move cursor one character to the right in the current editing line and accept the next word in suggestion when it's at the end of current editing line" ` 602 | -ScriptBlock { 603 | param($key, $arg) 604 | 605 | $line = $null 606 | $cursor = $null 607 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) 608 | 609 | if ($cursor -lt $line.Length) { 610 | [Microsoft.PowerShell.PSConsoleReadLine]::ForwardChar($key, $arg) 611 | } else { 612 | [Microsoft.PowerShell.PSConsoleReadLine]::AcceptNextSuggestionWord($key, $arg) 613 | } 614 | } 615 | 616 | # Cycle through arguments on current line and select the text. This makes it easier to quickly change the argument if re-running a previously run command from the history 617 | # or if using a psreadline predictor. You can also use a digit argument to specify which argument you want to select, i.e. Alt+1, Alt+a selects the first argument 618 | # on the command line. 619 | Set-PSReadLineKeyHandler -Key Alt+a ` 620 | -BriefDescription SelectCommandArguments ` 621 | -LongDescription "Set current selection to next command argument in the command line. Use of digit argument selects argument by position" ` 622 | -ScriptBlock { 623 | param($key, $arg) 624 | 625 | $ast = $null 626 | $cursor = $null 627 | [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$null, [ref]$null, [ref]$cursor) 628 | 629 | $asts = $ast.FindAll( { 630 | $args[0] -is [System.Management.Automation.Language.ExpressionAst] -and 631 | $args[0].Parent -is [System.Management.Automation.Language.CommandAst] -and 632 | $args[0].Extent.StartOffset -ne $args[0].Parent.Extent.StartOffset 633 | }, $true) 634 | 635 | if ($asts.Count -eq 0) { 636 | [Microsoft.PowerShell.PSConsoleReadLine]::Ding() 637 | return 638 | } 639 | 640 | $nextAst = $null 641 | 642 | if ($null -ne $arg) { 643 | $nextAst = $asts[$arg - 1] 644 | } 645 | else { 646 | foreach ($ast in $asts) { 647 | if ($ast.Extent.StartOffset -ge $cursor) { 648 | $nextAst = $ast 649 | break 650 | } 651 | } 652 | 653 | if ($null -eq $nextAst) { 654 | $nextAst = $asts[0] 655 | } 656 | } 657 | 658 | $startOffsetAdjustment = 0 659 | $endOffsetAdjustment = 0 660 | 661 | if ($nextAst -is [System.Management.Automation.Language.StringConstantExpressionAst] -and 662 | $nextAst.StringConstantType -ne [System.Management.Automation.Language.StringConstantType]::BareWord) { 663 | $startOffsetAdjustment = 1 664 | $endOffsetAdjustment = 2 665 | } 666 | 667 | [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($nextAst.Extent.StartOffset + $startOffsetAdjustment) 668 | [Microsoft.PowerShell.PSConsoleReadLine]::SetMark($null, $null) 669 | [Microsoft.PowerShell.PSConsoleReadLine]::SelectForwardChar($null, ($nextAst.Extent.EndOffset - $nextAst.Extent.StartOffset) - $endOffsetAdjustment) 670 | } 671 | 672 | 673 | Set-PSReadLineOption -PredictionSource History 674 | Set-PSReadLineOption -PredictionViewStyle ListView 675 | Set-PSReadLineOption -EditMode Windows 676 | 677 | 678 | # This is an example of a macro that you might use to execute a command. 679 | # This will add the command to history. 680 | Set-PSReadLineKeyHandler -Key Ctrl+Shift+b ` 681 | -BriefDescription BuildCurrentDirectory ` 682 | -LongDescription "Build the current directory" ` 683 | -ScriptBlock { 684 | [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() 685 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet build") 686 | [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() 687 | } 688 | 689 | Set-PSReadLineKeyHandler -Key Ctrl+Shift+t ` 690 | -BriefDescription BuildCurrentDirectory ` 691 | -LongDescription "Build the current directory" ` 692 | -ScriptBlock { 693 | [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() 694 | [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet test") 695 | [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() 696 | } 697 | 698 | --------------------------------------------------------------------------------