├── .gitignore ├── themes ├── unix.json ├── linux.json ├── unix-lambda.json ├── microsoft.json ├── bash.json ├── lambda-simple.json ├── keepprompt.json ├── lukes.json ├── kiedix.json ├── babun.json ├── kiedtl.json ├── lambda.json ├── agnoster.json ├── msys.json ├── default.json ├── aag.json ├── steeef.json ├── itscaro.json ├── kubernetes.json ├── borin.json ├── zor.json ├── tonic.json ├── ys.json ├── xpando.json ├── agnoster-alternate.json ├── myty.json ├── awan.json └── xpander.json ├── .vscode ├── extensions.json └── settings.json ├── .gitattributes ├── .editorconfig ├── libexec ├── pshazz-which.ps1 ├── pshazz-config.ps1 ├── pshazz-rm.ps1 ├── pshazz-list.ps1 ├── pshazz-new.ps1 ├── ssh-complete.ps1 ├── g-complete.ps1 ├── pshazz-use.ps1 ├── pshazz-get.ps1 ├── pshazz-edit.ps1 ├── pshazz-help.ps1 ├── pshazz-init.ps1 ├── hg-complete.ps1 └── git-complete.ps1 ├── plugins ├── g.ps1 ├── z.ps1 ├── g.psd1 ├── z.psd1 ├── resetcolor.ps1 ├── k8s.ps1 ├── svn.ps1 ├── virtualenv.ps1 ├── hg.ps1 ├── aliases.ps1 ├── z.psm1 ├── git.ps1 ├── g.psm1 ├── ssh.ps1 └── dircolors.ps1 ├── lib ├── edit.ps1 ├── plugin.ps1 ├── commands.ps1 ├── help.ps1 ├── config.ps1 ├── completion.ps1 ├── theme.ps1 ├── core.ps1 └── prompt.ps1 ├── bin ├── refresh.ps1 ├── pshazz.ps1 └── install.ps1 ├── LICENSE ├── README.md └── PSScriptAnalyzerSettings.psd1 /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-workspace 2 | *~ 3 | -------------------------------------------------------------------------------- /themes/unix.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git"], 3 | "prompt": [["white", "", " `$"]] 4 | } 5 | -------------------------------------------------------------------------------- /themes/linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["ssh", "z"], 3 | "prompt": [["white", "", "[ ${user}:${path} ] `$"]] 4 | } 5 | -------------------------------------------------------------------------------- /themes/unix-lambda.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git"], 3 | "prompt": [["white", "", " $([text.encoding]::utf8.getstring((206,187)))"]] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "EditorConfig.EditorConfig", 4 | "ms-vscode.PowerShell" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /themes/microsoft.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Just the powershell defaults.", 3 | "prompt": [ 4 | [ "", "", "PS $pwd>" ] 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /themes/bash.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["ssh", "z"], 3 | "prompt": [ 4 | ["white", "", "${user}@${hostname}:${path}"], 5 | ["white", "", "`$"] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /themes/lambda-simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git"], 3 | "prompt": [ 4 | ["blue", "", " $path "], 5 | ["white", "", "$([text.encoding]::utf8.getstring((206,187)))"] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /libexec/pshazz-which.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz which 2 | # Summary: Print the theme's path 3 | 4 | param($name) 5 | 6 | if (!$name) { 7 | my_usage 8 | exit 1 9 | } 10 | 11 | find_path $name 12 | -------------------------------------------------------------------------------- /plugins/g.ps1: -------------------------------------------------------------------------------- 1 | Import-Module "$pluginDir\g" 2 | 3 | Set-Alias g Set-Bookmark -opt allscope -scope global 4 | 5 | function pshazz:g:init { 6 | $global:pshazz.completions.g = resolve-path "$psscriptroot\..\libexec\g-complete.ps1" 7 | } 8 | -------------------------------------------------------------------------------- /plugins/z.ps1: -------------------------------------------------------------------------------- 1 | # Imports [z.ps](https://github.com/JannesMeyer/z.ps) 2 | 3 | Import-Module "$pluginDir\z" 4 | Set-Alias z Search-NavigationHistory -Scope "global" 5 | function global:pshazz:z:prompt { 6 | Update-NavigationHistory $pwd.Path 7 | } 8 | -------------------------------------------------------------------------------- /plugins/g.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ModuleVersion = '1.0' 3 | Author = 'Cameron Harp' 4 | Description = 'Navigate to specific directory paths in a quick and easy way' 5 | Copyright = 'MIT' 6 | 7 | ModuleToProcess = 'g.psm1' 8 | FunctionsToExport = @('Set-Bookmark') 9 | } -------------------------------------------------------------------------------- /themes/keepprompt.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "This theme just keeps whatever prompt you already have set up in your $profile.", 3 | "plugins": [ "git", "hg", "ssh", "z", "aliases" ], 4 | "prompt": null, 5 | "git": { 6 | "prompt_dirty": "*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /plugins/z.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ModuleVersion = '1.0' 3 | Author = 'Jannes Meyer' 4 | Description = 'Jump to your favorite directories' 5 | Copyright = 'WTFPL' 6 | 7 | ModuleToProcess = 'z.psm1' 8 | FunctionsToExport = @('Update-NavigationHistory', 'Search-NavigationHistory', 'Optimize-NavigationHistory') 9 | } -------------------------------------------------------------------------------- /libexec/pshazz-config.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz config [name] [val] 2 | # Summary: Get or set pshazz config 3 | param($name, $val) 4 | 5 | if ($name) { 6 | if ($val) { 7 | set_config $name $val 8 | } else { 9 | get_config $name 10 | } 11 | } else { 12 | $cfg 13 | } 14 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /libexec/pshazz-rm.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz rm 2 | # Summary: Remove a custom theme 3 | param($name) 4 | 5 | if (!$name) { 6 | my_usage 7 | exit 1 8 | } 9 | 10 | $path = "$userThemeDir\$name.json" 11 | if (Test-Path $path) { 12 | Remove-Item $path -Force | Out-Null 13 | Write-Output "Removed custom theme '$name'." 14 | } else { 15 | Write-Output "pshazz: '$name' custom theme not found. use 'pshazz list' to see themes." 16 | exit 1 17 | } 18 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugins/resetcolor.ps1: -------------------------------------------------------------------------------- 1 | # resets the console foreground color if a program changes it 2 | function pshazz:resetcolor:init { 3 | $global:pshazz:resetcolor:fg = $host.ui.rawui.foregroundcolor 4 | $global:pshazz:resetcolor:bg = $host.ui.rawui.backgroundcolor 5 | } 6 | 7 | function global:pshazz:resetcolor:prompt { 8 | $fg = $global:pshazz:resetcolor:fg 9 | if($host.ui.rawui.foregroundcolor -ne $fg) { 10 | $host.ui.rawui.foregroundcolor = $fg 11 | } 12 | $bg = $global:pshazz:resetcolor:bg 13 | if($host.ui.rawui.backgroundcolor -ne $bg) { 14 | $host.ui.rawui.backgroundcolor = $bg 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libexec/pshazz-list.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz list 2 | # Summary: List available themes 3 | 4 | function list_themes($dir) { 5 | $themes = @() 6 | 7 | Get-ChildItem "$dir" "*.json" | ForEach-Object { 8 | $themes += [System.IO.Path]::GetFileNameWithoutExtension($_.Name) 9 | } 10 | 11 | Write-Output ($themes | Format-Wide { $_ } -AutoSize -Force | Out-String).Trim() 12 | } 13 | 14 | Write-Host "Builtin themes:" -f DarkGreen 15 | list_themes $themeDir 16 | 17 | if (Test-Path $userThemeDir) { 18 | Write-Host "Custom themes:" -f DarkGreen 19 | list_themes $userThemeDir 20 | } 21 | -------------------------------------------------------------------------------- /themes/lukes.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases" ], 3 | "prompt": [ 4 | [ "cyan", "", "$dir" ], 5 | [ "red", "", " $git_branch$git_dirty" ], 6 | [ "red", "", " $hg_branch$hg_dirty" ], 7 | [ "green", "", " `$" ] 8 | ], 9 | "git": { 10 | "prompt_dirty": "*" 11 | }, 12 | "hg": { 13 | "prompt_dirty": "*" 14 | }, 15 | "aliases": { 16 | "rm": [ "help", "man" ], 17 | "add": { 18 | "help($name)": "get-help $name -detailed | less", 19 | "man": "help" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /themes/kiedix.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z", "aliases"], 3 | "prompt": [ 4 | ["darkred", "", ""], 5 | ["green", "", " $path"], 6 | ["", "", " $git_branch"], 7 | ["", "", " $git_local_state"], 8 | ["", "", " $git_remote_state"], 9 | ["yellow", "", " `$"] 10 | ], 11 | "git": { 12 | "prompt_unstaged": "*", 13 | "prompt_staged": "+", 14 | "prompt_stash": "$", 15 | "prompt_untracked": "%", 16 | "prompt_remote_push": ">", 17 | "prompt_remote_pull": "<", 18 | "prompt_remote_same": "=" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /themes/babun.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z"], 3 | "prompt": [ 4 | ["cyan", "", "{ $dir }"], 5 | ["green", "", " $git_branch"], 6 | ["", "", " $git_local_state"], 7 | ["", "", " $git_remote_state"], 8 | ["magenta", "", " $([system.text.encoding]::utf8.getstring((194,187)))"] 9 | ], 10 | "git": { 11 | "prompt_unstaged": "*", 12 | "prompt_staged": "+", 13 | "prompt_stash": "$", 14 | "prompt_untracked": "%", 15 | "prompt_remote_push": ">", 16 | "prompt_remote_pull": "<", 17 | "prompt_remote_same": "=" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /themes/kiedtl.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z"], 3 | "prompt": [ 4 | ["red", "", "$user"], 5 | ["", "", "@$hostname"], 6 | ["blue", "", " $git_local_state"], 7 | ["cyan", "", " $git_remote_state"], 8 | ["cyan", "", " ($git_branch)"], 9 | ["yellow", "", " $dir"], 10 | ["green", "", " `n`$"] 11 | ], 12 | "git": { 13 | "prompt_unstaged": "*", 14 | "prompt_staged": "+", 15 | "prompt_stash": "$", 16 | "prompt_untracked": "%", 17 | "prompt_remote_push": ">", 18 | "prompt_remote_pull": "<", 19 | "prompt_remote_same": "=" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /themes/lambda.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z", "aliases"], 3 | "prompt": [ 4 | ["darkred", "", ""], 5 | ["green", "", " $path"], 6 | ["", "", " $git_branch"], 7 | ["", "", " $git_local_state"], 8 | ["", "", " $git_remote_state"], 9 | ["yellow", "", " $([text.encoding]::utf8.getstring((206,187)))"] 10 | ], 11 | "git": { 12 | "prompt_unstaged": "*", 13 | "prompt_staged": "+", 14 | "prompt_stash": "$", 15 | "prompt_untracked": "%", 16 | "prompt_remote_push": ">", 17 | "prompt_remote_pull": "<", 18 | "prompt_remote_same": "=" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugins/k8s.ps1: -------------------------------------------------------------------------------- 1 | function pshazz:k8s:init { 2 | $theme = $global:pshazz.theme.k8s 3 | $global:pshazz.k8s = @{ 4 | prompt_lbracket = $theme.prompt_lbracket; 5 | prompt_rbracket = $theme.prompt_rbracket; 6 | } 7 | } 8 | 9 | function global:pshazz:k8s:prompt { 10 | $vars = $global:pshazz.prompt_vars 11 | $kubeconfig = if ($env:KUBECONFIG) { $env:KUBECONFIG } else { "~/.kube/config" } 12 | $k8s_context=$(Get-Content $kubeconfig | grep "current-context:" | sed "s/current-context: //") 13 | 14 | If ($k8s_context) { 15 | $vars.git_lbracket = $global:pshazz.k8s.prompt_lbracket 16 | $vars.git_rbracket = $global:pshazz.k8s.prompt_rbracket 17 | 18 | $vars.k8s_context = $k8s_context 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /themes/agnoster.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z", "aliases"], 3 | "prompt": [ 4 | ["Black", "DarkRed", " $time"], 5 | ["DarkRed", "DarkBlue", "$rightarrow"], 6 | ["Black", "DarkBlue", " $path"], 7 | ["DarkBlue", "", "$no_git"], 8 | ["DarkBlue", "Green", "$yes_git"], 9 | ["", "Green", " $git_lbracket$git_branch"], 10 | ["Red", "Green", "$git_dirty"], 11 | ["DarkGreen", "Green", " $git_insertions"], 12 | ["DarkRed", "Green", " $git_deletions"], 13 | ["", "Green", "$git_rbracket"], 14 | ["Green", "", "$yes_git"], 15 | ["", "", " `n`$"] 16 | ], 17 | "git": { 18 | "prompt_lbracket": "[", 19 | "prompt_rbracket": "]" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /themes/msys.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases" ], 3 | "prompt": [ 4 | [ "darkgreen", "", "$user@$hostname" ], 5 | [ "darkyellow", "", " $path" ], 6 | [ "", "", " $git_lbracket$git_branch" ], 7 | [ "red", "", "$git_dirty" ], 8 | [ "", "", "$git_rbracket"], 9 | [ "", "", " $hg_lbracket$hg_branch$hg_bookmark" ], 10 | [ "red", "", "$hg_dirty" ], 11 | [ "", "", "$hg_rbracket" ], 12 | [ "", "", "`n$" ] 13 | ], 14 | "git": { 15 | "prompt_dirty": "*", 16 | "prompt_lbracket": "[", 17 | "prompt_rbracket": "]" 18 | }, 19 | "hg": { 20 | "prompt_dirty": "*", 21 | "prompt_lbracket": "[", 22 | "prompt_rbracket": "]" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libexec/pshazz-new.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz new 2 | # Summary: Create a new theme 3 | # Help: Creates a new theme and opens it in an editor. 4 | # 5 | # The new theme will use the default theme as a template. 6 | param($name) 7 | 8 | if (!$name) { 9 | my_usage 10 | exit 1 11 | } 12 | 13 | $new_path = "$userThemeDir\$name.json" 14 | 15 | if (Test-Path $new_path) { 16 | Write-Output "You already have a theme named $name. Type 'pshazz edit $name' to edit it." 17 | exit 1 18 | } 19 | 20 | new_theme $name 21 | 22 | $editor = editor 23 | 24 | if (!$editor) { 25 | Write-Output "Couldn't find a text editor!" 26 | exit 1 27 | } 28 | 29 | & $editor (Resolve-Path $new_path) 30 | 31 | Write-Output "Type 'pshazz use $name' when you're ready to try your theme." 32 | -------------------------------------------------------------------------------- /themes/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases" ], 3 | "prompt": [ 4 | [ "cyan", "", "$dir" ], 5 | [ "red", "", " $git_branch" ], 6 | [ "red", "", " $git_local_state" ], 7 | [ "red", "", " $git_remote_state" ], 8 | [ "red", "", " $hg_branch" ], 9 | [ "", "", "$hg_bookmark" ], 10 | [ "red", "", "$hg_dirty" ], 11 | [ "green", "", " `$" ] 12 | ], 13 | "git": { 14 | "prompt_unstaged": "*", 15 | "prompt_staged": "+", 16 | "prompt_stash": "$", 17 | "prompt_untracked": "%", 18 | "prompt_remote_push": ">", 19 | "prompt_remote_pull": "<", 20 | "prompt_remote_same": "=" 21 | }, 22 | "hg": { 23 | "prompt_dirty": "*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libexec/ssh-complete.ps1: -------------------------------------------------------------------------------- 1 | # everything after ^ssh\s* 2 | param($fragment) 3 | 4 | function Get-SshHost($filter) { 5 | $sshConfig = "$env:USERPROFILE\.ssh\config" 6 | 7 | $hosts = @() 8 | Get-Content $sshConfig | Where-Object { $_ -like "Host *" } | ForEach-Object { 9 | $hosts += $_.Split(" ") | Select-Object -Skip 1 | Where-Object { 10 | $_ -like "$filter*" 11 | } 12 | } 13 | 14 | return $hosts 15 | } 16 | 17 | switch -Regex ($fragment) { 18 | # Handles ssh user@ 19 | "^(?\w+)@(?\S*)$" { 20 | Get-SshHost $matches['cmd'] | ForEach-Object { 21 | return "$($matches['user'])@$_" 22 | } 23 | } 24 | 25 | # Handles ssh 26 | "^(?\S*)$" { 27 | Get-SshHost $matches['cmd'] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugins/svn.ps1: -------------------------------------------------------------------------------- 1 | try { Get-Command git -ea stop > $null } catch { return } 2 | 3 | function pshazz:svn:init { 4 | $svn = $global:pshazz.theme.svn 5 | 6 | $dirty = $svn.prompt_dirty 7 | 8 | # defaults 9 | if(!$dirty) { $dirty = "*" } 10 | 11 | $global:pshazz.svn = @{ 12 | prompt_dirty = $dirty; 13 | } 14 | } 15 | 16 | function global:pshazz:svn:prompt { 17 | $vars = $global:pshazz.prompt_vars 18 | 19 | $svn_root = pshazz_local_or_parent_path .svn 20 | 21 | if ($svn_root) { 22 | 23 | $vars.yes_svn = ([char]0xe0b0); 24 | $vars.svn_branch = "svn"; 25 | 26 | try { $status = svn status } catch {} 27 | 28 | if ($status) { 29 | $vars.svn_dirty = $global:pshazz.svn.prompt_dirty 30 | } 31 | 32 | } else { 33 | $vars.no_svn = ([char]0xe0b0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /themes/aag.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases" ], 3 | "prompt": [ 4 | [ "", "", "┌—", "" ], 5 | [ "darkgreen", "", " $user@$hostname", "$true" ], 6 | [ "darkyellow", "", " $pwd", "" ], 7 | [ "", "", " `n├— git —→", "$is_git" ], 8 | [ "", "", " $git_lbracket$git_branch", "" ], 9 | [ "red", "", " $git_dirty", "" ], 10 | [ "", "", "$git_rbracket", ""], 11 | [ "", "", " $hg_lbracket$hg_branch$hg_bookmark", "" ], 12 | [ "red", "", "$hg_dirty", "" ], 13 | [ "", "", "$hg_rbracket", "" ], 14 | [ "", "", "`n└———→", "" ] 15 | ], 16 | "git": { 17 | "prompt_lbracket": "[", 18 | "prompt_rbracket": "]" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /themes/steeef.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z"], 3 | "prompt": [ 4 | ["blue", "", "$user"], 5 | ["white", "", " at"], 6 | ["yellow", "", " $hostname"], 7 | ["white", "", " in"], 8 | ["green", "", " $path"], 9 | ["white", "", " ("], 10 | ["cyan", "", "$git_branch"], 11 | ["white", "", " $git_local_state"], 12 | ["white", "", " $git_remote_state"], 13 | ["white", "", ")`n`$"] 14 | ], 15 | "git": { 16 | "prompt_unstaged": "*", 17 | "prompt_staged": "+", 18 | "prompt_stash": "$", 19 | "prompt_untracked": "%", 20 | "prompt_remote_push": ">", 21 | "prompt_remote_pull": "<", 22 | "prompt_remote_same": "=" 23 | }, 24 | "hg": { 25 | "prompt_dirty": "*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /themes/itscaro.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases", "k8s" ], 3 | "prompt": [ 4 | [ "cyan", "", "$dir" ], 5 | [ "yellow", "", " [$k8s_context] " ], 6 | [ "red", "", " $git_branch" ], 7 | [ "red", "", " $git_local_state" ], 8 | [ "red", "", " $git_remote_state" ], 9 | [ "red", "", " $hg_branch" ], 10 | [ "", "", "$hg_bookmark" ], 11 | [ "red", "", "$hg_dirty" ], 12 | [ "green", "", " `$" ] 13 | ], 14 | "git": { 15 | "prompt_unstaged": "*", 16 | "prompt_staged": "+", 17 | "prompt_stash": "$", 18 | "prompt_untracked": "%", 19 | "prompt_remote_push": ">", 20 | "prompt_remote_pull": "<", 21 | "prompt_remote_same": "=" 22 | }, 23 | "hg": { 24 | "prompt_dirty": "*" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /libexec/pshazz-use.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz use 2 | # Summary: Change the current theme 3 | # Help: This command will configure pshazz to use the specified theme. 4 | # 5 | # To revert to the default theme, use 'default'. E.g.: 6 | # pshazz use default 7 | # 8 | # To use a random theme for each session, use 'random'. E.g.: 9 | # pshazz use random 10 | 11 | param($name) 12 | 13 | if (!$name) { 14 | my_usage 15 | Write-Output "`npshazz currently using '$($global:pshazz.theme_name)' theme." 16 | return 17 | } 18 | 19 | if ("random" -ne $name) { 20 | # make sure valid theme 21 | $theme = theme $name 22 | if (!$theme) { 23 | Write-Output "pshazz: couldn't use the theme named '$name'." 24 | exit 1 25 | } 26 | } 27 | 28 | # save theme 29 | set_config 'theme' $name 30 | 31 | # re-init 32 | pshazz init 33 | -------------------------------------------------------------------------------- /themes/kubernetes.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases", "k8s" ], 3 | "prompt": [ 4 | [ "cyan", "", "$dir" ], 5 | [ "yellow", "", " [$k8s_context] " ], 6 | [ "red", "", " $git_branch" ], 7 | [ "red", "", " $git_local_state" ], 8 | [ "red", "", " $git_remote_state" ], 9 | [ "red", "", " $hg_branch" ], 10 | [ "", "", "$hg_bookmark" ], 11 | [ "red", "", "$hg_dirty" ], 12 | [ "green", "", " `$" ] 13 | ], 14 | "git": { 15 | "prompt_unstaged": "*", 16 | "prompt_staged": "+", 17 | "prompt_stash": "$", 18 | "prompt_untracked": "%", 19 | "prompt_remote_push": ">", 20 | "prompt_remote_pull": "<", 21 | "prompt_remote_same": "=" 22 | }, 23 | "hg": { 24 | "prompt_dirty": "*" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugins/virtualenv.ps1: -------------------------------------------------------------------------------- 1 | # Plugin to display Python virtualenv in prompt 2 | 3 | function pshazz:virtualenv:init { 4 | $virtualenv = $global:pshazz.theme.virtualenv 5 | 6 | $global:pshazz.virtualenv = @{ 7 | prompt_lbracket = $virtualenv.prompt_lbracket; 8 | prompt_rbracket = $virtualenv.prompt_rbracket; 9 | } 10 | } 11 | 12 | function global:pshazz:virtualenv:prompt { 13 | $vars = $global:pshazz.prompt_vars 14 | 15 | if ($env:VIRTUAL_ENV -or $env:CONDA_DEFAULT_ENV) { 16 | $vars.virtualenv_lbracket = $global:pshazz.virtualenv.prompt_lbracket 17 | $vars.virtualenv_rbracket = $global:pshazz.virtualenv.prompt_rbracket 18 | if ($env:VIRTUAL_ENV) { 19 | $vars.virtualenv = (Get-Item $env:VIRTUAL_ENV).BaseName 20 | } else { 21 | $vars.virtualenv = $env:CONDA_DEFAULT_ENV 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libexec/pshazz-get.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz get 2 | # Summary: Get a pshazz theme from a URL 3 | 4 | param($url) 5 | 6 | if (!$url) { 7 | my_usage 8 | exit 1 9 | } 10 | 11 | if ($url -notmatch '.json$') { 12 | "pshazz: error: only URLs ending in .json are allowed" 13 | } 14 | 15 | $file = $url | Select-String '/([^/]+)$' | ForEach-Object { $_.matches.groups[1].value } 16 | $url | Select-String '/[^/]+$' | ForEach-Object { $_.matches.groups[1] } 17 | $name = $file | Select-String '[^\.]+' | ForEach-Object { $_.matches.groups[0].value } 18 | 19 | if (!$name) { 20 | "pshazz: error: empty theme name" 21 | exit 1 22 | } 23 | 24 | $path = fullpath "$userThemeDir\$file" 25 | 26 | Write-Host "downloading '$name' theme..." -nonewline 27 | try { 28 | (new-object net.webclient).downloadfile($url, $path) 29 | } catch { 30 | exit 1 31 | } 32 | 33 | write-host "done." 34 | 35 | "use 'pshazz use $name' to use" 36 | -------------------------------------------------------------------------------- /themes/borin.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git" ], 3 | "prompt": [ 4 | [ "white", "", "$user " ], 5 | [ "blue", "", "$path" ], 6 | [ "white", "", " git:" ], 7 | [ "yellow", "", "$([text.encoding]::utf8.getstring((238,130,160))) $git_branch" ], 8 | [ "yellow", "", " $git_local_state" ], 9 | [ "yellow", "", " $git_remote_state" ], 10 | [ "black", "black", "$([text.encoding]::utf8.getstring((226,157,175)))" ], 11 | [ "blue", "", "$([text.encoding]::utf8.getstring((226,157,175)))$([text.encoding]::utf8.getstring((226,157,175)))$([text.encoding]::utf8.getstring((226,157,175)))" ] 12 | ], 13 | "git": { 14 | "prompt_unstaged": "*", 15 | "prompt_staged": "+", 16 | "prompt_stash": "$", 17 | "prompt_untracked": "%", 18 | "prompt_remote_push": ">", 19 | "prompt_remote_pull": "<", 20 | "prompt_remote_same": "=" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libexec/pshazz-edit.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz edit 2 | # Summary: Edit a theme 3 | 4 | param($name) 5 | 6 | if (!$name) { 7 | my_usage 8 | exit 1 9 | } 10 | 11 | $path = "$userThemeDir\$name.json" 12 | 13 | if (!(Test-Path $path)) { 14 | if (!(Test-Path $userThemeDir)) { 15 | New-Item -Path $userThemeDir -ItemType Directory | Out-Null 16 | } 17 | 18 | # see if it's a default theme, and copy it if it is 19 | if (Test-Path "$themeDir\$name.json") { 20 | Copy-Item "$themeDir\$name.json" $path 21 | } else { 22 | Write-Output "pshazz: couldn't find a theme named '$name'. Type 'pshazz list' to see themes." 23 | exit 1 24 | } 25 | } 26 | 27 | $editor = editor 28 | if (!$editor) { 29 | Write-Output "Couldn't find a text editor!" 30 | exit 1 31 | } 32 | 33 | & $editor (resolve-path $path) 34 | 35 | Write-Output "Type 'pshazz use $name' when you're ready to try your theme." 36 | -------------------------------------------------------------------------------- /themes/zor.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "Crumzor defaults (User@Hostname:Path SCM $).", 3 | "plugins": ["git", "hg", "ssh", "z", "aliases"], 4 | "prompt": [ 5 | ["darkcyan", "", "$user"], 6 | ["gray", "", "@"], 7 | ["gray", "", "$hostname"], 8 | ["yellow", "", ":"], 9 | ["darkgray", "", "$path"], 10 | ["red", "", " $git_branch"], 11 | ["red", "", " $git_local_state"], 12 | ["red", "", " $git_remote_state"], 13 | ["red", "", " $hg_branch"], 14 | ["", "", "$hg_bookmark"], 15 | ["red", "", "$hg_dirty"], 16 | ["yellow", "", " `$"] 17 | ], 18 | "git": { 19 | "prompt_unstaged": "*", 20 | "prompt_staged": "+", 21 | "prompt_stash": "$", 22 | "prompt_untracked": "%", 23 | "prompt_remote_push": ">", 24 | "prompt_remote_pull": "<", 25 | "prompt_remote_same": "=" 26 | }, 27 | "hg": { 28 | "prompt_dirty": "*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /themes/tonic.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "ssh", "z", "aliases", "dircolors" ], 3 | "dircolors": { 4 | "dirs": [ 5 | [".*", "cyan", ""] 6 | ], 7 | "files": [ 8 | ["(?ix).(7z|zip|tar|gz|rar)$", "darkcyan", ""], 9 | ["(?ix).(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg)$", "darkgreen", ""], 10 | ["(?ix).(doc|docx|ppt|pptx|xls|xlsx|mdb|mdf|ldf)$", "magenta", ""], 11 | ["(?ix).(txt|cfg|conf|config|yml|ini|csv|log|json)$", "darkyellow", ""], 12 | ["(?ix).(sln|csproj|sqlproj|proj|targets)$", "darkred", ""], 13 | [".*", "darkgray", ""] 14 | ] 15 | }, 16 | "prompt": [ 17 | [ "white", "", "$user" ], 18 | [ "red", "", " at "], 19 | [ "white", "", "$hostname"], 20 | [ "red", "", " in "], 21 | [ "cyan", "", "$dir" ], 22 | [ "red", "", " $git_branch$git_dirty " ] 23 | ], 24 | "git": { 25 | "prompt_dirty": " [X]" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /themes/ys.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "ssh", "z"], 3 | "prompt": [ 4 | [ 5 | "yellow", 6 | "", 7 | "`n$(if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { '%' } else { '#' } )" 8 | ], 9 | ["cyan", "", " $user"], 10 | ["white", "", " @"], 11 | ["green", "", " $hostname"], 12 | ["white", "", " in"], 13 | ["yellow", "", " $path"], 14 | ["white", "", "$(if ($git_branch) {' on git:'} else {':'})"], 15 | ["cyan", "", "$git_branch"], 16 | ["white", "", " $git_local_state"], 17 | ["white", "", " $git_remote_state"], 18 | ["", "", " [$([datetime]::now.tostring(\"HH:mm:ss\"))]"], 19 | ["magenta", "", "`n`$"] 20 | ], 21 | "git": { 22 | "prompt_unstaged": "*", 23 | "prompt_staged": "+", 24 | "prompt_stash": "$", 25 | "prompt_untracked": "%", 26 | "prompt_remote_push": ">", 27 | "prompt_remote_pull": "<", 28 | "prompt_remote_same": "=" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /themes/xpando.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases", "dircolors" ], 3 | "dircolors": { 4 | "dirs": [ 5 | [".*", "cyan", ""] 6 | ], 7 | "files": [ 8 | ["(?ix).(7z|zip|tar|gz|rar)$", "darkcyan", ""], 9 | ["(?ix).(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg)$", "darkgreen", ""], 10 | ["(?ix).(doc|docx|ppt|pptx|xls|xlsx|mdb|mdf|ldf)$", "magenta", ""], 11 | ["(?ix).(txt|cfg|conf|config|yml|ini|csv|log|json)$", "darkyellow", ""], 12 | ["(?ix).(sln|csproj|sqlproj|proj|targets)$", "darkred", ""], 13 | [".*", "darkgray", ""] 14 | ] 15 | }, 16 | "prompt": [ 17 | [ "cyan", "", "$dir" ], 18 | [ "red", "", " $git_branch$git_dirty" ], 19 | [ "red", "", " $hg_branch" ], 20 | [ "", "", "$hg_bookmark" ], 21 | [ "red", "", "$hg_dirty" ], 22 | [ "green", "", " `$" ] 23 | ], 24 | "git": { 25 | "prompt_dirty": "*" 26 | }, 27 | "hg": { 28 | "prompt_dirty": "*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libexec/pshazz-help.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz help 2 | # Summary: Show help for a command 3 | param($cmd) 4 | 5 | function print_help($cmd) { 6 | $file = Get-Content "$PSScriptRoot\pshazz-$cmd.ps1" -Raw 7 | 8 | $usage = usage $file 9 | $summary = summary $file 10 | $help = help $file 11 | 12 | if ($usage) { "$usage" } 13 | if ($help) { "`n$help" } 14 | } 15 | 16 | function print_summaries { 17 | $summaries = @{} 18 | 19 | command_files | ForEach-Object { 20 | $command = command_name $_ 21 | $summary = summary (Get-Content $_.FullName -Raw ) 22 | if (!($summary)) { $summary = '' } 23 | $summaries.Add("$command ", $summary) # add padding 24 | } 25 | 26 | ($summaries.GetEnumerator() | Sort-Object name | Format-Table -HideTableHeaders -AutoSize -Wrap | Out-String).TrimEnd() 27 | } 28 | 29 | $commands = commands 30 | 31 | if (!($cmd)) { 32 | "Usage: pshazz [] 33 | 34 | Some useful commands are:" 35 | print_summaries 36 | "`nType 'pshazz help ' to get help for a specific command." 37 | } elseif ($commands -contains $cmd) { 38 | print_help $cmd 39 | } else { 40 | "pshazz help: no such command '$cmd'"; exit 1 41 | } 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /plugins/hg.ps1: -------------------------------------------------------------------------------- 1 | try { gcm hg -ea stop > $null } catch { return } 2 | 3 | function pshazz:hg:init { 4 | $hg = $global:pshazz.theme.hg 5 | 6 | $dirty = $hg.prompt_dirty 7 | 8 | if(!$dirty) { $dirty = "*" } # default 9 | 10 | $show_bookmark = prompt_uses 'hg_bookmark' 11 | 12 | $global:pshazz.hg = @{ 13 | prompt_dirty = $dirty; 14 | prompt_lbracket = $hg.prompt_lbracket; 15 | prompt_rbracket = $hg.prompt_rbracket; 16 | show_bookmark = $show_bookmark; 17 | } 18 | 19 | $global:pshazz.completions.hg = resolve-path "$psscriptroot\..\libexec\hg-complete.ps1" 20 | } 21 | 22 | function global:pshazz:hg:prompt { 23 | $vars = $global:pshazz.prompt_vars 24 | 25 | try { $branch = hg branch } catch { } 26 | if($branch) { 27 | $vars.hg_lbracket = $global:pshazz.hg.prompt_lbracket 28 | $vars.hg_rbracket = $global:pshazz.hg.prompt_rbracket 29 | 30 | $vars.is_hg = $true; 31 | 32 | $vars.hg_branch = $branch 33 | try { $status = hg status } catch { } 34 | if($status) { 35 | $vars.hg_dirty = $global:pshazz.hg.prompt_dirty 36 | } 37 | 38 | if($global:pshazz.hg.show_bookmark) { 39 | $bookmark = hg bookmarks | sls "\* ([^\s]+)" | % { $_.matches.groups[1].value } 40 | if($bookmark) { $vars.hg_bookmark = " at $bookmark" } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /themes/agnoster-alternate.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git" ], 3 | "prompt": [ 4 | [ "white", "", " ${user}@${hostname} " ], 5 | [ "black", "darkblue", "${rightarrow}" ], 6 | [ "white", "darkblue", " $path " ], 7 | [ "darkblue", "black", "$(&{If(!$git_branch.Length) {${rightarrow}}})" ], 8 | [ "darkblue", "darkyellow", "$(&{If($git_branch.Length) {${rightarrow}}})" ], 9 | [ "white", "darkyellow", "$(&{If($git_branch.Length) {' ' + $([text.encoding]::utf8.getstring((238,130,160)))}})" ], 10 | [ "white", "darkyellow", "$(&{If($git_branch.Length) {' ' + $git_branch}})" ], 11 | [ "white", "darkyellow", "$(&{If($git_branch.Length) {' ' + $git_local_state}})" ], 12 | [ "white", "darkyellow", "$(&{If($git_branch.Length) {$git_remote_state}})" ], 13 | [ "darkyellow", "darkyellow", "$(&{If($git_branch.Length) {${rightarrow}}})" ], 14 | [ "darkyellow", "black", "$(&{If($git_branch.Length) {${rightarrow}}})" ] 15 | ], 16 | "git": { 17 | "prompt_unstaged": "*", 18 | "prompt_staged": "+", 19 | "prompt_stash": "$", 20 | "prompt_untracked": "%", 21 | "prompt_remote_push": ">", 22 | "prompt_remote_pull": "<", 23 | "prompt_remote_same": "=" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /themes/myty.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "hg", "ssh", "z", "aliases", "dircolors" ], 3 | "dircolors": { 4 | "dirs": [ 5 | [".*", "cyan", ""] 6 | ], 7 | "files": [ 8 | ["(?ix).(7z|zip|tar|gz|rar)$", "darkcyan", ""], 9 | ["(?ix).(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg)$", "darkgreen", ""], 10 | ["(?ix).(doc|docx|ppt|pptx|xls|xlsx|mdb|mdf|ldf)$", "magenta", ""], 11 | ["(?ix).(txt|cfg|conf|config|yml|ini|csv|log|json)$", "darkyellow", ""], 12 | ["(?ix).(sln|csproj|sqlproj|proj|targets)$", "darkred", ""], 13 | [".*", "darkgray", ""] 14 | ] 15 | }, 16 | "prompt": [ 17 | [ "cyan", "", "$path" ], 18 | [ "red", "", "$git_lbracket$git_branch$git_dirty$git_rbracket" ], 19 | [ "red", "", "$hg_lbracket$hg_branch$hg_bookmark$hg_dirty$hg_rbracket" ], 20 | [ "green", "", "`n$([char]0x3BB)$([char]0x0BB)" ] 21 | ], 22 | "git": { 23 | "prompt_dirty": "*", 24 | "prompt_lbracket": " [", 25 | "prompt_rbracket": "]" 26 | }, 27 | "hg": { 28 | "prompt_dirty": "*", 29 | "prompt_lbracket": " [", 30 | "prompt_rbracket": "]" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /themes/awan.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "git", "ssh", "z", "aliases", "dircolors" ], 3 | "dircolors": { 4 | "dirs": [ 5 | [".*", "gray", ""] 6 | ], 7 | "files": [ 8 | ["(?ix).(7z|zip|tar|gz|rar)$", "darkcyan", ""], 9 | ["(?ix).(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|css)$", "darkgreen", ""], 10 | ["(?ix).(doc|docx|ppt|pptx|xls|xlsx|mdb|mdf|ldf)$", "magenta", ""], 11 | ["(?ix).(txt|cfg|conf|config|yml|ini|csv|log|json)$", "darkyellow", ""], 12 | ["(?ix).(php)$", "darkmagenta", ""], 13 | ["(?ix).(js)$", "darkblue", ""], 14 | ["(?ix).(sln|csproj|sqlproj|proj|targets|html)$", "darkred", ""], 15 | [".*", "darkgray", ""] 16 | ] 17 | }, 18 | "prompt": [ 19 | [ "cyan", "", "$([char]0x2601) " ], 20 | [ "green", "", "$dir" ], 21 | [ "cyan", "", " $(&{If($git_branch.Length) {'['} Else {''}})$git_branch" ], 22 | [ "darkmagenta", "", " $git_dirty" ], 23 | [ "cyan", "", " $git_local_state" ], 24 | [ "cyan", "", " $git_remote_state" ], 25 | [ "cyan", "", " $hg_branch" ], 26 | [ "", "", "$hg_bookmark" ], 27 | [ "cyan", "", "$hg_dirty$(&{If($git_branch.Length) {']'} Else {''}})" ], 28 | [ "yellow", "", " $(&{If($git_branch.Length) {$([char]0x26A1)} Else {''}})" ] 29 | ], 30 | "git": { 31 | "prompt_dirty": " [X]" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /libexec/pshazz-init.ps1: -------------------------------------------------------------------------------- 1 | # Usage: pshazz init 2 | # Summary: Initialize pshazz 3 | # Help: Usually this is called from your PS profile. 4 | # 5 | # When initializing, pshazz will use the theme configured in $env:USERPROFILE/.pshazz 6 | # or otherwise revert to the default theme. 7 | 8 | function init($theme_name) { 9 | $theme = theme $theme_name 10 | 11 | if (!$theme) { 12 | "pshazz: error: couldn't load theme '$theme_name'." 13 | 14 | # try reverting to default theme 15 | if ($theme_name -ne 'default') { 16 | $theme_name = 'default' 17 | $theme = theme $theme_name 18 | } else { 19 | # already tried loading default theme, abort 20 | exit 1 21 | } 22 | } 23 | 24 | $global:pshazz = @{} 25 | $pshazz.theme_name = $theme_name 26 | $pshazz.theme = $theme 27 | $pshazz.completions = @{} 28 | 29 | @($theme.plugins) | Where-Object { $_ } | ForEach-Object { 30 | plugin:init $_ 31 | } 32 | } 33 | 34 | $theme = get_config 'theme' 35 | 36 | # get a random theme 37 | if ($theme -eq 'random') { 38 | $themes = @() 39 | 40 | Get-ChildItem "$themeDir" "*.json" | ForEach-Object { 41 | $themes += $($_.Name -replace '.json$', '') 42 | } 43 | 44 | if (Test-Path $userThemeDir) { 45 | Get-ChildItem "$userThemeDir" "*.json" | ForEach-Object { 46 | $themes += $($_.Name -replace '.json$', '') 47 | } 48 | } 49 | 50 | $theme = $themes[(Get-Random -Maximum ($themes.Count) -SetSeed (Get-Random -Maximum (Get-Random)))] 51 | "pshazz: loaded random theme $theme" 52 | } 53 | 54 | if (!$theme) { 55 | $theme = 'default' 56 | } 57 | 58 | init $theme 59 | 60 | . "$PSScriptRoot\..\lib\prompt.ps1" 61 | . "$PSScriptRoot\..\lib\completion.ps1" 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugins/aliases.ps1: -------------------------------------------------------------------------------- 1 | # fixes some insane powershell aliases that interfere with real programs 2 | # also adds some commonly used aliases 3 | # you can specify more aliases to add and remove in the theme under aliases.rm and aliases.add 4 | function pshazz:aliases:init { 5 | # Add default aliases 6 | Set-PAlias 'll' 'ls' 7 | 8 | # remove default/theme aliases 9 | $remove = @($global:pshazz.theme.aliases.rm) + ('curl', 'wget', 'r') | Where-Object { $_ } # theme overrides 10 | $remove | ForEach-Object { 11 | # may need to execute the rm many times in parent scopes until really removed 12 | # (set-alias -option allscope copies the alias to child scopes) 13 | while (test-path "alias:$_") { 14 | Remove-Item "alias:\$_" -Force 15 | } 16 | } 17 | 18 | # Theme aliases 19 | $global:pshazz.theme.aliases.add.psobject.Properties | Where-Object { $_ } | ForEach-Object { 20 | Set-PAlias $_.Name $_.Value 21 | } 22 | } 23 | 24 | function Set-PAlias($alias, $cmd) { 25 | if (($alias -match '\(') -or ($cmd -match ' ')) { 26 | Set-InterpolatedPAlias $alias $cmd # with params 27 | } 28 | else { 29 | Set-Alias $alias $cmd -opt allscope -scope global # without params 30 | } 31 | } 32 | 33 | function Set-InterpolatedPAlias($alias, $cmd) { 34 | # alias with extra parameters, based on 35 | # http://huddledmasses.org/powershell-power-user-tips-bash-style-alias-command/ 36 | $m = $alias | Select-String '([^\(]+)(\([^\)]+\))' | Select-Object -First 1 37 | $in_param = $null 38 | 39 | if ($m) { 40 | # has input parameters 41 | $alias, $in_param = $m.Matches.Groups[1..2] | ForEach-Object { $_.Value } 42 | } 43 | 44 | $fn_body = $cmd 45 | if ($in_param) { 46 | $fn_body = "param$in_param $fn_body" 47 | } 48 | 49 | $null = New-Item -Path function: -Name "global:pshazz.alias_$alias" -Options allscope -Value $fn_body -Force 50 | Set-Alias $alias "pshazz.alias_$alias" -Opt allscope -Scope global 51 | } 52 | -------------------------------------------------------------------------------- /themes/xpander.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["git", "hg", "ssh", "z", "aliases", "dircolors"], 3 | "dircolors": { 4 | "dirs": [[".*", "cyan", ""]], 5 | "files": [ 6 | ["(?ix).(7z|zip|tar|gz|rar)$", "darkcyan", ""], 7 | [ 8 | "(?ix).(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|md|txt|tex)$", 9 | "darkgreen", 10 | "" 11 | ], 12 | ["(?ix).(doc|docx|ppt|pptx|xls|xlsx|mdb|mdf|ldf|lock)$", "magenta", ""], 13 | ["(?ix).(txt|cfg|conf|config|yml|ini|csv|log|json)$", "darkyellow", ""], 14 | ["(?ix).(sln|csproj|sqlproj|proj|targets|rc|ignore)$", "red", ""], 15 | ["(?ix).env.*", "white", ""], 16 | [".*", "darkgray", ""] 17 | ] 18 | }, 19 | "prompt": [ 20 | ["", "DarkGray", " $time "], 21 | ["DarkGray", "Blue", "$rightarrow"], 22 | ["Black", "Blue", " $path "], 23 | ["Blue", "", "$no_git"], 24 | [ 25 | "Blue", 26 | "Green", 27 | "$(&{If($is_git -and ! ($git_dirty)) {\"$yes_git \"} Else {''}})" 28 | ], 29 | [ 30 | "Blue", 31 | "Yellow", 32 | "$(&{If($is_git -and $git_dirty) {\"$yes_git \"} Else {''}})" 33 | ], 34 | [ 35 | "Black", 36 | "Green", 37 | "$(&{If($is_git -and ! ($git_dirty)) {\" \ue0a0 $git_lbracket$git_branch \"} Else {''}})" 38 | ], 39 | ["Black", "Yellow", " \ue0a0 $git_lbracket$git_branch", "$git_dirty"], 40 | [ 41 | "Black", 42 | "Green", 43 | "$(&{If($is_git -and ! ($git_dirty)) {' \u2713 '} Else {''}})" 44 | ], 45 | ["Red", "Yellow", "$(&{If($git_local_state -eq '*' -and $git_dirty) {' \u00d7 '} Else {''}})"], 46 | [ 47 | "Black", 48 | "Green", 49 | "$(&{If($is_git -and ! ($git_dirty)) {\" $git_remote_state \"} Else {''}})" 50 | ], 51 | ["Black", "Yellow", "$(&{If($git_remote_state -eq '=' -and $git_dirty) {' \u003d '} Else {''}})"], 52 | [ 53 | "", 54 | "Green", 55 | "$(&{If($is_git -and ! ($git_dirty)) {\" $git_rbracket \"} Else {''}})" 56 | ], 57 | ["", "Yellow", "$git_rbracket", "$git_dirty"], 58 | [ 59 | "Green", 60 | "", 61 | "$(&{If($is_git -and ! ($git_dirty)) {\"$yes_git\"} Else {''}})" 62 | ], 63 | ["Yellow", "", "$yes_git", "$git_dirty"], 64 | ["", "", " $"] 65 | ], 66 | "git": { 67 | "prompt_dirty": "*" 68 | }, 69 | "hg": { 70 | "prompt_dirty": "*" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugins/z.psm1: -------------------------------------------------------------------------------- 1 | # 2 | # PowerShell port of z.sh 3 | # 4 | 5 | $dbfile = "$env:UserProfile\navdb.csv" 6 | 7 | # Tip: 8 | # You should combine this script with "Push-Location" and "Pop-Location" 9 | 10 | # Get-Module -ListAvailable 11 | # Get-Module 12 | # Get-Command -Module z 13 | 14 | # Execution time: 15 | # Measure-Command { Update-NavigationHistory $pwd.Path } 16 | 17 | function Calculate-FrecencyValue { 18 | Param([Int64]$Frequency, [Int64]$LastAccess) 19 | 20 | $now = [DateTime]::UtcNow 21 | $last = [DateTime]::FromFileTimeUtc($LastAccess) 22 | $factor = switch($last) { 23 | {$_.AddHours(1) -gt $now} { 4; break } 24 | {$_.AddDays(1) -gt $now} { 2; break } 25 | {$_.AddDays(7) -gt $now} { 1/2; break } 26 | default { 1/4 } 27 | } 28 | return $factor * $Frequency 29 | } 30 | 31 | function MatchAll-Patterns { 32 | Param([String]$string, [Array][String]$patterns) 33 | 34 | foreach ($pattern in $patterns) { 35 | if ($string -inotmatch $pattern) { 36 | return $false 37 | } 38 | } 39 | return $true 40 | } 41 | 42 | function Optimize-NavigationHistory { 43 | # Make sure that all external hard drives are 44 | # plugged in before you continue 45 | 46 | # Import database 47 | try { 48 | [Array]$navdb = @(Import-Csv $dbfile -Encoding 'Unicode') 49 | } catch { 50 | $_.Exception.Message 51 | return 52 | } 53 | 54 | # TODO: Filter out all directories that don't exist 55 | # TODO: Filter out the directories that haven't been used in the last 3 months 56 | # TODO: Sort database highest rank first? 57 | foreach ($item in $navdb) { 58 | <# 59 | if (!(Test-Path $item.Path)) { 60 | # TODO: Delete item 61 | continue 62 | } 63 | #> 64 | } 65 | 66 | # Save database 67 | try { 68 | $navdb | Export-Csv -Path $dbfile -NoTypeInformation -Encoding 'Unicode' 69 | } catch { 70 | $_.Exception.Message 71 | } 72 | } 73 | 74 | function Update-NavigationHistory { 75 | #[CmdletBinding()] 76 | Param( 77 | [parameter(Mandatory=$true)] 78 | [String] 79 | $Path 80 | ) 81 | 82 | # Abort if we got $HOME 83 | $h = (Get-PsProvider 'FileSystem').home 84 | if ($Path -eq $h) { 85 | return 86 | } 87 | 88 | # Import database 89 | try { 90 | [Array]$navdb = @(Import-Csv $dbfile -Encoding 'Unicode') 91 | # TODO: Write a function that handles the database import 92 | } catch [System.IO.FileNotFoundException] { 93 | [Array]$navdb = @() 94 | } 95 | 96 | # Look for an existing record and update it accordingly 97 | $found = $false 98 | foreach ($item in $navdb) { 99 | # Update Frequency and LastAccess time 100 | if ($item.Path -eq $Path) { 101 | $found = $true 102 | ++[Int64]$item.Frequency 103 | $item.LastAccess = [DateTime]::Now.ToFileTimeUtc() 104 | } 105 | } 106 | # Nothing found 107 | if (!$found) { 108 | # Create new object 109 | $navdb += [PSCustomObject]@{ 110 | Path = $Path 111 | Frequency = 1 112 | LastAccess = [DateTime]::Now.ToFileTimeUtc() 113 | } 114 | # TODO: Append only one item instead of rewriting the whole file? 115 | } 116 | 117 | # TODO: Age the complete database if the compound score is above 1000 118 | #$navdb | Measure-Object -Sum Frequency 119 | #if ($navdb.Count -gt 1000) {} 120 | 121 | # Save database 122 | try { 123 | $navdb | Export-Csv -Path $dbfile -NoTypeInformation -Encoding 'Unicode' 124 | } catch { 125 | Write-Output $_.Exception.Message 126 | } 127 | } 128 | 129 | function Search-NavigationHistory { 130 | Param( 131 | [parameter(ValueFromRemainingArguments=$true, ValueFromPipeline=$true, Position=0)] 132 | [String] 133 | $Patterns, 134 | 135 | [Switch] 136 | $List, 137 | 138 | [ValidateSet('Default', 'Recent', 'Frequent')] 139 | [String] 140 | $SortOrder='Default' 141 | ) 142 | 143 | if ([String]::IsNullOrEmpty($Patterns)) { 144 | # No search terms given, list everything 145 | $List = $true 146 | [Array]$PatternList = @() 147 | } else { 148 | # Convert search terms to Array 149 | [Array]$PatternList = $Patterns.Split() 150 | } 151 | 152 | # Import database 153 | try { 154 | [Array]$navdb = Import-Csv $dbfile -Encoding 'Unicode' 155 | } catch [System.IO.FileNotFoundException] { 156 | $_.Exception.Message 157 | return 158 | } 159 | $navdb | Add-Member -MemberType NoteProperty -Name 'Rank' -Value 0 160 | 161 | # Create a non-fixed-size Array 162 | $candidates = New-Object System.Collections.ArrayList 163 | # Iterate over every entry in the file 164 | foreach ($item in $navdb) { 165 | # Ignore this item, if the path doesn't exist 166 | if (!(Test-Path $item.Path)) { 167 | continue 168 | } 169 | # Enhance item with Rank 170 | $item.Frequency = [Int64]($item.Frequency) 171 | $item.LastAccess = [Int64]($item.LastAccess) 172 | $item.Rank = switch($SortOrder) { 173 | 'Frequent' { $item.Frequency } 174 | 'Recent' { $item.LastAccess } 175 | default { Calculate-FrecencyValue $item.Frequency $item.LastAccess } 176 | } 177 | # Match 178 | if (MatchAll-Patterns $item.Path $PatternList) { 179 | $candidates.Add($item) | Out-Null 180 | } 181 | } 182 | # Nothing found 183 | if (!$candidates) { 184 | return 'No matches found' 185 | } 186 | 187 | if ($List) { 188 | # Display the first 20 results 189 | $candidates | Sort-Object -Descending Rank | Select-Object Path, Rank -First 20 190 | } else { 191 | # Change directory 192 | $winner = $candidates | Sort-Object -Descending Rank | Select-Object -First 1 193 | Set-Location $winner.Path 194 | } 195 | } -------------------------------------------------------------------------------- /plugins/git.ps1: -------------------------------------------------------------------------------- 1 | try { Get-Command git -ea stop > $null } catch { return } 2 | 3 | function pshazz:git:init { 4 | $git = $global:pshazz.theme.git 5 | 6 | $dirty = $git.prompt_dirty 7 | 8 | $unstaged = $git.prompt_unstaged 9 | $staged = $git.prompt_staged 10 | $stash = $git.prompt_stash 11 | $untracked = $git.prompt_untracked 12 | 13 | $push = $git.prompt_remote_push 14 | $pull = $git.prompt_remote_pull 15 | $same = $git.prompt_remote_same 16 | 17 | # defaults 18 | if(!$dirty) { $dirty = "*" } 19 | 20 | if(!$unstaged) { $unstaged = "*" } 21 | if(!$staged) { $staged = "+" } 22 | if(!$stash) { $stash = "$" } 23 | if(!$untracked) { $untracked = "%" } 24 | 25 | if(!$push) { $push = ">" } 26 | if(!$pull) { $pull = "<" } 27 | if(!$same) { $same = "=" } 28 | 29 | $global:pshazz.git = @{ 30 | prompt_dirty = $dirty; 31 | prompt_unstaged = $unstaged; 32 | prompt_staged = $staged; 33 | prompt_stash = $stash; 34 | prompt_untracked = $untracked; 35 | prompt_remote_push = $push; 36 | prompt_remote_pull = $pull; 37 | prompt_remote_same = $same; 38 | prompt_lbracket = $git.prompt_lbracket; 39 | prompt_rbracket = $git.prompt_rbracket; 40 | } 41 | 42 | $global:pshazz.completions.git = resolve-path "$psscriptroot\..\libexec\git-complete.ps1" 43 | } 44 | 45 | # Based on posh-git 46 | function global:pshazz:git:git_branch($git_dir) { 47 | $r = ''; $b = ''; $c = '' 48 | if (Test-Path $git_dir\rebase-merge\interactive) { 49 | $r = '|REBASE-i' 50 | $b = "$(Get-Content $git_dir\rebase-merge\head-name)" 51 | } elseif (Test-Path $git_dir\rebase-merge) { 52 | $r = '|REBASE-m' 53 | $b = "$(Get-Content $git_dir\rebase-merge\head-name)" 54 | } else { 55 | if (Test-Path $git_dir\rebase-apply) { 56 | if (Test-Path $git_dir\rebase-apply\rebasing) { 57 | $r = '|REBASE' 58 | } elseif (Test-Path $git_dir\rebase-apply\applying) { 59 | $r = '|AM' 60 | } else { 61 | $r = '|AM/REBASE' 62 | } 63 | } elseif (Test-Path $git_dir\MERGE_HEAD) { 64 | $r = '|MERGING' 65 | } elseif (Test-Path $git_dir\CHERRY_PICK_HEAD) { 66 | $r = '|CHERRY-PICKING' 67 | } elseif (Test-Path $git_dir\BISECT_LOG) { 68 | $r = '|BISECTING' 69 | } 70 | 71 | try { $b = git symbolic-ref HEAD } catch { } 72 | if (-not $b) { 73 | try { $b = git rev-parse --short HEAD } catch { } 74 | } 75 | } 76 | 77 | if ('true' -eq $(git rev-parse --is-inside-git-dir 2>$null)) { 78 | if ('true' -eq $(git rev-parse --is-bare-repository 2>$null)) { 79 | $c = 'BARE:' 80 | } else { 81 | $b = 'GIT_DIR!' 82 | } 83 | } 84 | 85 | return "$c$($b -replace 'refs/heads/','')$r" 86 | } 87 | 88 | function global:pshazz:git:prompt { 89 | $vars = $global:pshazz.prompt_vars 90 | 91 | $git_root = pshazz_local_or_parent_path .git 92 | 93 | if ($git_root) { 94 | 95 | $vars.git_current_branch = ([char]0xe0a0); 96 | $vars.yes_git = ([char]0xe0b0); 97 | $vars.git_local_state = "" 98 | $vars.git_remote_state = "" 99 | 100 | $vars.is_git = $true 101 | 102 | $vars.git_lbracket = $global:pshazz.git.prompt_lbracket 103 | $vars.git_rbracket = $global:pshazz.git.prompt_rbracket 104 | 105 | $vars.git_branch = pshazz:git:git_branch (Join-Path $git_root ".git") 106 | 107 | try { $status = git status --porcelain } catch { } 108 | try { $stash = git rev-parse --verify --quiet refs/stash } catch { } 109 | 110 | $unstaged = 0; 111 | $staged = 0; 112 | $untracked = 0; 113 | 114 | if($status) { 115 | $vars.git_dirty = $global:pshazz.git.prompt_dirty 116 | 117 | $status | ForEach-Object { 118 | $item_array = $_.Split(" ") 119 | 120 | if ($_.Substring(0, 2) -eq "??") { 121 | $untracked++; 122 | } 123 | 124 | if ($item_array[0].length -ne 0 -And $item_array[0][0] -ne "?") { 125 | $staged++; 126 | } 127 | 128 | if ($item_array[0].length -ne 1 -And $_[1] -ne "?") { 129 | $unstaged++; 130 | } 131 | } 132 | } 133 | 134 | if ($unstaged) { 135 | $vars.git_local_state += $global:pshazz.git.prompt_unstaged; 136 | $vars.git_unstaged = $global:pshazz.git.prompt_unstaged; 137 | } 138 | 139 | if ($staged) { 140 | $vars.git_local_state += $global:pshazz.git.prompt_staged; 141 | $vars.git_staged = $global:pshazz.git.prompt_staged; 142 | } 143 | 144 | if ($stash) { 145 | $vars.git_local_state += $global:pshazz.git.prompt_stash; 146 | $vars.git_stash = $global:pshazz.git.prompt_stash; 147 | } 148 | 149 | if ($untracked) { 150 | $vars.git_local_state += $global:pshazz.git.prompt_untracked; 151 | $vars.git_untracked = $global:pshazz.git.prompt_untracked; 152 | } 153 | 154 | # upstream state 155 | try { $tracking = cmd /c "git rev-parse --abbrev-ref @{u}" } catch { } 156 | 157 | if ($tracking -And $tracking -ne "@{u}") { 158 | try { $remote = cmd /c "git rev-list --count --left-right $tracking...HEAD" } catch { } 159 | 160 | if($remote) { 161 | $remote_array = @($remote.split()); 162 | 163 | if ($remote_array.length -eq 2) { 164 | 165 | if ($remote_array[1] -ne 0) { 166 | $vars.git_remote_state += $global:pshazz.git.prompt_remote_push; 167 | } 168 | 169 | if ($remote_array[0] -ne 0) { 170 | $vars.git_remote_state += $global:pshazz.git.prompt_remote_pull; 171 | } 172 | 173 | if ($remote_array[0] -eq 0 -And $remote_array[1] -eq 0) { 174 | $vars.git_remote_state += $global:pshazz.git.prompt_remote_same; 175 | } 176 | } 177 | } 178 | } 179 | 180 | } else { 181 | $vars.no_git = ([char]0xe0b0); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /plugins/g.psm1: -------------------------------------------------------------------------------- 1 | $cfgpath = "$env:USERPROFILE/.gconfig" 2 | 3 | function Set-Bookmark ( 4 | [string]$Key, 5 | [string]$SelectedPath = "", 6 | [switch]$Add, 7 | [switch]$Remove, 8 | [switch]$Clear, 9 | [switch]$Show, 10 | [switch]$List 11 | ) 12 | { 13 | <# 14 | .SYNOPSIS 15 | Navigate to specific directory paths in a quick and easy way. 16 | .DESCRIPTION 17 | The Set-Bookmark function uses to save location in bookmarks. Once a bookmark is added, 18 | you can easily go to one the directory by using the bookmark's name. 19 | Bookmarks are saved in teh $Env:USERPROFILE/.gconfig file. 20 | .EXAMPLE 21 | Set-Bookmark key 22 | Change current directory to a predefined bookmark 23 | .EXAMPLE 24 | Set-Bookmark key [PathToSave] -Add 25 | Add a bookmark 26 | .EXAMPLE 27 | Set-Bookmark key -Remove 28 | Remove a bookmark 29 | .EXAMPLE 30 | Set-Bookmark key -Show 31 | Show the path for a particular bookmark 32 | .EXAMPLE 33 | Set-Bookmark -List 34 | List all bookmarks 35 | .EXAMPLE 36 | Set-Bookmark -Clear 37 | Clear all bookmarks 38 | #> 39 | 40 | #------------------------------------Check Setup------------------------------------ 41 | if(-not (Test-Path $cfgpath)) 42 | { 43 | $doNothing = New-item $cfgpath -type file 44 | } 45 | 46 | #------------------------------------Show all keys------------------------------------ 47 | if($List) 48 | { 49 | $directoryContent = Get-Content $cfgpath 50 | 51 | if($directoryContent) 52 | { 53 | $longestCount = 0 54 | $directoryArray = @{} 55 | 56 | foreach($item in $directoryContent) 57 | { 58 | $keys = $item.Split("|") 59 | $keyLength = $keys[0].Length 60 | 61 | if($longestCount -eq 0) 62 | { 63 | $longestCount = $keyLength 64 | } 65 | 66 | if($keyLength -gt $longestCount) 67 | { 68 | $longestCount = $keyLength 69 | } 70 | } 71 | 72 | if($longestCount -gt 0) 73 | { 74 | $lineBreak = "" 75 | $dashLine = "" 76 | 77 | for($index = 0; $index -lt $longestCount; $index++) 78 | { 79 | if ($index -lt ($longestCount - 2)) { 80 | $lineBreak += " "; 81 | } 82 | $dashLine += "-" 83 | } 84 | 85 | 86 | Write-Host 87 | Write-Host "Key" $lineBreak "Value" 88 | Write-Host $dashLine " ------------------" 89 | 90 | foreach($item in $directoryContent) 91 | { 92 | $keys = $item.Split("|") 93 | $subCount = $longestCount - $keys[0].Length 94 | $middleBreak = " " 95 | 96 | for($index = 0; $index -lt $subCount; $index++) 97 | { 98 | $middleBreak += " " 99 | } 100 | 101 | Write-Host $keys[0] $middleBreak $keys[1] 102 | } 103 | 104 | Write-Host 105 | } 106 | } 107 | return 108 | } 109 | 110 | #------------------------------------Show key------------------------------------ 111 | if($Show) 112 | { 113 | if($Key) 114 | { 115 | $directoryContent = Get-Content $cfgpath 116 | 117 | if($directoryContent) 118 | { 119 | $specificValue = @{} 120 | 121 | foreach($item in $directoryContent) 122 | { 123 | $keys = $item.Split("|") 124 | 125 | if($keys[0] -eq $Key.ToLower()) 126 | { 127 | $specificValue = $keys 128 | 129 | break 130 | } 131 | } 132 | 133 | if($specificValue.Count -ne 0) 134 | { 135 | $dashLine = "" 136 | $lineBreak = "" 137 | 138 | for($index = 0; $index-lt $specificValue[0].Length; $index++) 139 | { 140 | $lineBreak += " "; 141 | $dashLine += "-" 142 | } 143 | 144 | Write-Host 145 | Write-Host "Key" $lineBreak "Value" 146 | Write-Host $dashLine " ------------------" -ForegroundColor Yellow 147 | Write-Host $specificValue[0] " " $specificValue[1] 148 | Write-Host 149 | } 150 | } 151 | } 152 | 153 | return 154 | } 155 | 156 | #------------------------------------Clear all keys------------------------------------ 157 | if($Clear) 158 | { 159 | $response = Read-Host "Are you sure you want to clear? [Y] or [N]" 160 | 161 | Write-Host $val 162 | 163 | if($response -and $response.ToLower() -eq "y") 164 | { 165 | Clear-Content $cfgpath 166 | } 167 | 168 | return 169 | } 170 | 171 | #------------------------------------Delete Key------------------------------------ 172 | if($Remove) 173 | { 174 | if($Key) 175 | { 176 | $directoryContent = Get-Content $cfgpath 177 | 178 | if($directoryContent) 179 | { 180 | $keyToDelete = "" 181 | 182 | foreach($item in $directoryContent) 183 | { 184 | $keys = $item.Split("|") 185 | 186 | if($keys[0] -eq $Key.ToLower()) 187 | { 188 | $keyToDelete = $item 189 | 190 | break 191 | } 192 | } 193 | 194 | if($keyToDelete -ne "") 195 | { 196 | $directoryContent = $directoryContent |? {$_ -ne $keyToDelete} 197 | 198 | Clear-Content $cfgpath 199 | 200 | Add-Content -Value $directoryContent -Path $cfgpath 201 | } 202 | } 203 | } 204 | 205 | return 206 | } 207 | 208 | #------------------------------------Add key------------------------------------ 209 | 210 | if($Add) 211 | { 212 | if($Key) 213 | { 214 | $directoryContent = Get-Content $cfgpath 215 | $isDuplicate = $false 216 | 217 | if($cfgpath) 218 | { 219 | foreach($item in $directoryContent) 220 | { 221 | $keys = $item.Split('|') 222 | 223 | if($keys[0] -eq $Key.ToLower()) 224 | { 225 | $isDuplicate = $true; 226 | 227 | break; 228 | } 229 | } 230 | } 231 | 232 | if(!$isDuplicate) 233 | { 234 | $compositeKey = $Key.ToLower() + "|" 235 | 236 | if($SelectedPath) 237 | { 238 | $compositeKey += $SelectedPath 239 | } 240 | else 241 | { 242 | $compositeKey += $pwd 243 | } 244 | 245 | Add-Content -value $compositeKey -Path $cfgpath 246 | } 247 | } 248 | 249 | return 250 | } 251 | 252 | #------------------------------------Push key------------------------------------ 253 | if($Key) 254 | { 255 | $directoryContent = Get-Content $cfgpath 256 | $bookmark = "" 257 | 258 | if($directoryContent) 259 | { 260 | foreach($item in $directoryContent) 261 | { 262 | $keys = $item.Split("|") 263 | 264 | if($keys[0] -eq $Key.ToLower()) 265 | { 266 | $bookmark = $keys[1] 267 | 268 | break 269 | } 270 | } 271 | 272 | if($bookmark) 273 | { 274 | Push-Location $bookmark 275 | } 276 | } 277 | } 278 | } -------------------------------------------------------------------------------- /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 --