├── .editorconfig
├── .gitattributes
├── .gitignore
├── .vscode
├── extensions.json
└── settings.json
├── LICENSE
├── PSScriptAnalyzerSettings.psd1
├── README.md
├── bin
├── install.ps1
├── pshazz.ps1
└── refresh.ps1
├── lib
├── commands.ps1
├── completion.ps1
├── config.ps1
├── core.ps1
├── edit.ps1
├── help.ps1
├── plugin.ps1
├── prompt.ps1
└── theme.ps1
├── libexec
├── g-complete.ps1
├── git-complete.ps1
├── hg-complete.ps1
├── pshazz-config.ps1
├── pshazz-edit.ps1
├── pshazz-get.ps1
├── pshazz-help.ps1
├── pshazz-init.ps1
├── pshazz-list.ps1
├── pshazz-new.ps1
├── pshazz-rm.ps1
├── pshazz-use.ps1
├── pshazz-which.ps1
└── ssh-complete.ps1
├── plugins
├── aliases.ps1
├── dircolors.ps1
├── g.ps1
├── g.psd1
├── g.psm1
├── git.ps1
├── hg.ps1
├── k8s.ps1
├── resetcolor.ps1
├── ssh.ps1
├── svn.ps1
├── virtualenv.ps1
├── z.ps1
├── z.psd1
└── z.psm1
└── themes
├── aag.json
├── agnoster-alternate.json
├── agnoster.json
├── awan.json
├── babun.json
├── bash.json
├── borin.json
├── default.json
├── itscaro.json
├── keepprompt.json
├── kiedix.json
├── kiedtl.json
├── kubernetes.json
├── lambda-simple.json
├── lambda.json
├── linux.json
├── lukes.json
├── microsoft.json
├── msys.json
├── myty.json
├── steeef.json
├── tonic.json
├── unix-lambda.json
├── unix.json
├── xpander.json
├── xpando.json
├── ys.json
└── zor.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = crlf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set attributes so Windows EOL gets maintained
2 | *.json text eol=crlf
3 | *.ps1 text eol=crlf
4 | *.md text eol=crlf
5 | LICENSE text eol=crlf
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sublime-workspace
2 | *~
3 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "EditorConfig.EditorConfig",
4 | "ms-vscode.PowerShell"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1",
3 | "powershell.codeFormatting.alignPropertyValuePairs": true,
4 | "powershell.codeFormatting.ignoreOneLineBlock": true,
5 | "editor.rulers": [
6 | 80,
7 | 120
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/PSScriptAnalyzerSettings.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | # Only diagnostic records of the specified severity will be generated.
3 | # Uncomment the following line if you only want Errors and Warnings but
4 | # not Information diagnostic records.
5 | Severity = @('Error','Warning')
6 |
7 | # Analyze **only** the following rules. Use IncludeRules when you want
8 | # to invoke only a small subset of the defualt rules.
9 | # IncludeRules = @('PSAvoidDefaultValueSwitchParameter',
10 | # 'PSMisleadingBacktick',
11 | # 'PSMissingModuleManifestField',
12 | # 'PSReservedCmdletChar',
13 | # 'PSReservedParams',
14 | # 'PSShouldProcess',
15 | # 'PSUseApprovedVerbs',
16 | # 'PSAvoidUsingCmdletAliases',
17 | # 'PSUseDeclaredVarsMoreThanAssignments')
18 |
19 | # Do not analyze the following rules. Use ExcludeRules when you have
20 | # commented out the IncludeRules settings above and want to include all
21 | # the default rules except for those you exclude below.
22 | # Note: if a rule is in both IncludeRules and ExcludeRules, the rule
23 | # will be excluded.
24 | ExcludeRules = @(
25 | # Pshazz uses global vars.
26 | 'PSAvoidGlobalVars',
27 | # Pshazz uses Write-Host to output colored text.
28 | 'PSAvoidUsingWriteHost',
29 | # PSUseDeclaredVarsMoreThanAssignments doesn't currently work due to:
30 | # https://github.com/PowerShell/PSScriptAnalyzer/issues/636
31 | 'PSUseDeclaredVarsMoreThanAssignments',
32 | # Do not check functions whose verbs change system state
33 | 'PSUseShouldProcessForStateChangingFunctions'
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pshazz
2 | ##### Give your powershell some pizazz.
3 |
4 | Pshazz extends your powershell profile to add things like
5 |
6 | * A nicer prompt, including Git and Mercurial info
7 | * Git and Mercurial tab completion
8 | * An SSH helper that lets you never enter your private key password again
9 | * Sensible aliases, and an easy way to add your own aliases and remove ones you don't like
10 |
11 | Pshazz is designed to work with themes, so you can create your own [theme](https://github.com/lukesampson/pshazz/wiki/Themes) if the defaults aren't quite what you want. Make sure to send a pull request to include your theme with pshazz if you come up with something cool!
12 |
13 | ### Installation
14 | Using [Scoop](http://scoop.sh):
15 |
16 | ```
17 | scoop install pshazz
18 | ```
19 |
20 | If you don't have Scoop installed, you can download a zip of this repository, and add `bin\pshazz.ps1` to your PATH.
21 |
22 | ### On the shoulders of giants...
23 | Pshazz borrows heavily from:
24 |
25 | * [Posh-Git](https://github.com/dahlbyk/posh-git) by [Keith Dahlby](http://lostechies.com/keithdahlby/) for Git completions
26 | * [Posh-Hg](https://github.com/JeremySkinner/posh-hg) by [Jeremy Skinner](http://www.jeremyskinner.co.uk/) for Mercurial completions
27 | * [git-credential-winstore](http://gitcredentialstore.codeplex.com/) by [Andrew Nurse](http://vibrantcode.com/) and others, for saving SSH passwords.
28 | * [z.ps](https://github.com/JannesMeyer/z.ps) by [Jannes Meyer](https://github.com/JannesMeyer) for rapid system navigation
29 |
30 | Inspired by [Oh-My-Zsh](https://github.com/robbyrussell/oh-my-zsh).
31 |
32 | ### License
33 |
34 | Public Domain
35 |
--------------------------------------------------------------------------------
/bin/install.ps1:
--------------------------------------------------------------------------------
1 | if (!(Test-Path $PROFILE)) {
2 | $profileDir = Split-Path $PROFILE
3 |
4 | if (!(Test-Path $profileDir)) {
5 | New-Item -Path $profileDir -ItemType Directory | Out-Null
6 | }
7 |
8 | '' > $PROFILE
9 | }
10 |
11 | $old_init = "try { `$null = gcm pshazz -ea stop; pshazz init 'default' } catch { }"
12 | $new_init = "try { `$null = gcm pshazz -ea stop; pshazz init } catch { }"
13 |
14 | $text = Get-Content $PROFILE
15 |
16 | if ($null -eq ($text | Select-String 'pshazz')) {
17 | Write-Output 'Adding pshazz to your powershell profile.'
18 |
19 | # read and write whole profile to avoid problems with line endings and encodings
20 | $new_profile = @($text) + "try { `$null = gcm pshazz -ea stop; pshazz init 'default' } catch { }"
21 | $new_profile > $PROFILE
22 | } elseif ($text -contains $old_init) {
23 | Write-Output 'Updating pshazz init in your powershell profile.'
24 | $new_profile = $text -replace [Regex]::Escape($old_init), $new_init
25 | $new_profile > $PROFILE
26 | } else {
27 | Write-Output 'It looks like pshazz is already in your powershell profile, skipping.'
28 | }
29 |
30 | ""
31 | " _ _ "
32 | " _ __ ___| |__ __ _ _______| |"
33 | "| '_ \/ __| '_ \ / _`` |_ /_ / |"
34 | "| |_) \__ \ | | | (_| |/ / / /|_|"
35 | "| .__/|___/_| |_|\__,_/___/___(_)"
36 | "|_|"
37 | ""
38 |
39 | & "$PSScriptRoot\pshazz" init
40 |
41 | Write-Host "Your PowerShell is now powered by pshazz!" -f DarkGreen
42 |
--------------------------------------------------------------------------------
/bin/pshazz.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 3
2 | param($cmd)
3 |
4 | Set-StrictMode -Off
5 |
6 | . "$PSScriptRoot\..\lib\core.ps1"
7 | . "$PSScriptRoot\..\lib\config.ps1"
8 | . "$PSScriptRoot\..\lib\commands.ps1"
9 | . "$PSScriptRoot\..\lib\edit.ps1"
10 | . "$PSScriptRoot\..\lib\help.ps1"
11 | . "$PSScriptRoot\..\lib\plugin.ps1"
12 | . "$PSScriptRoot\..\lib\theme.ps1"
13 |
14 | $commands = commands
15 |
16 | if (@($null, '-h', '--help', '/?') -contains $cmd) {
17 | exec 'help' $args
18 | } elseif ($commands -contains $cmd) {
19 | exec $cmd $args
20 | } else {
21 | Write-Output "pshazz: '$cmd' isn't a pshazz command. See 'pshazz help'"
22 | exit 1
23 | }
24 |
--------------------------------------------------------------------------------
/bin/refresh.ps1:
--------------------------------------------------------------------------------
1 | # The refresh script is for development only
2 | $src = Resolve-Path "$PSScriptRoot\.."
3 | $dest = Resolve-Path "$(Split-Path (scoop which pshazz))\.."
4 |
5 | # make sure not running from the installed directory
6 | if ("$src" -eq "$dest") {
7 | Write-Output "The refresh script is for development only."
8 | return
9 | }
10 |
11 | Write-Host -NoNewline 'Copying files.'
12 | robocopy $src $dest /mir /njh /njs /nfl /ndl /xd .git /xf .DS_Store manifest.json install.json > $null
13 | Write-Host ' Done.' -f DarkGreen
14 |
15 | Write-Host 'Reloading pshazz.'
16 | pshazz init
17 |
--------------------------------------------------------------------------------
/lib/commands.ps1:
--------------------------------------------------------------------------------
1 | function command_files {
2 | Get-ChildItem "$PSScriptRoot\..\libexec" | Where-Object {
3 | $_.Name -match 'pshazz-.*?\.ps1$'
4 | }
5 | }
6 |
7 | function commands {
8 | command_files | ForEach-Object { command_name $_ }
9 | }
10 |
11 | function command_name($filename) {
12 | $filename.Name | Select-String 'pshazz-(.*?)\.ps1$' | ForEach-Object {
13 | $_.matches[0].groups[1].Value
14 | }
15 | }
16 |
17 | function exec($cmd, $arguments) {
18 | & "$PSScriptRoot\..\libexec\pshazz-$cmd.ps1" @arguments
19 | }
20 |
--------------------------------------------------------------------------------
/lib/completion.ps1:
--------------------------------------------------------------------------------
1 | # pshazz tab completion
2 |
3 | # Backup previous TabExpansion function
4 | if ((Test-Path Function:\TabExpansion) -and !$global:PshazzTabExpansionPatched) {
5 | Rename-Item Function:\TabExpansion global:PshazzTabExpansionBackup
6 | }
7 |
8 | # Override TabExpansion function
9 | # FIXME: DO NOT override global TabExpansion function
10 | function global:TabExpansion($line, $lastWord) {
11 | $expression = [regex]::Split($line, '[|;]')[-1].TrimStart()
12 |
13 | foreach($cmd in $global:pshazz.completions.keys) {
14 | if ($expression -match "^$cmd\s+(?.*)") {
15 | return & $global:pshazz.completions[$cmd] $matches['fragment']
16 | }
17 | }
18 |
19 | # Fall back on existing tab expansion
20 | if (Test-Path Function:\PshazzTabExpansionBackup) {
21 | PshazzTabExpansionBackup $line $lastWord
22 | }
23 | }
24 |
25 | # Rememeber that we've patched TabExpansion, to avoid doing it a second time.
26 | $global:PshazzTabExpansionPatched = $true
27 |
--------------------------------------------------------------------------------
/lib/config.ps1:
--------------------------------------------------------------------------------
1 | function load_cfg {
2 | if (!(Test-Path $configFile)) {
3 | return $null
4 | }
5 |
6 | try {
7 | return (Get-Content $configFile -Raw | ConvertFrom-Json -ErrorAction Stop)
8 | } catch {
9 | Write-Host "ERROR loading $cfgpath`: $($_.Exception.Message)"
10 | }
11 | }
12 |
13 | function get_config($name) {
14 | return $cfg.$name
15 | }
16 |
17 | function set_config($name, $val) {
18 | # Ensure configFile exists
19 | if (!(Test-Path $configFile)) {
20 | New-Item $configFile -Force -ErrorAction Ignore | Out-Null
21 | }
22 |
23 | if (!$cfg) {
24 | $cfg = @{ $name = $val }
25 | } else {
26 | if ($null -eq $cfg.$name) {
27 | $cfg | Add-Member -MemberType NoteProperty -Name $name -Value $val
28 | } else {
29 | $cfg.$name = $val
30 | }
31 | }
32 |
33 | ConvertTo-Json $cfg | Set-Content $configFile -Encoding ASCII
34 | }
35 |
36 | $cfg = load_cfg
37 |
--------------------------------------------------------------------------------
/lib/core.ps1:
--------------------------------------------------------------------------------
1 | function fullpath($path) {
2 | $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
3 | }
4 |
5 | # checks if the current theme's prompt will use a variable
6 | function prompt_uses($varname) {
7 | foreach($item in $global:pshazz.theme.prompt) {
8 | if ($item[2] -match "\`$$varname\b") {
9 | return $true
10 | }
11 | }
12 | return $false
13 | }
14 |
15 | # Pshazz Env
16 | $configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
17 | $configFile = "$configHome\pshazz\config.json"
18 | $pluginDir = fullpath "$PSScriptRoot\..\plugins"
19 | $userPluginDir = "$configHome\pshazz\plugins"
20 | $themeDir = fullpath "$PSScriptRoot\..\themes"
21 | $userThemeDir = "$configHome\pshazz\themes"
22 |
23 | # Migration
24 |
25 | if ((Test-Path "$env:USERPROFILE\.pshazz") -and !(Test-Path $configFile)) {
26 | New-Item -ItemType Directory (Split-Path -Path $configFile) -ErrorAction Ignore | Out-Null
27 | Move-Item "$env:USERPROFILE\.pshazz" $configFile
28 | Write-Host "WARNING: pshazz configuration has been migrated from '~/.pshazz' to '$configFile'" -f DarkYellow
29 | }
30 |
31 | if ((Test-Path "$env:USERPROFILE\pshazz\plugins") -and !(Test-Path $userPluginDir)) {
32 | Move-Item "$env:USERPROFILE\pshazz\plugins" "$userPluginDir\..\" -Force
33 | Write-Host "WARNING: pshazz user plugins have been migrated from '~/pshazz/plugins' to '$userPluginDir'" -f DarkYellow
34 | }
35 |
36 | if ((Test-Path "$env:USERPROFILE\pshazz") -and !(Test-Path $userThemeDir)) {
37 | New-Item -Path $userThemeDir -ItemType Directory -ErrorAction Ignore | Out-Null
38 | Move-Item "$env:USERPROFILE\pshazz\*.json" "$userThemeDir" -Force
39 | Write-Host "WARNING: pshazz user themes have been migrated from '~/pshazz/' to '$userThemeDir'" -f DarkYellow
40 | # Leave old files there
41 | # Remove-Item -Recurse -Force "$env:USERPROFILE\pshazz"
42 | }
43 |
--------------------------------------------------------------------------------
/lib/edit.ps1:
--------------------------------------------------------------------------------
1 | $known_editors = "gvim", "vim", "nano", "notepad2", "notepad++", "notepad"
2 |
3 | function editor {
4 | $editor = get_config 'editor'
5 | if ($editor) {
6 | return $editor
7 | }
8 |
9 | foreach($editor in $known_editors) {
10 | if (has_editor $editor) {
11 | return $editor
12 | }
13 | }
14 |
15 | return $null
16 | }
17 |
18 | function has_editor($name) {
19 | try { Get-Command $name -ErrorAction Stop; $true } catch { $false }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/help.ps1:
--------------------------------------------------------------------------------
1 | function usage($text) {
2 | $text | Select-String '(?m)^# Usage: ([^\n]*)$' | ForEach-Object {
3 | "Usage: " + $_.matches[0].groups[1].value
4 | }
5 | }
6 |
7 | function summary($text) {
8 | $text | Select-String '(?m)^# Summary: ([^\n]*)$' | ForEach-Object {
9 | $_.matches[0].groups[1].value
10 | }
11 | }
12 |
13 | function help($text) {
14 | $help_lines = $text | Select-String '(?ms)^# Help:(.(?!^[^#]))*' | ForEach-Object {
15 | $_.matches[0].value
16 | }
17 | $help_lines -replace '(?ms)^#\s?(Help: )?', ''
18 | }
19 |
20 | function my_usage {
21 | # gets usage for the calling script
22 | usage (Get-Content $myInvocation.PSCommandPath -Raw)
23 | }
24 |
--------------------------------------------------------------------------------
/lib/plugin.ps1:
--------------------------------------------------------------------------------
1 | function plugin:init($name) {
2 | # try user plugin dir first
3 | $path = "$userPluginDir\$name.ps1"
4 | if (!(Test-Path $path)) {
5 | # fallback to defaults
6 | $path = "$pluginDir\$name.ps1"
7 | if (!(Test-Path $path)) {
8 | Write-Warning "Couldn't find pshazz plugin '$name'."
9 | return $false
10 | }
11 | }
12 |
13 | . $path
14 |
15 | $initfn = "pshazz:$name`:init"
16 | if (Test-Path "function:\$initfn") {
17 | & $initfn
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/prompt.ps1:
--------------------------------------------------------------------------------
1 | function global:pshazz_time {
2 | return (Get-Date -DisplayHint Time -Format T)
3 | }
4 |
5 | function global:pshazz_dir {
6 | $h = (Get-PsProvider 'FileSystem').Home
7 | if ($PWD -like $h) {
8 | return '~'
9 | }
10 |
11 | $dir = Split-Path $PWD -Leaf
12 | if ($dir -imatch '[a-z]:\\') {
13 | return '\'
14 | }
15 | return $dir
16 | }
17 |
18 | function global:pshazz_two_dir {
19 | $h = (Get-PsProvider 'FileSystem').Home
20 | if ($PWD -like $h) {
21 | return '~'
22 | }
23 |
24 | $dir = Split-Path $PWD -Leaf
25 | $parent_pwd = Split-Path $PWD -Parent
26 | if ($dir -imatch '[a-z]:\\') {
27 | return '\'
28 | }
29 |
30 | if ($parent_pwd) {
31 | if ($parent_pwd -like $h) {
32 | $parent = '~'
33 | } else {
34 | $parent = Split-Path $parent_pwd -Leaf
35 | }
36 |
37 | if ( $parent -imatch '[a-z]:\\') {
38 | $dir = "\$dir"
39 | } else {
40 | $dir = "$parent\$dir"
41 | }
42 | }
43 |
44 | return $dir
45 | }
46 |
47 | function global:pshazz_path {
48 | # Replace $HOME with '~'
49 | return $PWD -replace [Regex]::Escape((Get-PsProvider 'FileSystem').Home), "~"
50 | }
51 |
52 | function global:pshazz_rightarrow {
53 | return ([char]0xe0b0)
54 | }
55 |
56 | # Based on posh-git
57 | function global:pshazz_local_or_parent_path($path) {
58 | $check_in = Get-Item -Force .
59 | if ($check_in.PSProvider.Name -ne 'FileSystem') {
60 | return $null
61 | }
62 | while ($null -ne $check_in) {
63 | $path_to_test = [System.IO.Path]::Combine($check_in.FullName, $path)
64 | if (Test-Path -LiteralPath $path_to_test) {
65 | return $check_in.FullName
66 | } else {
67 | $check_in = $check_in.Parent
68 | }
69 | }
70 | return $null
71 | }
72 |
73 |
74 | function global:pshazz_write_prompt($prompt, $vars) {
75 | $vars.keys | ForEach-Object { set-variable $_ $vars[$_] }
76 | function eval($str) {
77 | $executionContext.invokeCommand.expandString($str)
78 | }
79 |
80 | $fg_default = $Host.UI.RawUI.ForegroundColor
81 | $bg_default = $Host.UI.RawUI.BackgroundColor
82 |
83 | # write each element of the prompt, stripping out portions
84 | # that evaluate to blank strings
85 | $prompt | ForEach-Object {
86 | $str = eval $_[2]
87 |
88 | # check if there is additional conditional parameter for prompt part
89 | if ($_.Count -ge 4) {
90 | $cond = eval $_[3]
91 | $condition = ([String]::IsNullOrWhiteSpace($_[3]) -or $cond)
92 | } else {
93 | $condition = $true
94 | }
95 |
96 | # empty up the prompt part if condition fails
97 | if (!$condition) {
98 | $str = ""
99 | }
100 |
101 | if (![String]::IsNullOrWhiteSpace($str)) {
102 | $fg = eval $_[0]; $bg = eval $_[1]
103 | if (!$fg) { $fg = $fg_default }
104 | if (!$bg) { $bg = $bg_default }
105 | Write-Host $str -NoNewline -ForegroundColor $fg -BackgroundColor $bg
106 | }
107 | }
108 | }
109 |
110 | if (!$global:pshazz.theme.prompt) { return } # no prompt specified, keep existing
111 |
112 | function global:prompt {
113 | $saved_lastoperationstatus = $? # status of win32 AND powershell command (False on interrupts)
114 | $saved_lastexitcode = $lastexitcode
115 |
116 | $global:pshazz.prompt_vars = @{
117 | time = pshazz_time;
118 | dir = pshazz_dir;
119 | two_dir = pshazz_two_dir;
120 | path = pshazz_path;
121 | user = $env:username;
122 | hostname = $env:computername;
123 | rightarrow = pshazz_rightarrow;
124 | }
125 |
126 | # get plugins to populate prompt vars
127 | $global:pshazz.theme.plugins | ForEach-Object {
128 | $prompt_fn = "pshazz:$_`:prompt"
129 | if (Test-Path "function:\$prompt_fn") {
130 | & $prompt_fn
131 | }
132 | }
133 |
134 | pshazz_write_prompt $global:pshazz.theme.prompt $global:pshazz.prompt_vars
135 |
136 | $global:lastexitcode = $saved_lastexitcode
137 | " "
138 | }
139 |
--------------------------------------------------------------------------------
/lib/theme.ps1:
--------------------------------------------------------------------------------
1 | function theme($name) {
2 | $path = find_path $name
3 |
4 | if ([bool]$path) {
5 | $theme = load_theme $path
6 | if ($theme) {
7 | return $theme
8 | }
9 | }
10 | }
11 |
12 | function find_path($name) {
13 | # try user dir first
14 | $path = "$userThemeDir\$name.json"
15 | if (Test-Path $path) {
16 | return $path
17 | }
18 |
19 | # fallback to builtin dir
20 | $path = "$themeDir\$name.json"
21 | if (Test-Path $path) {
22 | return $path
23 | }
24 | }
25 |
26 | function load_theme($path) {
27 | try {
28 | return (Get-Content $path -Raw | ConvertFrom-Json -ErrorAction Stop)
29 | } catch {
30 | Write-Host "ERROR loading JSON for '$path'`:"
31 | Write-Host "$($_.Exception.Message)" -f DarkRed
32 | }
33 | }
34 |
35 | function new_theme($name) {
36 | if (!(Test-Path $userThemeDir)) {
37 | New-Item -Path $userThemeDir -ItemType Directory | Out-Null
38 | }
39 | Copy-Item "$themeDir\default.json" "$userThemeDir\$name.json"
40 | }
41 |
--------------------------------------------------------------------------------
/libexec/g-complete.ps1:
--------------------------------------------------------------------------------
1 | # everything after ^g\s*
2 | param($fragment)
3 |
4 | $cfgpath = "$env:USERPROFILE\.gconfig"
5 |
6 | $textContent = Get-Content $cfgpath
7 | $inputKeys = $fragment.Split(' ')
8 | $matchingKey = $inputKeys[$inputKeys.length - 1]
9 |
10 | if ($textContent) {
11 | $fileHash = @{}
12 |
13 | $textContent | ForEach-Object {
14 | $keys = $_.Split("|")
15 |
16 | if($keys[0] -ne $matchingKey) {
17 | $fileHash.Add($keys[0], $keys[1])
18 | }
19 | }
20 |
21 | if($fileHash.Count -gt 0) {
22 | $fileHash.Keys | ForEach-Object {
23 | if ($_.StartsWith($matchingKey))
24 | {
25 | #this will output the auto filled key to the screen.
26 | $_ | Sort-Object
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/libexec/git-complete.ps1:
--------------------------------------------------------------------------------
1 | # Based on Keith Dahlby's GitTabExpansion.ps1 from PoshGit
2 | # https://github.com/dahlbyk/posh-git
3 | #
4 | # Initial implementation by Jeremy Skinner
5 | # http://www.jeremyskinner.co.uk/2010/03/07/using-git-with-windows-powershell/
6 | param($fragment) # everything after ^git\s*
7 |
8 | $subcommands = @{
9 | bisect = 'start bad good skip reset visualize replay log run'
10 | notes = 'edit show'
11 | reflog = 'expire delete show'
12 | remote = 'add rename rm set-head show prune update'
13 | stash = 'list show drop pop apply branch save clear create'
14 | submodule = 'add status init update summary foreach sync'
15 | svn = 'init fetch clone rebase dcommit branch tag log blame find-rev set-tree create-ignore show-ignore mkdirs commit-diff info proplist propget show-externals gc reset'
16 | tfs = 'bootstrap checkin checkintool ct cleanup cleanup-workspaces clone diagnostics fetch help init pull quick-clone rcheckin shelve shelve-list unshelve verify'
17 | flow = 'init feature release hotfix'
18 | }
19 |
20 | $gitflowsubcommands = @{
21 | feature = 'list start finish publish track diff rebase checkout pull'
22 | release = 'list start finish publish track'
23 | hotfix = 'list start finish publish track'
24 | }
25 |
26 | function gitCmdOperations($commands, $command, $filter) {
27 | $commands.$command -split ' ' | Where-Object { $_ -like "$filter*" }
28 | }
29 |
30 | function gitAliases($filter) {
31 | git config --get-regexp "^alias.$filter" | ForEach-Object {
32 | [regex]::match($_, 'alias\.([^\s]+)').groups[1].value
33 | } | Sort-Object
34 | }
35 |
36 | function gitCommands($filter, $includeAliases) {
37 | $cmdList = @()
38 | $cmdList += git help --all |
39 | Where-Object { $_ -match '^ \S.*' } |
40 | ForEach-Object { $_.Split(' ', [StringSplitOptions]::RemoveEmptyEntries) } |
41 | Where-Object { $_ -like "$filter*" }
42 |
43 | if ($includeAliases) {
44 | $cmdList += gitAliases $filter
45 | }
46 | $cmdList | Sort-Object
47 | }
48 |
49 | function gitRemotes($filter) {
50 | git remote | Where-Object { $_ -like "$filter*" }
51 | }
52 |
53 | function gitBranches($filter, $includeHEAD = $false) {
54 | $prefix = $null
55 | if ($filter -match "^(?\S*\.{2,3})(?.*)") {
56 | $prefix = $matches['from']
57 | $filter = $matches['to']
58 | }
59 | $branches = @(git branch --no-color | ForEach-Object { if($_ -match "^\*?\s*(?[.*)") { $matches['ref'] } }) +
60 | @(git branch --no-color -r | ForEach-Object { if($_ -match "^ (?][\S+)(?: -> .+)?") { $matches['ref'] } }) +
61 | @(if ($includeHEAD) { 'HEAD','FETCH_HEAD','ORIG_HEAD','MERGE_HEAD' })
62 | $branches |
63 | Where-Object { $_ -ne '(no branch)' -and $_ -like "$filter*" } |
64 | ForEach-Object { $prefix + $_ }
65 | }
66 |
67 | function gitRemoteBranches($remote, $ref, $filter) {
68 | git branch --no-color -r |
69 | Where-Object { $_ -like " $remote/$filter*" } |
70 | ForEach-Object { $ref + ($_ -replace " $remote/","") }
71 | }
72 |
73 | function gitStashes($filter) {
74 | (git stash list) -replace ':.*','' |
75 | Where-Object { $_ -like "$filter*" } |
76 | ForEach-Object { "'$_'" }
77 | }
78 |
79 | function gitTfsShelvesets($filter) {
80 | (git tfs shelve-list) |
81 | Where-Object { $_ -like "$filter*" } |
82 | ForEach-Object { "'$_'" }
83 | }
84 |
85 | function gitFiles($filter, $files) {
86 | $files | Sort-Object |
87 | Where-Object { $_ -like "$filter*" } |
88 | ForEach-Object { if($_ -like '* *') { "'$_'" } else { $_ } }
89 | }
90 |
91 | # returns an array of files changes, where the file change is
92 | # an array of (x,y,path1,path2). see `git help status` for meanings
93 | function gitStatus {
94 | git -c color.status=false status --short 2>$null | Select-String '^(.)(.) (.*?)(?: -> (.*))?$' | ForEach-Object {
95 | $_all, $groups = $_.matches.groups; # discard group 0 (complete match)
96 | ,($groups | ForEach-Object { $_.value }) # ',' forces array of arrays
97 | }
98 | }
99 |
100 | function gitIndexedFiles {
101 | gitStatus | Where-Object { $_[0] -and ($_[0] -ne '?') } | ForEach-Object { $_[2] }
102 | }
103 |
104 | function gitChangedFiles {
105 | gitStatus | Where-Object { $_[1] -ne ' ' } | ForEach-Object { $_[2] }
106 | }
107 |
108 | function gitStagedFiles {
109 | gitStatus | Where-Object { 'M','A','D','R','C' -contains $_[0] } | ForEach-Object { $_[2] }
110 | }
111 |
112 | function gitUnmergedFiles {
113 | gitStatus | Where-Object { $_[1] -eq 'U' } | ForEach-Object { $_[2] }
114 | }
115 |
116 | function gitDeletedFiles {
117 | gitStatus | Where-Object { $_[1] -eq 'D' } | ForEach-Object { $_[2] }
118 | }
119 |
120 | function gitIndex($filter) {
121 | gitFiles $filter @(gitIndexedFiles)
122 | }
123 |
124 | function gitAddFiles($filter) {
125 | gitFiles $filter @(gitChangedFiles)
126 | }
127 |
128 | function gitCheckoutFiles($filter) {
129 | gitFiles $filter @(gitChangedFiles)
130 | }
131 |
132 | function gitDiffFiles($filter, $staged) {
133 | if ($staged) {
134 | gitFiles $filter @(gitStagedFiles)
135 | } else {
136 | gitFiles $filter @(gitChangedFiles)
137 | }
138 | }
139 |
140 | function gitMergeFiles($filter) {
141 | gitFiles $filter @(gitUnmergedFiles)
142 | }
143 |
144 | function gitDeleted($filter) {
145 | gitFiles $filter @(gitDeletedFiles)
146 | }
147 |
148 | function expandGitAlias($cmd, $rest) {
149 | if((git config --get-regexp "^alias\.$cmd`$") -match "^alias\.$cmd (?[^!].*)`$") {
150 | return "$($Matches['cmd'])$rest"
151 | } else {
152 | return "$cmd$rest"
153 | }
154 | }
155 |
156 | if($fragment -match "^(?\S+)(? .*)$") {
157 | $fragment = expandGitAlias $Matches['cmd'] $Matches['args']
158 | }
159 |
160 | switch -regex ($fragment) {
161 |
162 | # Handles git
163 | "^(?$($subcommands.Keys -join '|'))\s+(?\S*)$" {
164 | gitCmdOperations $subcommands $matches['cmd'] $matches['op']
165 | }
166 |
167 | # Handles git flow
168 | "^flow (?$($gitflowsubcommands.Keys -join '|'))\s+(?\S*)$" {
169 | gitCmdOperations $gitflowsubcommands $matches['cmd'] $matches['op']
170 | }
171 |
172 | # Handles git remote (rename|rm|set-head|set-branches|set-url|show|prune)
173 | "^remote.* (?:rename|rm|set-head|set-branches|set-url|show|prune).* (?\S*)$" {
174 | gitRemotes $matches['remote']
175 | }
176 |
177 | # Handles git stash (show|apply|drop|pop|branch)
178 | "^stash (?:show|apply|drop|pop|branch).* (?\S*)$" {
179 | gitStashes $matches['stash']
180 | }
181 |
182 | # Handles git bisect (bad|good|reset|skip) ][
183 | "^bisect (?:bad|good|reset|skip).* (?][\S*)$" {
184 | gitBranches $matches['ref'] $true
185 | }
186 |
187 | # Handles git tfs unshelve
188 | "^tfs +unshelve.* (?\S*)$" {
189 | gitTfsShelvesets $matches['shelveset']
190 | }
191 |
192 | # Handles git branch -d|-D|-m|-M
193 | # Handles git branch
194 | "^branch.* (?\S*)$" {
195 | gitBranches $matches['branch']
196 | }
197 |
198 | # Handles git (commands & aliases)
199 | "^(?\S*)$" {
200 | gitCommands $matches['cmd'] $true
201 | }
202 |
203 | # Handles git help (commands only)
204 | "^help (?\S*)$" {
205 | gitCommands $matches['cmd'] $false
206 | }
207 |
208 | # Handles git push remote ][:
209 | "^push.* (?\S+) (?][[^\s\:]*\:)(?\S*)$" {
210 | gitRemoteBranches $matches['remote'] $matches['ref'] $matches['branch']
211 | }
212 |
213 | # Handles git push remote
214 | # Handles git pull remote
215 | "^(?:push|pull).* (?:\S+) (?[^\s\:]*)$" {
216 | gitBranches $matches['branch']
217 | }
218 |
219 | # Handles git pull
220 | # Handles git push
221 | # Handles git fetch
222 | "^(?:push|pull|fetch).* (?\S*)$" {
223 | gitRemotes $matches['remote']
224 | }
225 |
226 | # Handles git reset HEAD
227 | # Handles git reset HEAD --
228 | "^reset.* HEAD(?:\s+--)? (?\S*)$" {
229 | gitIndex $matches['path']
230 | }
231 |
232 | # Handles git ][
233 | "^commit.*-C\s+(?][\S*)$" {
234 | gitBranches $matches['ref'] $true
235 | }
236 |
237 | # Handles git add
238 | "^add.* (?\S*)$" {
239 | gitAddFiles $matches['files']
240 | }
241 |
242 | # Handles git checkout --
243 | "^checkout.* -- (?\S*)$" {
244 | gitCheckoutFiles $matches['files']
245 | }
246 |
247 | # Handles git rm
248 | "^rm.* (?\S*)$" {
249 | gitDeleted $matches['index']
250 | }
251 |
252 | # Handles git diff/difftool
253 | "^(?:diff|difftool)(?:.* (?(?:--cached|--staged))|.*) (?\S*)$" {
254 | gitDiffFiles $matches['files'] $matches['staged']
255 | }
256 |
257 | # Handles git merge/mergetool
258 | "^(?:merge|mergetool).* (?\S*)$" {
259 | gitMergeFiles $matches['files']
260 | }
261 |
262 | # Handles git ][
263 | "^(?:checkout|cherry|cherry-pick|diff|difftool|log|merge|rebase|reflog\s+show|reset|revert|show).* (?][\S*)$" {
264 | gitBranches $matches['ref'] $true
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/libexec/hg-complete.ps1:
--------------------------------------------------------------------------------
1 | # based on Jeremy Skinner's HgTabExpansion from Posh-Hg
2 | # https://github.com/JeremySkinner/posh-hg
3 | param($fragment) # everything after ^hg\s*
4 |
5 | $script:hgCommands = @()
6 | $script:hgflowStreams = @()
7 |
8 | function hgFiles($filter, $pattern) {
9 | hg status $(hg root) |
10 | ForEach-Object {
11 | if($_ -match "($pattern){1} (.*)") {
12 | $matches[2]
13 | }
14 | } |
15 | Where-Object { $_ -like "*$filter*" } |
16 | ForEach-Object { if($_ -like '* *') { "'$_'" } else { $_ } }
17 | }
18 |
19 | function hgRemotes($filter) {
20 | hg paths | ForEach-Object {
21 | $path = $_.Split("=")[0].Trim();
22 | if($filter -and $path.StartsWith($filter)) {
23 | $path
24 | } elseif(-not $filter) {
25 | $path
26 | }
27 | }
28 | }
29 |
30 | # By default the hg command list is populated the first time hgCommands is invoked.
31 | # Invoke PopulateHgCommands in your profile if you don't want the initial hit.
32 | function hgCommands($filter) {
33 | if($script:hgCommands.Length -eq 0) {
34 | populateHgCommands
35 | }
36 |
37 | if($filter) {
38 | $hgCommands | Where-Object { $_.StartsWith($filter) } | ForEach-Object { $_.Trim() } | Sort-Object
39 | }
40 | else {
41 | $hgCommands | ForEach-Object { $_.Trim() } | Sort-Object
42 | }
43 | }
44 |
45 | # By default the hg command list is populated the first time hgCommands is invoked.
46 | # Invoke PopulateHgCommands in your profile if you don't want the initial hit.
47 | function PopulateHgCommands() {
48 | $hgCommands = foreach($cmd in (hg help)) {
49 | # Stop once we reach the "Enabled Extensions" section of help.
50 | # Not sure if there's a better way to do this...
51 | if($cmd -eq "enabled extensions:") {
52 | break
53 | }
54 |
55 | if($cmd -match '^ (\S+) (.*)') {
56 | $matches[1]
57 | }
58 | }
59 |
60 | if($global:PoshHgSettings.ShowPatches) {
61 | # MQ integration must be explicitly enabled as the user may not have the extension
62 | $hgCommands += (hg help mq) | ForEach-Object {
63 | if($_ -match '^ (\S+) (.*)') {
64 | $matches[1]
65 | }
66 | }
67 | }
68 |
69 | $script:hgCommands = $hgCommands
70 | }
71 |
72 | function findBranchOrBookmarkOrTags($filter){
73 | hgLocalBranches($filter)
74 | hgLocalTags($filter)
75 | hgLocalBookmarks($filter)
76 | }
77 |
78 | function hgLocalBranches($filter) {
79 | hg branches -a | ForEach-Object {
80 | if($_ -match "(\S+) .*") {
81 | if($filter -and $matches[1].StartsWith($filter)) {
82 | $matches[1]
83 | }
84 | elseif(-not $filter) {
85 | $matches[1]
86 | }
87 | }
88 | }
89 | }
90 |
91 | function hgLocalTags($filter) {
92 | hg tags | ForEach-Object {
93 | if($_ -match "(\S+) .*") {
94 | if($filter -and $matches[1].StartsWith($filter)) {
95 | $matches[1]
96 | }
97 | elseif(-not $filter) {
98 | $matches[1]
99 | }
100 | }
101 | }
102 | }
103 |
104 | function bookmarkName($bookmark) {
105 | $split = $bookmark.Split(" ");
106 |
107 | if($bookmark.StartsWith("*")) {
108 | $split[1]
109 | }
110 | else{
111 | $split[0]
112 | }
113 | }
114 |
115 | function hgLocalBookmarks($filter) {
116 | hg bookmarks --quiet | ForEach-Object {
117 | if($_ -match "(\S+) .*") {
118 | $bookmark = bookmarkName($matches[0])
119 | if($filter -and $bookmark.StartsWith($filter)) {
120 | $bookmark
121 | }
122 | elseif(-not $filter) {
123 | $bookmark
124 | }
125 | }
126 | }
127 | }
128 |
129 | function hgRemoteBookmarks($filter) {
130 | hg incoming -B | ForEach-Object {
131 | if($_ -match "(\S+) .*") {
132 | if($filter -and $matches[1].StartsWith($filter)) {
133 | $matches[1]
134 | }
135 | elseif(-not $filter) {
136 | $matches[1]
137 | }
138 | }
139 | }
140 | }
141 |
142 | function hgOptions($cmd, $filter) {
143 | $optList = @()
144 | $output = hg help $cmd
145 | foreach($line in $output) {
146 | if($line -match '^ ((-\S)| ) --(\S+) .*$') {
147 | $opt = $matches[3]
148 | if($filter -and $opt.StartsWith($filter)) {
149 | $optList += '--' + $opt.Trim()
150 | }
151 | elseif(-not $filter) {
152 | $optList += '--' + $opt.Trim()
153 | }
154 | }
155 | }
156 |
157 | $optList | Sort-Object
158 | }
159 |
160 | function thgCommands($filter) {
161 | $cmdList = @()
162 | $output = thg help
163 | foreach($line in $output) {
164 | if($line -match '^ (\S+) (.*)') {
165 | $cmd = $matches[1]
166 | if($filter -and $cmd.StartsWith($filter)) {
167 | $cmdList += $cmd.Trim()
168 | }
169 | elseif(-not $filter) {
170 | $cmdList += $cmd.Trim()
171 | }
172 | }
173 | }
174 |
175 | $cmdList | Sort-Object
176 | }
177 |
178 | function hgflowStreams($filter) {
179 | if($script:hgflowStreams.Length -eq 0) {
180 | $hgflow = ((hg root) + "\.flow")
181 | if (Test-Path $hgflow) {
182 | populatehgflowStreams($hgflow)
183 | } else {
184 | $hgflow = ((hg root) + "\.hgflow")
185 | if (Test-Path $hgflow) {
186 | populatehgflowStreams($hgflow)
187 | }
188 | }
189 |
190 | $script:hgflowStreams = $script:hgflowStreams
191 | }
192 |
193 | if($filter) {
194 | $hgflowStreams | Where-Object { $_.StartsWith($filter) } | ForEach-Object { $_.Trim() } | Sort-Object
195 | }
196 | else {
197 | $hgflowStreams | ForEach-Object { $_.Trim() } | Sort-Object
198 | }
199 | }
200 |
201 | function populatehgflowStreams($filename) {
202 | $ini = @{}
203 |
204 | switch -regex -file $filename
205 | {
206 | "^\[(.+)\]" # Section
207 | {
208 | $section = $matches[1]
209 | $ini[$section] = @()
210 | }
211 | "(.+?)\s*=(.*)" # Key
212 | {
213 | $name,$value = $matches[1..2]
214 | $ini[$section] += $name
215 | }
216 | }
217 |
218 | # Supporting by 0.4 and 0.9 files
219 | $script:hgflowStreams = if ($ini["Basic"]) { $ini["Basic"] } else { $ini["branchname"] }
220 | }
221 |
222 | switch -regex ($fragment) {
223 |
224 | #handles hg update
225 | #handles hg merge
226 | '^(up|update|merge|co|checkout) (\S*)$' {
227 | findBranchOrBookmarkOrTags($matches[2])
228 | }
229 |
230 | #Handles hg pull -B
231 | '^pull (-\S* )*-(B) (\S*)$' {
232 | hgRemoteBookmarks($matches[3])
233 | hgLocalBookmarks($matches[3])
234 | }
235 |
236 | #Handles hg push -B
237 | '^push (-\S* )*-(B) (\S*)$' {
238 | hgLocalBookmarks($matches[3])
239 | }
240 |
241 | #Handles hg bookmark
242 | '^(book|bookmark) (\S*)$' {
243 | hgLocalBookmarks($matches[2])
244 | }
245 |
246 | #Handles hg push
247 | #Handles hg pull
248 | #Handles hg outgoing
249 | #Handles hg incoming
250 | '^(push|pull|outgoing|incoming) (-\S* )*(\S*)$' {
251 | hgRemotes($matches[3])
252 | }
253 |
254 | #handles hg help
255 | #handles hg
256 | '^(help )?(\S*)$' {
257 | hgCommands($matches[2]);
258 | }
259 |
260 | #handles hg --]