├── 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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------