core/init.ps1
using namespace System.Management.Automation using namespace System.Management.Automation.Language New-Variable -Name PSCompletions -Value @{} -Option Constant @('config', 'confirm', 'download', 'less', 'order', 'text', 'path') | ForEach-Object { . $PSScriptRoot\utils\$_.ps1 } $PSCompletions.version = '3.2.4' $PSCompletions.path = @{} $PSCompletions.path.root = Split-Path $PSScriptRoot -Parent $PSCompletions.path.completions = Join-Path $PSCompletions.path.root 'completions' $PSCompletions.path.core = Join-Path $PSCompletions.path.root 'core' $PSCompletions.path.list = Join-Path $PSCompletions.path.root 'list.txt' $PSCompletions.path.config = Join-Path $PSCompletions.path.root 'config.json' $PSCompletions.path.old_list = Join-Path $PSCompletions.path.core '.old_list' $PSCompletions.path.update = Join-Path $PSCompletions.path.core '.update' if ($PSVersionTable.Platform -ne 'Unix') { $PSCompletions.lang = (Get-WinSystemLocale).name } else { if ($env:LANG -like 'zh[-_]CN*') { $PSCompletions.lang = 'zh-CN' } else { $PSCompletions.lang = 'en-US' } } $PSCompletions.langs = @('zh-CN', 'en-US') $PSCompletions.comp_data = [ordered]@{} $PSCompletions.comp_config = @{} $PSCompletions.temp = @{} if ($PSHOME -like "*WindowsPowerShell*" -and $PSCompletions.fn_get_config().run_with_admin -eq 1 -and (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) { if ($PSCompletions.lang -eq 'zh-CN') { @(80, 83, 67, 111, 109, 112, 108, 101, 116, 105, 111, 110, 115, 32, 27169, 22359, 21152, 36733, 38169, 35823, 65306, 10, 30001, 20110, 20320, 20351, 29992, 30340, 26159, 32, 87, 105, 110, 100, 111, 119, 115, 32, 80, 111, 119, 101, 114, 83, 104, 101, 108, 108, 65292, 20320, 38656, 35201, 20351, 29992, 31649, 29702, 21592, 26435, 38480, 21551, 21160, 23427, 10, 25512, 33616, 20320, 20351, 29992, 32, 80, 111, 119, 101, 114, 83, 104, 101, 108, 108, 65292, 23427, 19981, 38656, 35201, 31649, 29702, 21592, 26435, 38480, 10) | ForEach-Object { $privilege_err += [char]::ConvertFromUtf32($_) } Write-Host $privilege_err -f Red } else { Write-Host "PSCompletions module loading err:`nBecause you're using Windows PowerShell, you must start it with administrator privilege.`nRecommend using PowerShell as it doesn't require administrator privilege.`n" -f Red } throw } if (Get-Command Set-PSReadLineKeyHandler -ErrorAction SilentlyContinue) { Set-PSReadLineKeyHandler 'Tab' MenuComplete } if (!(Test-Path $PSCompletions.path.completions)) { New-Item -ItemType Directory $PSCompletions.path.completions > $null } if (!(Test-Path $PSCompletions.path.list) -or !(Test-Path (Join-Path $PSCompletions.path.root 'env.json'))) { $PSCompletions | Add-Member -MemberType ScriptMethod fn_move_old_version { if ([environment]::GetEnvironmentvariable('abgox_PSCompletions', 'User')) { [environment]::SetEnvironmentvariable('abgox_PSCompletions', '', 'User') } $version = (Get-ChildItem (Split-Path $PSCompletions.path.root -Parent)).Name | Sort-Object { [Version] $_ } -ErrorAction SilentlyContinue if ($version -is [array]) { $version = $version[-2] } $old_version_dir = Join-Path (Split-Path $PSCompletions.path.root -Parent) $version $old = (Get-ChildItem (Join-Path $old_version_dir 'completions') -ErrorAction SilentlyContinue | Where-Object { $_.BaseName -ne 'PSCompletions' }).FullName if ($old) { Move-Item $old $PSCompletions.path.completions -Force -ErrorAction SilentlyContinue } if (Test-Path (Join-Path $old_version_dir 'env.json')) { Move-Item (Join-Path $old_version_dir 'env.json') (Join-Path $PSCompletions.path.root 'env.json') -Force -ErrorAction SilentlyContinue } if (Test-Path (Join-Path $old_version_dir 'config.json')) { Move-Item (Join-Path $old_version_dir 'config.json') (Join-Path $PSCompletions.path.root 'config.json') -Force -ErrorAction SilentlyContinue } } $PSCompletions.fn_move_old_version() $PSCompletions.fn_get_config() | ConvertTo-Json | Out-File (Join-Path $PSCompletions.path.root 'env.json') $PSCompletions.init = $true } $PSCompletions | Add-Member -MemberType ScriptMethod fn_init { $PSCompletions.comp_cmd = [ordered]@{} $PSCompletions.config = $PSCompletions.fn_get_config() $PSCompletions.root_cmd = $PSCompletions.config.root_cmd if ($PSCompletions.config.language) { $PSCompletions.lang = $PSCompletions.config.language } if ($PSCompletions.config.github) { $PSCompletions.github = $PSCompletions.config.github.Replace('github.com', 'raw.githubusercontent.com') + '/main' } if ($PSCompletions.config.gitee) { $PSCompletions.gitee = $PSCompletions.config.gitee + '/raw/main' } function _do($i, $k) { if ($PSCompletions.config.$i) { return @($PSCompletions.$i, $PSCompletions.config.$i) } else { return @($PSCompletions.$k, $PSCompletions.config.$k) } } if ($PSCompletions.lang -eq 'zh-CN') { $info = _do 'gitee' 'github' $PSCompletions.url = $info[0] $PSCompletions.repo = $info[1] } else { $info = _do 'github' 'gitee' $PSCompletions.url = $info[0] $PSCompletions.repo = $info[1] $PSCompletions.lang = 'en-US' } $psc_alias_path = $PSCompletions.fn_join_path($PSCompletions.path.completions, 'PSCompletions', 'alias.txt') $psc_json_path = $PSCompletions.fn_join_path($PSCompletions.path.completions, 'PSCompletions', 'lang', ($PSCompletions.lang + '.json')) try { if (!(Test-Path $psc_json_path)) { $psc_temp = 'PSCompletions' + (New-Guid).Guid + '.json' $PSCompletions.wc = New-Object System.Net.WebClient $PSCompletions.wc.DownloadFile(($PSCompletions.url + '/completions/PSCompletions/lang/' + $PSCompletions.lang + '.json'), $psc_temp) $PSCompletions.json = ($PSCompletions.fn_get_raw_content($psc_temp) | ConvertFrom-Json -ErrorAction SilentlyContinue).PSCompletions_core_info $PSCompletions.fn_add_completion('PSCompletions') Remove-Item $psc_temp -Force -ErrorAction SilentlyContinue } if (!(Test-Path $PSCompletions.path.list)) { New-Item $PSCompletions.path.list > $null if (!($PSCompletions.fn_download_list())) { throw } } } catch { throw $PSCompletions.fn_replace($PSCompletions.json.init_err) } if (!(Test-Path $psc_alias_path)) { $PSCompletions.root_cmd | Out-File $psc_alias_path -Force -Encoding utf8 } $psc_alias = $PSCompletions.fn_get_raw_content($psc_alias_path) if ($psc_alias) { $psc_alias = $psc_alias.Trim() } if ($psc_alias -ne $PSCompletions.root_cmd) { $PSCompletions.fn_set_config('root_cmd', $psc_alias) $PSCompletions.root_cmd = $PSCompletions.config.root_cmd = $psc_alias } $PSCompletions.json = ($PSCompletions.fn_get_raw_content($psc_json_path) | ConvertFrom-Json).PSCompletions_core_info if (!(Test-Path $PSCompletions.path.update)) { New-Item $PSCompletions.path.update > $null } if (!(Test-Path $PSCompletions.path.old_list)) { Copy-Item $PSCompletions.path.list $PSCompletions.path.old_list -Force } $PSCompletions.list = $PSCompletions.fn_get_content($PSCompletions.path.list) $PSCompletions.update = $PSCompletions.fn_get_content($PSCompletions.path.update) $res = [System.Collections.Generic.List[string]]@() $PSCompletions.installed = Get-ChildItem -Path $PSCompletions.path.completions -Filter '*.ps1' -Recurse -Depth 1 | Sort-Object CreationTime $PSCompletions.installed | ForEach-Object { $cmd = Split-Path (Split-Path $_.FullName -Parent) -Leaf $PSCompletions.comp_cmd.$cmd = $cmd $res.Add($_.FullName) } Get-ChildItem -Path $PSCompletions.path.completions -Filter 'alias.txt' -Recurse -Depth 1 | ForEach-Object { $cmd = Split-Path (Split-Path $_.FullName -Parent) -Leaf $PSCompletions.comp_cmd.$cmd = $PSCompletions.fn_get_raw_content($_.FullName) } $load_err_list = [System.Collections.Generic.List[string]]@() foreach ($item in $res) { try { . $item }catch { $load_err_list.Add($item) } } if ($load_err_list) { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.import_error)) } } $PSCompletions.fn_init() if ($PSHOME -notlike "*WindowsPowerShell*" -and $PSVersionTable.Platform -ne 'Unix') { $PSCompletions.ui = [ordered]@{} . $PSScriptRoot\ui\ui.ps1 } $PSCompletions.comp_cmd.keys | Where-Object { $PSCompletions.comp_cmd.$_ -ne $_ } | ForEach-Object { Set-Alias $PSCompletions.comp_cmd.$_ $_ } if (!$PSCompletions.config.github -and !$PSCompletions.config.gitee) { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.repo_err)) } #region init and update if ($PSCompletions.init) { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.init_info)) } if (!($PSCompletions.config.update -in @('1', '0')) -and $PSCompletions.config.module_update -eq 1) { $null = $PSCompletions.fn_confirm($PSCompletions.json.module_update, { try { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.module_updating)) try { Update-Module PSCompletions -ErrorAction Stop } catch { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.module_update_admin)) & "$($PSCompletions.path.core)\utils\sudo.ps1" Update-Module PSCompletions -ErrorAction Stop } if ($PSCompletions.config.update -in (Get-ChildItem (Split-Path $PSCompletions.path.root -Parent)).BaseName) { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.module_update_done)) } else { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.module_update_err)) } } catch { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.module_update_err)) } }) } if ($PSCompletions.config.update -ne 0) { if ($PSCompletions.update -or $PSCompletions.fn_get_content((Join-Path $PSCompletions.path.core '.add'))) { $PSCompletions.fn_write($PSCompletions.fn_replace($PSCompletions.json.update_info)) } } #endregion $PSCompletions.jobs = Start-Job -ScriptBlock { param( $PSCompletions, $path_history ) function get_content([string]$path) { return (Get-Content $path -Encoding utf8 -ErrorAction SilentlyContinue | Where-Object { $_ -ne '' }) } function get_raw_content([string]$path, [bool]$trim = $true) { $res = Get-Content $path -Raw -Encoding utf8 -ErrorAction SilentlyContinue if ($trim -and $res) { return $res.Trim() } return $res } function get_order { param ( [string]$PSScriptRoots, [array]$exclude = @(), [string]$file = 'order.json' ) $path_order = Join-Path $PSScriptRoots $file if (!(Test-Path $path_order)) { $json = get_raw_content ($PSScriptRoots + '/lang/' + $PSCompletions.lang + '.json') | ConvertFrom-Json $i = 1 $res = [ordered]@{} $json.PSObject.Properties.Name | Where-Object { $_ -notin $exclude } | ForEach-Object { $res.$_ = $i $i++ } $res | ConvertTo-Json | Out-File $path_order -Force } return (get_raw_content $path_order | ConvertFrom-Json) } $alias_list = $PSCompletions.comp_cmd.Keys | ForEach-Object { $PSCompletions.comp_cmd.$_ } $history = [System.Collections.Generic.List[string]]@() [array](get_content $path_history) | ForEach-Object { $cmd = ($_ -split '\s+')[0] if ($cmd -in $alias_list) { if ($cmd -in $history) { $null = $history.Remove($cmd) } $null = $history.Add($cmd) } } $cache = @() $history | ForEach-Object { if ($_ -notin $cache) { $cache += $_ } } $cmd_list = @{} $PSCompletions.comp_cmd.Keys | ForEach-Object { $alias = $PSCompletions.comp_cmd.$_ $cmd_list.$alias = $_ } $cache[ - ([int]$PSCompletions.config.LRU)..-1] | ForEach-Object { $cmd_list.$_ } | ForEach-Object { $alias = $PSCompletions.comp_cmd.$_ $PSCompletions.comp_data.$alias = @{} if ($PSCompletions.comp_config.$_.language) { $lang = $PSCompletions.comp_config.$_.language } else { $lang = $PSCompletions.lang } $json = get_raw_content "$($PSCompletions.path.completions)/$($_)/lang/$($lang).json" | ConvertFrom-Json $info = $_ + '_core_info' $PSCompletions.comp_data.$($alias + '_info') = @{ core_info = $json.$info exclude = @($info) num = -1 } $common_options = $json.$info.common_options $order = get_order ($PSCompletions.path.completions + '/' + $_) $PSCompletions.comp_data.$($alias + '_info').exclude $_i = 1 $__i = 999999 $json.PSObject.Properties.Name | Where-Object { $_ -notin $PSCompletions.comp_data.$($alias + '_info').exclude } | ForEach-Object { $cmd = $_ -split ' ' $_o = if ($order.$_) { $order.$_ }else { $_i } $PSCompletions.comp_data.$alias[$alias + ' ' + $_] = @($cmd[-1], $json.$_, $_o) $_i++ if ($common_options) { foreach ($item in $common_options.PSObject.Properties.Name) { $PSCompletions.comp_data.$alias[$alias + ' ' + $_ + ' ' + $item] = @($item, $common_options.$item, $__i) $__i ++ } } } if ($common_options) { foreach ($item in $common_options.PSObject.Properties.Name) { $PSCompletions.comp_data.$alias[$alias + ' ' + $item] = @($item, $common_options.$item, $__i) $__i++ } } } return $PSCompletions.comp_data } -ArgumentList $PSCompletions, (Get-PSReadLineOption).HistorySavePath $null = Start-Job -ScriptBlock { param( $PSCompletions ) function _do($do) { try { & $do }catch {} } function get_content([string]$path) { $res = Get-Content $path -Encoding utf8 -ErrorAction SilentlyContinue | Where-Object { $_ -ne '' } if ($res) { return $res } return $null } function get_raw_content([string]$path, [bool]$trim = $true) { $res = Get-Content $path -Raw -Encoding utf8 -ErrorAction SilentlyContinue if ($trim -and $res) { $res = $res.Trim() } if ($res) { return $res } return $null } function _replace([array]$data) { $data = $data -join '' $pattern = '\{\{(.*?(\})*)(?=\}\})\}\}' $matches = [regex]::Matches($data, $pattern) foreach ($match in $matches) { $data = $data.Replace($match.Value, (Invoke-Expression $match.Groups[1].Value)) } if ($data -match $pattern) { _replace $data }else { return $data } } function download_list() { try { if ($PSCompletions.url) { $res = Invoke-WebRequest -Uri ($PSCompletions.url + '/list.txt') if ($res.StatusCode -eq 200) { $content = $res.Content -split "`n" | Where-Object { $_ -ne '' } $old_list = get_content $PSCompletions.path.old_list $list = get_content $PSCompletions.path.old_list if (!$content) { $content = "" } if (!$old_list) { $old_list = "" } if (!$list) { $list = "" } if (Compare-Object $list $old_list -PassThru) { Copy-Item $PSCompletions.path.list $PSCompletions.path.old_list -Force } if (Compare-Object $content $list -PassThru) { $content | Out-File $PSCompletions.path.list -Force -Encoding utf8 $PSCompletions.list = $PSCompletions.fn_get_content($PSCompletions.path.list) } return $content } } else { return $false } } catch { return $false } } function get_config() { $c = get_raw_content "$($PSCompletions.path.root)/env.json" | ConvertFrom-Json $config = [ordered]@{} $default = [ordered]@{ root_cmd = 'psc' github = 'https://github.com/abgox/PSCompletions' gitee = 'https://gitee.com/abgox/PSCompletions' language = $PSCompletions.lang update = 1 LRU = 5 run_with_admin = 1 module_update = 1 sym = [char]::ConvertFromUtf32(128516) sym_wr = [char]::ConvertFromUtf32(128526) sym_opt = [char]::ConvertFromUtf32(129300) } $need_set = $false foreach ($key in $default.Keys) { if ($key -notin $c.PSObject.Properties.Name) { $need_set = $true $config.$key = $default[$key] } else { $config.$key = $c.$key } } if ($need_set) { $config | ConvertTo-Json | Out-File "$($PSCompletions.path.root)/env.json" } if ($config.update -eq $PSCompletions.version) { $config.update = 1 } return $config } function set_config([string]$k, [string]$v) { $c = get_config $c.$k = $v $c | ConvertTo-Json | Out-File "$($PSCompletions.path.root)/env.json" } _do { $response = Invoke-WebRequest -Uri ($PSCompletions.url + '/module/.version') if ($response.StatusCode -eq 200) { $content = $response.Content.Trim() $versions = @($PSCompletions.version, $content) | Sort-Object { [Version] $_ } if ($versions[-1] -ne $PSCompletions.version) { $PSCompletions.wc = New-Object System.Net.WebClient $log_url = $PSCompletions.url + '/module/log.json' $log_file = $PSCompletions.path.core + '/log.json' $PSCompletions.wc.DownloadFile($log_url, $log_file) if (Test-Path $log_file) { set_config 'update' $versions[-1] } } } } $old_list = get_content $PSCompletions.path.old_list $new_list = get_content $PSCompletions.path.list $diff = Compare-Object $new_list $old_list -PassThru if ($diff) { $diff | Out-File ($PSCompletions.path.core + '/.add') -Force -Encoding utf8 $new_list | Out-File $PSCompletions.path.old_list -Force } else { Clear-Content ($PSCompletions.path.core + '/.add') -Force } download_list $update_list = [System.Collections.Generic.List[string]]@() $installed = (Get-ChildItem -Path $PSCompletions.path.completions -Filter '*.ps1' -Recurse -Depth 1).BaseName | Where-Object { $_ -in $PSCompletions.list } _do { $installed | ForEach-Object { $url = $PSCompletions.url + '/completions/' + $_ + '/guid.txt' $response = Invoke-WebRequest -Uri $url if ($response.StatusCode -eq 200) { $content = $response.Content.Trim() $guid = get_raw_content ($PSCompletions.path.completions + '/' + $_ + '/guid.txt') $true if ($guid -ne $content) { $update_list.Add($_) } } } } $old_update_list = get_content $PSCompletions.path.update if ($update_list) { if ($old_update_list) { $is_write = Compare-Object $update_list $old_update_list -PassThru } else { $is_write = $true } } if ($is_write) { $update_list | Out-File $PSCompletions.path.update -Force -Encoding utf8 } } -ArgumentList $PSCompletions |