diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..0091f76 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,15 @@ +# List of whitespace-only commits to ignore in the Git blame; +# to improve tracking changes and avoid noise +58db4e3419bf1e5cc1bb61fcd7ce2ebbca89243a +efb3338f5cf0eec21e8a75abc62ee14965cb4a7e +3859f6ffc088b2ae78748abc84986f4adcadcd41 +d6569192fc91167f555c3eff58402ff01f1197ea +67de97a492c9389f95499db38f9474a1c20ec585 +a0d085f93eaa69c22449d0217e8daf9eaea2b180 +1cfba25beb46c74bb1debca2bcfe7ac470e96172 +f6bc623284914489e891bbac923feb774c862b99 +abbab3f8b477e917d0a175d0de23cce121096631 +126347025f9cade241beff182738b2527da7535e +4740b836f300658b27e6ad4d79efac63c9c24c24 +be44bac95670b1cbbc91bd657882d985989846f9 +f67e5704eda60526d495be758572181f01a6cac8 diff --git a/.github/workflows/branches.yml b/.github/workflows/branches.yml index 333242b..d76c3a3 100644 --- a/.github/workflows/branches.yml +++ b/.github/workflows/branches.yml @@ -19,7 +19,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 # fetch all history for all branches and tags diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8fb9368..c75704f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: discussions: write steps: - name: Check out repository code (Action from GitHub) - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 @@ -53,66 +53,66 @@ jobs: run: .\pack.ps1 -verbose -terminal all - name: Upload artifact (cmder_win_mini.zip) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_win_mini.zip name: cmder_win_mini.zip if-no-files-found: error - name: Upload artifact (cmder_win.7z) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_win.7z name: cmder_win.7z if-no-files-found: error - name: Upload artifact (cmder_win.zip) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_win.zip name: cmder_win.zip if-no-files-found: error - name: Upload artifact (cmder_wt.zip) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_wt.zip name: cmder_wt.zip if-no-files-found: error - name: Upload artifact (cmder_wt.7z) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_wt.7z name: cmder_wt.7z - name: Upload artifact (cmder_wt_mini.zip) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/cmder_wt_mini.zip name: cmder_wt_mini.zip - name: Upload artifact (cmder.zip) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: path: build/cmder.zip name: cmder.zip if-no-files-found: error - name: Upload artifact (cmder.7z) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: path: build/cmder.7z name: cmder.7z - name: Upload artifact (cmder_mini.zip) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: path: build/cmder_mini.zip name: cmder_mini.zip - name: Upload artifact (hashes.txt) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: path: build/hashes.txt name: hashes.txt diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8e9f4b5..87ee1b5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,11 +45,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,6 +68,6 @@ jobs: run: .\build.ps1 -Compile -verbose - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8d9ecec..0334e86 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: continue-on-error: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Initialize vendors shell: pwsh working-directory: scripts @@ -48,7 +48,7 @@ jobs: cmd /c vendor\init.bat /v /d /t - name: Testing PowerShell run: | - PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NoProfile -Command "Invoke-Expression '. ''vendor\profile.ps1'''" + PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NoProfile -Command "$env:CMDER_DEBUG='1'; . 'vendor\profile.ps1'" - name: Testing Bash run: | bash vendor/cmder.sh diff --git a/.github/workflows/vendor.yml b/.github/workflows/vendor.yml index f237626..62ccbcb 100644 --- a/.github/workflows/vendor.yml +++ b/.github/workflows/vendor.yml @@ -24,7 +24,7 @@ jobs: pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 @@ -51,7 +51,7 @@ jobs: Set-GHVariable -Name LIST_UPDATED -Value $listUpdated.Trim(', ') echo "UPDATE_MESSAGE<< 0 with: title: 'Updates to `${{ env.COUNT_UPDATED }}` vendored dependencies' diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b22a19..9919a47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## Unreleased + +### Fixes + +- Fixes #2940 + +### Adds + +- Cmder for Windows + - Uses Windows and Git for Windows Native Terminals. + - Does not contain a terminal emulator like ConEmu or Windows Terminal. + ## [1.3.20](https://github.com/cmderdev/cmder/tree/v1.3.20) (2022-03-18) ### Changes diff --git a/README.md b/README.md index cda18e9..7b8364a 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,10 @@ Cmder by default comes with a vendored ConEmu installation as the underlying ter However, Cmder can in fact run in a variety of other terminal emulators, and even integrated IDEs. Assuming you have the latest version of Cmder, follow the following instructions to get Cmder working with your own terminal emulator. +⚠ *Note:* Cmder includes built-in support for Windows Terminal directory tracking via OSC 9;9 sequences. This enables "Duplicate Tab" and "Split Pane" features to preserve the current working directory for both `cmd.exe` and PowerShell sessions. + +⚠ *Note:* Cmder also includes built-in support for [Windows Terminal shell integration](https://learn.microsoft.com/en-us/windows/terminal/tutorials/shell-integration) via OSC 133 sequences (A, B, C, D) for PowerShell sessions. This enables features like command navigation (jump between commands), command selection, visual command separators, command exit code tracking, and improved command history management in Windows Terminal. + For instructions on how to integrate Cmder with your IDE, please read our [Wiki section](https://github.com/cmderdev/cmder/wiki#cmder-integration). ## Upgrading diff --git a/launcher/CmderLauncher.vcxproj b/launcher/CmderLauncher.vcxproj index 2662957..6d49ed9 100644 --- a/launcher/CmderLauncher.vcxproj +++ b/launcher/CmderLauncher.vcxproj @@ -188,6 +188,9 @@ + + + diff --git a/launcher/src/CmderLauncher.cpp b/launcher/src/CmderLauncher.cpp index ea753d1..62383f8 100644 --- a/launcher/src/CmderLauncher.cpp +++ b/launcher/src/CmderLauncher.cpp @@ -105,11 +105,11 @@ bool FileExists(const wchar_t * filePath) return false; } -void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstring taskName = L"", std::wstring title = L"", std::wstring iconPath = L"", std::wstring cfgRoot = L"", bool use_user_cfg = true, std::wstring conemu_args = L"", bool admin = false) +void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstring taskName = L"", std::wstring title = L"", std::wstring iconPath = L"", std::wstring cfgRoot = L"", bool use_user_cfg = true, std::wstring conemu_args = L"") { -#if USE_TASKBAR_API - wchar_t appId[MAX_PATH] = { 0 }; -#endif + #if USE_TASKBAR_API + wchar_t appId[MAX_PATH] = { 0 }; + #endif wchar_t exeDir[MAX_PATH] = { 0 }; wchar_t icoPath[MAX_PATH] = { 0 }; wchar_t cfgPath[MAX_PATH] = { 0 }; @@ -153,9 +153,9 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr GetModuleFileName(NULL, exeDir, sizeof(exeDir)); -#if USE_TASKBAR_API - wcscpy_s(appId, exeDir); -#endif + #if USE_TASKBAR_API + wcscpy_s(appId, exeDir); + #endif PathRemoveFileSpec(exeDir); @@ -312,7 +312,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) ? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_terminal_%COMPUTERNAME%_settings.json! Access Denied." - : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_teerminal_%COMPUTERNAME%_settigns.json!", MB_TITLE, MB_ICONSTOP); + : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_terminal_%COMPUTERNAME%_settigns.json!", MB_TITLE, MB_ICONSTOP); exit(1); } else if (PathFileExists(conEmuDir)) @@ -329,7 +329,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr { if (!CopyFile(cpuCfgPath, cfgPath, FALSE)) { - if (PathFileExists(windowsTerminalDir)) { + if (PathFileExists(windowsTerminalDir)) { MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) ? L"Failed to copy config/windows_terminal_%COMPUTERNAME%_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied." @@ -360,7 +360,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) ? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_terminal_settings.json! Access Denied." - : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_teerminal_settigns.json!", MB_TITLE, MB_ICONSTOP); + : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_terminal_settigns.json!", MB_TITLE, MB_ICONSTOP); exit(1); } else if (PathFileExists(conEmuDir)) @@ -645,44 +645,13 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr STARTUPINFO si = { 0 }; si.cb = sizeof(STARTUPINFO); -#if USE_TASKBAR_API - si.lpTitle = appId; - si.dwFlags = STARTF_TITLEISAPPID; -#endif + #if USE_TASKBAR_API + si.lpTitle = appId; + si.dwFlags = STARTF_TITLEISAPPID; + #endif PROCESS_INFORMATION pi; - // MessageBox(NULL, terminalPath, _T("Error"), MB_OK); - // MessageBox(NULL, args, _T("Error"), MB_OK); - // Let's try to rerun as Administrator - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS; - sei.lpVerb = L"runas"; - sei.lpFile = terminalPath; - sei.lpParameters = args; - sei.nShow = SW_SHOWNORMAL; - - if (admin && ShellExecuteEx(&sei)) - { - if (!sei.hProcess) - { - Sleep(500); - _ASSERTE(sei.hProcess != nullptr); - } - - if (sei.hProcess) - { - WaitForSingleObject(sei.hProcess, INFINITE); - } - - // int nZone = 0; - // if (!HasZoneIdentifier(lsFile, nZone) - // || (nZone != 0 /*LocalComputer*/)) - // { - // // Assuming that elevated copy has fixed all zone problems - // break; - // } - } - else if (!CreateProcess(terminalPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) + if (!CreateProcess(terminalPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) { if (PathFileExists(windowsTerminalDir)) { @@ -813,7 +782,6 @@ struct cmderOptions std::wstring cmderIcon = L""; std::wstring cmderRegScope = L"USER"; std::wstring cmderTerminalArgs = L""; - bool cmderAdmin = false; bool cmderSingle = false; bool cmderUserCfg = true; bool registerApp = false; @@ -902,10 +870,6 @@ cmderOptions GetOption() { cmderOptions.cmderUserCfg = false; } - else if (_wcsicmp(L"/a", szArgList[i]) == 0 && !PathFileExists(windowsTerminalDir) && !PathFileExists(conEmuDir)) - { - cmderOptions.cmderAdmin = true; - } else if (_wcsicmp(L"/register", szArgList[i]) == 0) { cmderOptions.registerApp = true; @@ -1042,7 +1006,8 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, } else { - StartCmder(cmderOptions.cmderStart, cmderOptions.cmderSingle, cmderOptions.cmderTask, cmderOptions.cmderTitle, cmderOptions.cmderIcon, cmderOptions.cmderCfgRoot, cmderOptions.cmderUserCfg, cmderOptions.cmderTerminalArgs, cmderOptions.cmderAdmin); } + StartCmder(cmderOptions.cmderStart, cmderOptions.cmderSingle, cmderOptions.cmderTask, cmderOptions.cmderTitle, cmderOptions.cmderIcon, cmderOptions.cmderCfgRoot, cmderOptions.cmderUserCfg, cmderOptions.cmderTerminalArgs); + } return 0; } diff --git a/launcher/src/resource.rc b/launcher/src/resource.rc index 5960625..8602089 100644 --- a/launcher/src/resource.rc +++ b/launcher/src/resource.rc @@ -35,19 +35,19 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 1 TEXTINCLUDE BEGIN -"resource.h\0" + "resource.h\0" END 2 TEXTINCLUDE BEGIN -"#include ""winres.h""\r\n" -"\0" + "#include ""winres.h""\r\n" + "\0" END 3 TEXTINCLUDE BEGIN -"\r\n" -"\0" + "\r\n" + "\0" END #endif // APSTUDIO_INVOKED @@ -60,7 +60,7 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_CMDER ICON "..\\..\\icons\\cmder.ico" -#endif // English (United States) resources +#endif // not APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// diff --git a/launcher/src/strings.rc2 b/launcher/src/strings.rc2 index 494cbfe..d8feb4d 100644 --- a/launcher/src/strings.rc2 +++ b/launcher/src/strings.rc2 @@ -6,7 +6,7 @@ STRINGTABLE { IDS_TITLE "Cmder Launcher" - IDS_SWITCHES L"Valid options:\n\n /a Admin - Native Terminals ONLY!\n /c [CMDER User Root Path]\n /task [Windows Terminal Profile/ConEmu Task Name]\n /icon [CMDER Icon Path] - ConEmu ONLY!\n [/start [Start in Path] | [Start in Path]]\n /single - ConEmu ONLY!\n /m\n -- [ConEmu/Windows Terminal extra arguments]\n\nNote: '-- [...]' must be the last argument!\n\nor, either:\n /register [USER | ALL]\n /unregister [USER | ALL]" + IDS_SWITCHES L"Valid options:\n\n /c [CMDER User Root Path]\n /task [Windows Terminal Profile/ConEmu Task Name]\n /icon [CMDER Icon Path] - ConEmu ONLY!\n [/start [Start in Path] | [Start in Path]]\n /single - ConEmu ONLY!\n /m\n -- [ConEmu/Windows Terminal extra arguments]\n\nNote: '-- [...]' must be the last argument!\n\nor, either:\n /register [USER | ALL]\n /unregister [USER | ALL]" } ///////////////////////////////////////////////////////////////////////////// diff --git a/scripts/build.ps1 b/scripts/build.ps1 index f577fa1..634d246 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -27,7 +27,7 @@ .EXAMPLE .\build.ps1 -SourcesPath '~/custom/vendors.json' - Build cmder with your own packages. See vendor/sources.json for the syntax you need to copy. + Build Cmder with your own packages. See vendor/sources.json for the syntax you need to copy. .NOTES AUTHORS Samuel Vasko, Jack Bennett @@ -55,7 +55,7 @@ Param( # Using this option will skip all downloads, if you only need to build launcher [switch]$noVendor, - + # Using this option will specify the emulator to use [none, all, conemu-maximus5, or windows-terminal] [string]$terminal = 'all', @@ -129,8 +129,9 @@ if (-not $noVendor) { else { $WinTermSettingsJson = "" } # Kill ssh-agent.exe if it is running from the $env:cmder_root we are building + $cmder_folder = $cmder_root.toString() foreach ($ssh_agent in $(Get-Process ssh-agent -ErrorAction SilentlyContinue)) { - if ([string]$($ssh_agent.path) -Match [string]$cmder_root.replace('\', '\\')) { + if ([string]$($ssh_agent.path) -Match $cmder_folder.Replace('\', '\\')) { Write-Verbose $("Stopping " + $ssh_agent.path + "!") Stop-Process $ssh_agent.id } @@ -138,13 +139,13 @@ if (-not $noVendor) { foreach ($s in $sources) { if ($terminal -eq "none") { - return + continue } elseif ($s.name -eq "conemu-maximus5" -and $terminal -eq "windows-terminal") { - return + continue } elseif ($s.name -eq "windows-terminal" -and $terminal -eq "conemu-maximus5") { - return + continue } - + Write-Verbose "Getting vendored $($s.name) $($s.version)..." # We do not care about the extensions/type of archive @@ -157,12 +158,12 @@ if (-not $noVendor) { # Make Embedded Windows Terminal Portable if ($s.name -eq "windows-terminal") { - $windowTerminalFiles = resolve-path ($saveTo + "\" + $s.name + "\terminal*") - move-item -ErrorAction SilentlyContinue $windowTerminalFiles\* $s.name >$null - remove-item -ErrorAction SilentlyContinue $windowTerminalFiles >$null - write-verbose "Making Windows Terminal Portable..." - New-Item -Type Directory -Path (Join-Path $saveTo "/windows-terminal/settings") -ErrorAction SilentlyContinue >$null - New-Item -Type File -Path (Join-Path $saveTo "/windows-terminal/.portable") -ErrorAction SilentlyContinue >$null + $windowTerminalFiles = resolve-path ($saveTo + "\" + $s.name + "\terminal*") + Move-Item -ErrorAction SilentlyContinue $windowTerminalFiles\* $s.name >$null + Remove-Item -ErrorAction SilentlyContinue $windowTerminalFiles >$null + Write-Verbose "Making Windows Terminal Portable..." + New-Item -Type Directory -Path (Join-Path $saveTo "/windows-terminal/settings") -ErrorAction SilentlyContinue >$null + New-Item -Type File -Path (Join-Path $saveTo "/windows-terminal/.portable") -ErrorAction SilentlyContinue >$null } if ((Get-ChildItem $s.name).Count -eq 1) { diff --git a/scripts/pack.ps1 b/scripts/pack.ps1 index a96ea04..00e8625 100644 --- a/scripts/pack.ps1 +++ b/scripts/pack.ps1 @@ -2,18 +2,18 @@ .Synopsis Pack Cmder .DESCRIPTION - Use this script to pack cmder into release archives + Use this script to pack Cmder into release archives You will need to make this script executable by setting your Powershell Execution Policy to Remote signed Then unblock the script for execution with UnblockFile .\pack.ps1 .EXAMPLE .\pack.ps1 - Creates default archives for cmder + Creates default archives for Cmder .EXAMPLE .\pack.ps1 -verbose - Creates default archives for cmder with plenty of information + Creates default archives for Cmder with plenty of information .NOTES AUTHORS Samuel Vasko, Jack Bennett, Martin Kemp diff --git a/scripts/update.ps1 b/scripts/update.ps1 index 768744a..c6b982d 100644 --- a/scripts/update.ps1 +++ b/scripts/update.ps1 @@ -32,7 +32,11 @@ Param( # -whatif switch to not actually make changes # Path to the vendor configuration source file - [string]$sourcesPath = "$PSScriptRoot\..\vendor\sources.json" + [string]$sourcesPath = "$PSScriptRoot\..\vendor\sources.json", + + # Include pre-release versions (RC, beta, alpha, etc.) + # By default, only stable releases are considered + [switch]$IncludePrerelease = $false ) # Get the root directory of the cmder project. @@ -79,11 +83,39 @@ function Match-Filenames { return $position } +# Checks if a release is a pre-release based on GitHub API flag and version tag keywords +# Pre-release keywords include: -rc (release candidate), -beta, -alpha, -preview, -pre +function Test-IsPrerelease { + param ( + [Parameter(Mandatory = $true)] + $release + ) + + # Check if marked as pre-release by GitHub + if ($release.prerelease -eq $true) { + return $true + } + + # Check for common pre-release keywords in tag name + # This catches versions like v2.50.0-rc, v1.0.0-beta, v1.0.0-alpha, etc. + $prereleaseKeywords = @('-rc', '-beta', '-alpha', '-preview', '-pre') + foreach ($keyword in $prereleaseKeywords) { + if ($release.tag_name -ilike "*$keyword*") { + return $true + } + } + + return $false +} + # Uses the GitHub api in order to fetch the current download links for the latest releases of the repo. function Fetch-DownloadUrl { param ( [Parameter(Mandatory = $true)] - $urlStr + $urlStr, + + [Parameter(Mandatory = $false)] + [bool]$includePrerelease = $false ) $url = [uri] $urlStr @@ -127,6 +159,13 @@ function Fetch-DownloadUrl { } :loop foreach ($i in $info) { + # Skip pre-release versions unless explicitly included + # Pre-releases include RC (Release Candidate), beta, alpha, and other test versions + if (-not $includePrerelease -and (Test-IsPrerelease $i)) { + Write-Verbose "Skipping pre-release version: $($i.tag_name)" + continue + } + if (-not ($i.assets -is [array])) { continue } @@ -164,12 +203,26 @@ function Fetch-DownloadUrl { # Special case for archive downloads of repository if (($null -eq $downloadLinks) -or (-not $downloadLinks)) { - if ((($p | ForEach-Object { $_.Trim('/') }) -contains "archive") -and $info[0].tag_name) { - for ($i = 0; $i -lt $p.Length; $i++) { - if ($p[$i].Trim('/') -eq "archive") { - $p[$i + 1] = $info[0].tag_name + ".zip" - $downloadLinks = $url.Scheme + "://" + $url.Host + ($p -join '') - return $downloadLinks + if ((($p | ForEach-Object { $_.Trim('/') }) -contains "archive")) { + # Find the first release that matches our pre-release filtering criteria + $selectedRelease = $null + foreach ($release in $info) { + # Apply the same filtering logic + if (-not $includePrerelease -and (Test-IsPrerelease $release)) { + continue + } + # Use the first release that passes the filter + $selectedRelease = $release + break + } + + if ($selectedRelease -and $selectedRelease.tag_name) { + for ($i = 0; $i -lt $p.Length; $i++) { + if ($p[$i].Trim('/') -eq "archive") { + $p[$i + 1] = $selectedRelease.tag_name + ".zip" + $downloadLinks = $url.Scheme + "://" + $url.Host + ($p -join '') + return $downloadLinks + } } } } @@ -215,7 +268,7 @@ foreach ($s in $sources) { Write-Verbose "Old Link: $($s.url)" - $downloadUrl = Fetch-DownloadUrl $s.url + $downloadUrl = Fetch-DownloadUrl $s.url -includePrerelease $IncludePrerelease if (($null -eq $downloadUrl) -or ($downloadUrl -eq '')) { Write-Verbose "No new links were found" diff --git a/scripts/utils.ps1 b/scripts/utils.ps1 index 2b81a70..5895540 100644 --- a/scripts/utils.ps1 +++ b/scripts/utils.ps1 @@ -172,13 +172,13 @@ function Register-Cmder() { # Text for the context menu item. $MenuText = "Cmder Here" - , # Defaults to the current cmder directory when run from cmder. + , # Defaults to the current Cmder directory when run from Cmder. $PathToExe = (Join-Path $env:CMDER_ROOT "cmder.exe") , # Commands the context menu will execute. $Command = "%V" - , # Defaults to the icons folder in the cmder package. + , # Defaults to the icons folder in the Cmder package. $icon = (Split-Path $PathToExe | Join-Path -ChildPath 'icons/cmder.ico') ) Begin diff --git a/vendor/bin/create-cmdercfg.cmd b/vendor/bin/create-cmdercfg.cmd new file mode 100644 index 0000000..cc8c711 --- /dev/null +++ b/vendor/bin/create-cmdercfg.cmd @@ -0,0 +1,3 @@ +@echo off + +powershell -executionpolicy bypass -f "%cmder_root%\vendor\bin\create-cmdercfg.ps1" -shell cmd -outfile "%CMDER_CONFIG_DIR%\user_init.cmd" diff --git a/vendor/clink.lua b/vendor/clink.lua index 8e8365c..4e4e205 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -7,7 +7,7 @@ -- luacheck: globals uah_color cwd_color lamb_color clean_color dirty_color conflict_color unknown_color -- luacheck: globals prompt_homeSymbol prompt_lambSymbol prompt_type prompt_useHomeSymbol prompt_useUserAtHost -- luacheck: globals prompt_singleLine prompt_includeVersionControl --- luacheck: globals prompt_overrideGitStatusOptIn prompt_overrideSvnStatusOptIn +-- luacheck: globals prompt_overrideGitStatusOptIn -- luacheck: globals clink io.popenyield os.isdir settings.get -- At first, load the original clink.lua file @@ -350,13 +350,8 @@ end -- @return {false|mercurial branch information} --- local function get_hg_branch() - -- Return the branch information. The default is to get just the - -- branch name, but you could e.g. use the "hg-prompt" extension to - -- get more information, such as any applied mq patches. Here's an - -- example of that: - -- local cmd = "hg prompt \"{branch}{status}{|{patch}}{update}\"" - local cmd = "hg branch 2>nul" - local file = io.popen(cmd) + -- Return the branch information. + local file = io.popen("hg branch 2>nul") if not file then return false end @@ -424,12 +419,33 @@ local function get_git_status() return { status = is_status, conflict = conflict_found } end +--- +-- Get the status of working dir +-- @return {bool} +--- +local function get_hg_status() + -- The default is to just use the branch name, but you could e.g. use the + -- "hg-prompt" extension to get more information, such as any applied mq + -- patches. Here's an example of that: + -- "hg prompt \"{branch}{status}{|{patch}}{update}\"" + local pipe = io_popenyield("hg status -amrd 2>&1") + if not pipe then + return { error = true } + end + + local output = pipe:read('*all') + pipe:close() + + local dirty = (output ~= nil and output ~= "") + return { clean = not dirty } +end + --- -- Get the status of working dir -- @return {bool} --- local function get_svn_status() - local file = io_popenyield("svn status -q") + local file = io_popenyield("svn status -q 2>nul") if not file then return { error = true } end @@ -520,14 +536,6 @@ local function git_prompt_filter() return false end - -- Colors for git status - local colors = { - clean = get_clean_color(), - dirty = get_dirty_color(), - conflict = get_conflict_color(), - nostatus = get_unknown_color() - } - local git_dir = get_git_dir() local color if git_dir then @@ -547,18 +555,19 @@ local function git_prompt_filter() local gitConflict = gitInfo.conflict if gitStatus == nil then - color = colors.nostatus + color = get_unknown_color() elseif gitStatus then - color = colors.clean + color = get_clean_color() else - color = colors.dirty + color = get_dirty_color() end if gitConflict then - color = colors.conflict + color = get_conflict_color() end - clink.prompt.value = gsub_plain(clink.prompt.value, "{git}", " "..color.."("..branch..")") + local result = " "..color.."("..branch..")" + clink.prompt.value = gsub_plain(clink.prompt.value, "{git}", result) return false end end @@ -568,6 +577,18 @@ local function git_prompt_filter() return false end +local function get_hg_info_table() + local info = clink_promptcoroutine(function () + return get_hg_status() or {} + end) + if not info then + info = cached_info.hg_info or {} + else + cached_info.hg_info = info + end + return info +end + local function hg_prompt_filter() -- Don't do any hg processing if the prompt doesn't want to show hg info. @@ -577,33 +598,30 @@ local function hg_prompt_filter() local hg_dir = get_hg_dir() if hg_dir then - -- Colors for mercurial status - local colors = { - clean = get_clean_color(), - dirty = get_dirty_color(), - nostatus = get_unknown_color() - } - local output = get_hg_branch() - - -- strip the trailing newline from the branch name - local n = #output - while n > 0 and output:find("^%s", n) do n = n - 1 end - local branch = output:sub(1, n) - - if branch ~= nil and + local branch = get_hg_branch() + if branch and string.sub(branch,1,7) ~= "abort: " and -- not an HG working copy (not string.find(branch, "is not recognized")) then -- 'hg' not in path - local color = colors.clean - - local pipe = io.popen("hg status -amrd 2>&1") - if pipe then - output = pipe:read('*all') - pipe:close() - if output ~= nil and output ~= "" then color = colors.dirty end + -- If in a different repo or branch than last time, discard cached info + if cached_info.hg_dir ~= hg_dir or cached_info.hg_branch ~= branch then + cached_info.hg_info = nil + cached_info.hg_dir = hg_dir + cached_info.hg_branch = branch end - local result = color .. "(" .. branch .. ")" - clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", " "..result) + local hgInfo = get_hg_info_table() + + local color + if not hgInfo or hgInfo.error then + color = get_unknown_color() + elseif hgInfo.clean then + color = get_clean_color() + else + color = get_dirty_color() + end + + local result = " "..color.."("..branch..")" + clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", result) return false end end @@ -612,6 +630,18 @@ local function hg_prompt_filter() clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", "") end +local function get_svn_info_table() + local info = clink_promptcoroutine(function () + return get_svn_status() or {} + end) + if not info then + info = cached_info.svn_info or {} + else + cached_info.svn_info = info + end + return info +end + local function svn_prompt_filter() -- Don't do any svn processing if the prompt doesn't want to show svn info. @@ -619,13 +649,6 @@ local function svn_prompt_filter() return false end - -- Colors for svn status - local colors = { - clean = get_clean_color(), - dirty = get_dirty_color(), - nostatus = get_unknown_color() - } - local svn_dir = get_svn_dir() if svn_dir then -- if we're inside of svn repo then try to detect current branch @@ -637,29 +660,16 @@ local function svn_prompt_filter() cached_info.svn_dir = svn_dir cached_info.svn_branch = branch end - -- Get the svn status using coroutine if available and option is enabled. Otherwise use a blocking call - local svnStatus - if clink.promptcoroutine and io.popenyield and settings.get("prompt.async") and prompt_overrideSvnStatusOptIn then -- luacheck: no max line length - svnStatus = clink_promptcoroutine(function () - return get_svn_status() - end) - -- If the status result is pending, use the cached version instead, otherwise store it to the cache - if svnStatus == nil then - svnStatus = cached_info.svn_info - else - cached_info.svn_info = svnStatus - end - else - svnStatus = get_svn_status() - end + + local svnInfo = get_svn_info_table() local color - if not svnStatus or svnStatus.error then - color = colors.nostatus - elseif svnStatus.clean then - color = colors.clean + if not svnInfo or svnInfo.error then + color = get_unknown_color() + elseif svnInfo.clean then + color = get_clean_color() else - color = colors.dirty + color = get_dirty_color() end clink.prompt.value = gsub_plain(clink.prompt.value, "{svn}", " "..color.."("..branch..")") diff --git a/vendor/cmder_prompt_config.lua.default b/vendor/cmder_prompt_config.lua.default index 0c99bd8..b7dc1f6 100644 --- a/vendor/cmder_prompt_config.lua.default +++ b/vendor/cmder_prompt_config.lua.default @@ -38,25 +38,20 @@ prompt_includeVersionControl = true -- NOTE: This only takes effect if using Clink v1.2.10 or higher. prompt_overrideGitStatusOptIn = false --- OPTIONAL. If true then always ignore the cmder.status and cmder.cmdstatus svn config settings and run the svn prompt commands in the background. - -- default is false - -- NOTE: This only takes effect if using Clink v1.2.10 or higher. -prompt_overrideSvnStatusOptIn = false - -- Prompt Attributes -- -- Colors: https://github.com/cmderdev/cmder/wiki/Customization#list-of-colors -- Effects: https://github.com/cmderdev/cmder/wiki/Customization#list-of-effects -- --- Green: "\x1b[1;33;49m" --- Yellow: "\x1b[1;32;49m" +-- Green: "\x1b[1;32;49m" +-- Yellow: "\x1b[1;33;49m" -- Light Grey: "\x1b[1;30;49m" -- Prompt Element Colors -uah_color = "\x1b[1;33;49m" -- Green = uah = [user]@[hostname] -cwd_color = "\x1b[1;32;49m" -- Yellow cwd = Current Working Directory +uah_color = "\x1b[1;33;49m" -- Yellow uah = [user]@[hostname] +cwd_color = "\x1b[1;32;49m" -- Green cwd = Current Working Directory lamb_color = "\x1b[1;30;49m" -- Light Grey = Lambda Color clean_color = "\x1b[37;1m" dirty_color = "\x1b[33;3m" -- Yellow, Italic conflict_color = "\x1b[31;1m" -- Red, Bold -unknown_color = "\x1b[37;1m" -- White = No VCS Status Branch Color +unknown_color = "\x1b[37;1m" -- White, Bold = No VCS Status Branch Color diff --git a/vendor/git-prompt.sh b/vendor/git-prompt.sh index 189e3dc..e64f906 100644 --- a/vendor/git-prompt.sh +++ b/vendor/git-prompt.sh @@ -1,26 +1,35 @@ +# Returns 1 if git status for Cmder is disabled, otherwise returns 0 function getGitStatusSetting() { - gitStatusSetting=$(git --no-pager config -l 2>/dev/null) + local gitConfig - if [[ -n ${gitStatusSetting} ]] && [[ ${gitStatusSetting} =~ cmder.status=false ]] || [[ ${gitStatusSetting} =~ cmder.shstatus=false ]] + # Get all git config entries for the current repository without pager + gitConfig=$(git --no-pager config -l 2>/dev/null) || return 0 # treat failure as enabled + + # Check if git status display for Cmder is disabled via config + # Matches: cmder.status=false or cmder.shstatus=false (Bash-specific) + if [[ $gitConfig =~ (^|$'\n')cmder\.(sh)?status=false($|$'\n') ]] then - echo false - else - echo true + return 1 # disabled fi + + return 0 } +# Prints current branch or detached HEAD short commit hash function getSimpleGitBranch() { - gitDir=$(git rev-parse --git-dir 2>/dev/null) - if [ -z "$gitDir" ]; then - return 0 - fi + local gitDir + gitDir=$(git rev-parse --git-dir 2>/dev/null) || return 0 - headContent=$(< "$gitDir/HEAD") - if [[ "$headContent" == "ref: refs/heads/"* ]] + local headFile="$gitDir/HEAD" + [ -f "$headFile" ] || return 0 + + local headContent + headContent=$(< "$headFile") + if [[ "$headContent" =~ ^ref:\ refs/heads/(.+)$ ]] then - echo " (${headContent:16})" + echo " (${BASH_REMATCH[1]})" else - echo " (HEAD detached at ${headContent:0:7})" + echo " (HEAD detached at ${headContent:0:7})" fi } @@ -33,18 +42,50 @@ fi if test -f ~/.config/git/git-prompt.sh then - if [[ $(getGitStatusSetting) == true ]] + if getGitStatusSetting then . ~/.config/git/git-prompt.sh fi else - PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]' # set window title - # PS1="$PS1"'\n' # new line - PS1="$PS1"'\[\033[32m\]' # change to green + + # Setup OSC 133 shell integration for Windows Terminal + if [ -n "$WT_SESSION" ]; then + __cmder_prompt_command() { + local exit_code=$? + # Emit OSC 133;D to mark the end of command execution with exit code + printf '\e]133;D;%s\a' "$exit_code" + return $exit_code + } + + __cmder_preexec() { + # Emit OSC 133;C to mark the start of command execution + printf '\e]133;C\a' + } + + # Append to PROMPT_COMMAND to emit sequences just before each prompt + if [ -z "$PROMPT_COMMAND" ]; then + PROMPT_COMMAND="__cmder_prompt_command" + else + PROMPT_COMMAND="__cmder_prompt_command;$PROMPT_COMMAND" + fi + + # Use DEBUG trap to emit OSC 133;C before command execution + trap '__cmder_preexec' DEBUG + fi + + # Source: github.com/git-for-windows/build-extra/blob/main/git-extra/git-prompt.sh + PS1='\[\033]0;${TITLEPREFIX:+$TITLEPREFIX:}${PWD//[^[:ascii:]]/?}\007\]' # set window title to TITLEPREFIX (if set) and current working directory + # PS1="$PS1"'\n' # new line (disabled) + + if [ -n "$WT_SESSION" ]; then + # Emit OSC 133;A to mark the start of prompt + PS1="$PS1"'\e]133;A\a' + fi + + PS1="$PS1"'\[\033[32m\]' # change to green and bold PS1="$PS1"'\u@\h ' # user@host - # PS1="$PS1"'\[\033[35m\]' # change to purple - # PS1="$PS1"'$MSYSTEM ' # show MSYSTEM - PS1="$PS1"'\[\033[33m\]' # change to brownish yellow + PS1="$PS1${MSYSTEM:+\[\033[35m\]$MSYSTEM }" # show MSYSTEM in purple (if set) + PS1="$PS1"'\[\033[1;33m\]' # change to dark yellow in bold PS1="$PS1"'\w' # current working directory if test -z "$WINELOADERNOEXEC" then @@ -55,31 +96,38 @@ else if test -f "$COMPLETION_PATH/git-prompt.sh" then . "$COMPLETION_PATH/git-completion.bash" - if [[ $(getGitStatusSetting) == true ]] + if getGitStatusSetting then . "$COMPLETION_PATH/git-prompt.sh" PS1="$PS1"'\[\033[36m\]' # change color to cyan PS1="$PS1"'`__git_ps1`' # bash function else - PS1="$PS1"'\[\033[37;1m\]' # change color to white + PS1="$PS1"'\[\033[37;1m\]' # change color to white PS1="$PS1"'`getSimpleGitBranch`' fi fi fi - PS1="$PS1"'\[\033[0m\]' # change color + PS1="$PS1"'\[\033[0m\]' # reset color PS1="$PS1"'\n' # new line - PS1="$PS1"'λ ' # prompt: always λ + PS1="$PS1"'\[\033[30;1m\]' # change color to grey in bold + PS1="$PS1"'λ ' # prompt: Cmder uses λ + PS1="$PS1"'\[\033[0m\]' # reset color + + if [ -n "$WT_SESSION" ]; then + # Emit OSC 133;B to mark the end of prompt + PS1="$PS1"'\[\e]133;B\a\]' + fi fi -MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc +MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc # Evaluate all user-specific Bash completion scripts (if any) if test -z "$WINELOADERNOEXEC" then - for c in "$HOME"/bash_completion.d/*.bash - do - # Handle absence of any scripts (or the folder) gracefully - test ! -f "$c" || - . "$c" - done + for c in "$HOME"/bash_completion.d/*.bash + do + # Handle absence of any scripts (or the folder) gracefully + test ! -f "$c" || + . "$c" + done fi diff --git a/vendor/init.bat b/vendor/init.bat index fafb0ee..3a622c9 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -238,6 +238,9 @@ goto :SKIP_CLINK :: Revert back to plain cmd.exe prompt without clink prompt $E[1;32;49m$P$S$_$E[1;30;49mλ$S$E[0m + + :: Add Windows Terminal shell integration support (OSC 133 sequences) + if defined WT_SESSION (prompt $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\%PROMPT%$e]133;B$e\) chcp %cp%>nul @@ -390,7 +393,7 @@ setlocal enabledelayedexpansion if defined git_locale ( REM %print_debug% init.bat "Env Var - git_locale=!git_locale!" if not defined LANG ( - for /F "delims=" %%F in ('!git_locale! -uU 2') do ( + for /F "delims=" %%F in ('"!git_locale!" -uU 2') do ( set "LANG=%%F" ) ) @@ -540,7 +543,7 @@ if "%CMDER_ALIASES%" == "1" if exist "%CMDER_ROOT%\bin\alias.bat" if exist "%CMD set initialConfig= if not exist "%CMDER_CONFIG_DIR%\user_init.cmd" ( - powershell -f "%cmder_root%\vendor\bin\create-cmdercfg.ps1" -shell cmd -outfile "%CMDER_CONFIG_DIR%\user_init.cmd" + powershell -executionpolicy bypass -f "%cmder_root%\vendor\bin\create-cmdercfg.ps1" -shell cmd -outfile "%CMDER_CONFIG_DIR%\user_init.cmd" if not exist "%CMDER_ROOT%\config\user_init.cmd" ( %print_error% "Failed to generate Cmder config" diff --git a/vendor/lib/lib_base.cmd b/vendor/lib/lib_base.cmd index f7420ef..39371c7 100644 --- a/vendor/lib/lib_base.cmd +++ b/vendor/lib/lib_base.cmd @@ -4,7 +4,7 @@ set lib_base=call "%~dp0lib_base.cmd" if "%~1" == "/h" ( %lib_base% help "%~0" -) else if "%1" neq "" ( +) else if "%~1" neq "" ( call :%* ) diff --git a/vendor/lib/lib_console.cmd b/vendor/lib/lib_console.cmd index c3649cc..600655f 100644 --- a/vendor/lib/lib_console.cmd +++ b/vendor/lib/lib_console.cmd @@ -14,7 +14,7 @@ if %fast_init% gtr %verbose_output% if %fast_init% gtr %debug_output% exit /b if "%~1" == "/h" ( %lib_base% help "%~0" -) else if "%1" neq "" ( +) else if "%~1" neq "" ( call :%* ) diff --git a/vendor/lib/lib_git.cmd b/vendor/lib/lib_git.cmd index 7b3bc47..db618cc 100644 --- a/vendor/lib/lib_git.cmd +++ b/vendor/lib/lib_git.cmd @@ -1,12 +1,12 @@ @echo off call "%~dp0lib_base.cmd" -call "%%~dp0lib_console.cmd" +call "%~dp0lib_console.cmd" set lib_git=call "%~dp0lib_git.cmd" if "%~1" == "/h" ( %lib_base% help "%~0" -) else if "%1" neq "" ( +) else if "%~1" neq "" ( call :%* ) diff --git a/vendor/lib/lib_path.cmd b/vendor/lib/lib_path.cmd index 4a9f8b9..4310f5d 100644 --- a/vendor/lib/lib_path.cmd +++ b/vendor/lib/lib_path.cmd @@ -1,12 +1,12 @@ @echo off call "%~dp0lib_base.cmd" -call "%%~dp0lib_console" +call "%~dp0lib_console.cmd" set lib_path=call "%~dp0lib_path.cmd" if "%~1" == "/h" ( %lib_base% help "%~0" -) else if "%1" neq "" ( +) else if "%~1" neq "" ( call :%* ) @@ -48,7 +48,7 @@ exit /b set "add_path=%~1" ) else ( %print_error% "You must specify a directory to add to the path!" - exit 1 + exit /b 1 ) if "%~2" neq "" if /i "%~2" == "append" ( @@ -72,7 +72,7 @@ exit /b set "PATH=%add_to_path%;%PATH%" ) goto :end_enhance_path - ) else if "add_to_path" equ "" ( + ) else if "%add_to_path%" equ "" ( goto :end_enhance_path ) @@ -84,20 +84,20 @@ exit /b setlocal enabledelayedexpansion if "!found!" == "0" ( - echo "!path!"|!WINDIR!\System32\findstr >nul /I /R /C:";!find_query!;" + echo "!PATH!"|!WINDIR!\System32\findstr >nul /I /R /C:";!find_query!;" call :set_found ) %print_debug% :enhance_path "Env Var INSIDE PATH !find_query! - found=!found!" if /i "!position!" == "append" ( if "!found!" == "0" ( - echo "!path!"|!WINDIR!\System32\findstr >nul /I /R /C:";!find_query!\"$" + echo "!PATH!"|!WINDIR!\System32\findstr >nul /I /R /C:";!find_query!\"$" call :set_found ) %print_debug% :enhance_path "Env Var END PATH !find_query! - found=!found!" ) else ( if "!found!" == "0" ( - echo "!path!"|!WINDIR!\System32\findstr >nul /I /R /C:"^\"!find_query!;" + echo "!PATH!"|!WINDIR!\System32\findstr >nul /I /R /C:"^\"!find_query!;" call :set_found ) %print_debug% :enhance_path "Env Var BEGIN PATH !find_query! - found=!found!" @@ -119,7 +119,8 @@ exit /b :end_enhance_path set "PATH=%PATH:;;=;%" - REM echo %path%|"C:\Users\dgames\cmder - dev\vendor\git-for-windows\usr\bin\wc" -c + REM echo %path%|wc -c + if "%fast_init%" == "1" exit /b if not "%OLD_PATH:~0,3000%" == "%OLD_PATH:~0,3001%" goto :toolong @@ -127,15 +128,22 @@ exit /b exit /b :toolong - echo "%OLD_PATH%">"%temp%\cmder_lib_pathA" - echo "%PATH%">"%temp%\cmder_lib_pathB" - fc /b "%temp%\cmder_lib_pathA" "%temp%\cmder_lib_pathB" 2>nul 1>nul - if errorlevel 1 ( del "%temp%\cmder_lib_pathA" & del "%temp%\cmder_lib_pathB" & goto :changed ) - del "%temp%\cmder_lib_pathA" & del "%temp%\cmder_lib_pathB" + set "_rand=%RANDOM%" + if exist "%temp%\%_rand%_cmder_lib_pathA" del "%temp%\%_rand%_cmder_lib_pathA" 2>nul 1>nul + if exist "%temp%\%_rand%_cmder_lib_pathB" del "%temp%\%_rand%_cmder_lib_pathB" 2>nul 1>nul + if exist "%temp%\%_rand%_cmder_lib_pathA" goto :toolong + if exist "%temp%\%_rand%_cmder_lib_pathB" goto :toolong + echo "%OLD_PATH%">"%temp%\%_rand%_cmder_lib_pathA" + if errorlevel 1 ( if exist "%temp%\%_rand%_cmder_lib_pathA" del "%temp%\%_rand%_cmder_lib_pathA" & goto :toolong ) + echo "%PATH%">"%temp%\%_rand%_cmder_lib_pathB" + if errorlevel 1 ( if exist "%temp%\%_rand%_cmder_lib_pathA" del "%temp%\%_rand%_cmder_lib_pathA" & if exist "%temp%\%_rand%_cmder_lib_pathB" del "%temp%\%_rand%_cmder_lib_pathB" & goto :toolong ) + fc /b "%temp%\%_rand%_cmder_lib_pathA" "%temp%\%_rand%_cmder_lib_pathB" 2>nul 1>nul + if errorlevel 1 ( del "%temp%\%_rand%_cmder_lib_pathA" & del "%temp%\%_rand%_cmder_lib_pathB" & set "_rand=" & goto :changed ) + del "%temp%\%_rand%_cmder_lib_pathA" & del "%temp%\%_rand%_cmder_lib_pathB" & set "_rand=" exit /b :changed - %print_debug% :enhance_path "END Env Var - PATH=%path%" + %print_debug% :enhance_path "END Env Var - PATH=%PATH%" %print_debug% :enhance_path "Env Var %find_query% - found=%found%" exit /b @@ -183,7 +191,7 @@ exit /b set "add_path=%~1" ) else ( %print_error% "You must specify a directory to add to the path!" - exit 1 + exit /b 1 ) set "depth=%~2" diff --git a/vendor/lib/lib_profile.cmd b/vendor/lib/lib_profile.cmd index 050beac..2a72e9d 100644 --- a/vendor/lib/lib_profile.cmd +++ b/vendor/lib/lib_profile.cmd @@ -1,12 +1,12 @@ @echo off call "%~dp0lib_base.cmd" -call "%%~dp0lib_console" +call "%~dp0lib_console.cmd" set lib_profile=call "%~dp0lib_profile.cmd" if "%~1" == "/h" ( %lib_base% help "%~0" -) else if "%1" neq "" ( +) else if "%~1" neq "" ( call :%* ) diff --git a/vendor/profile.ps1 b/vendor/profile.ps1 index a4e252d..19eef8b 100644 --- a/vendor/profile.ps1 +++ b/vendor/profile.ps1 @@ -7,15 +7,11 @@ $CMDER_INIT_START = Get-Date -# Compatibility with PS major versions <= 2 +# Determine the script root if not already set if (!$PSScriptRoot) { $PSScriptRoot = Split-Path $Script:MyInvocation.MyCommand.Path } -if ($ENV:CMDER_USER_CONFIG) { - Write-Verbose "CMDER IS ALSO USING INDIVIDUAL USER CONFIG FROM '$ENV:CMDER_USER_CONFIG'!" -} - # We do this for Powershell as Admin Sessions because CMDER_ROOT is not being set. if (!$ENV:CMDER_ROOT) { if ($ENV:ConEmuDir) { @@ -28,40 +24,61 @@ if (!$ENV:CMDER_ROOT) { # Remove trailing '\' $ENV:CMDER_ROOT = ($ENV:CMDER_ROOT).TrimEnd("\") -# -> recent PowerShell versions include PowerShellGet out of the box +# Recent PowerShell versions include PowerShellGet out of the box $moduleInstallerAvailable = [bool](Get-Command -Name 'Install-Module' -ErrorAction SilentlyContinue) +# Enable Debug and Verbose output if CMDER_DEBUG environment variable is set to '1' or 'true' +if ($env:CMDER_DEBUG -and ($env:CMDER_DEBUG -match '^(1|true)$')) { + $DebugPreference = 'Continue' + $VerbosePreference = 'Continue' +} + # Add Cmder modules directory to the autoload path. $CmderModulePath = Join-path $PSScriptRoot "psmodules/" +# Import Cmder functions $CmderFunctions = Join-Path $CmderModulePath "Cmder.ps1" . $CmderFunctions -if(-not $moduleInstallerAvailable -and -not $env:PSModulePath.Contains($CmderModulePath) ) { +# Configure PSModulePath to include Cmder modules if not already present +if (-not $moduleInstallerAvailable -and -not $env:PSModulePath.Contains($CmderModulePath) ) { $env:PSModulePath = $env:PSModulePath.Insert(0, "$CmderModulePath;") } -$gitVersionVendor = (readVersion -gitPath "$ENV:CMDER_ROOT\vendor\git-for-windows\cmd") -Write-Debug "GIT VENDOR: ${gitVersionVendor}" +if ($env:CMDER_USER_CONFIG) { + Write-Verbose "CMDER IS ALSO USING INDIVIDUAL USER CONFIG FROM '$ENV:CMDER_USER_CONFIG'!" +} -# Get user installed Git Version[s] and Compare with vendored if found. +# Read vendored Git Version +$gitVendorPath = Join-Path $ENV:CMDER_ROOT 'vendor\git-for-windows\cmd' +$gitVersionVendor = Get-GitVersion -GitPath $gitVendorPath +if (-not [string]::IsNullOrEmpty($gitVersionVendor)) { + Write-Debug "GIT VENDOR: ${gitVersionVendor}" +} else { + Write-Debug "GIT VENDOR is not present at '$gitVendorPath'" +} + +# Get user installed Git version(s) if found, and compare them with vendored version. foreach ($git in (Get-Command -ErrorAction SilentlyContinue 'git')) { - Write-Debug "GIT PATH: {$git.Path}" + Write-Debug "GIT USER PATH: $($git.Path)" $gitDir = Split-Path -Path $git.Path - $gitDir = isGitShim -gitPath $gitDir - $gitVersionUser = (readVersion -gitPath $gitDir) - Write-Debug "GIT USER: ${gitVersionUser}" + $gitDir = Get-GitShimPath -GitPath $gitDir + $gitVersionUser = Get-GitVersion -GitPath $gitDir + Write-Debug "GIT USER VERSION: ${gitVersionUser}" - $useGitVersion = compare_git_versions -userVersion $gitVersionUser -vendorVersion $gitVersionVendor + $useGitVersion = Compare-GitVersion -UserVersion $gitVersionUser -VendorVersion $gitVersionVendor Write-Debug "Using Git Version: ${useGitVersion}" # Use user installed Git if ($null -eq $gitPathUser) { + Write-Debug "Detected Git from mingw bin directory" + Write-Debug "Git Dir: ${gitDir}" if ($gitDir -match '\\mingw32\\bin' -or $gitDir -match '\\mingw64\\bin') { - $gitPathUser = ($gitDir.subString(0,$gitDir.Length - 12)) + $gitPathUser = $gitDir.subString(0, $gitDir.Length - 12) } else { - $gitPathUser = ($gitDir.subString(0,$gitDir.Length - 4)) + $gitPathUser = $gitDir.subString(0, $gitDir.Length - 4) } + Write-Debug "Git Path User: ${gitDir}" } if ($useGitVersion -eq $gitVersionUser) { @@ -72,7 +89,7 @@ foreach ($git in (Get-Command -ErrorAction SilentlyContinue 'git')) { } } -# User vendored Git. +# Use vendored Git if no user Git found or user Git is older than vendored Git if ($null -eq $ENV:GIT_INSTALL_ROOT -and $null -ne $gitVersionVendor) { $ENV:GIT_INSTALL_ROOT = "$ENV:CMDER_ROOT\vendor\git-for-windows" $ENV:GIT_INSTALL_TYPE = 'VENDOR' @@ -82,23 +99,43 @@ Write-Debug "GIT_INSTALL_ROOT: ${ENV:GIT_INSTALL_ROOT}" Write-Debug "GIT_INSTALL_TYPE: ${ENV:GIT_INSTALL_TYPE}" if ($null -ne $ENV:GIT_INSTALL_ROOT) { - $env:Path = Configure-Git -gitRoot "$ENV:GIT_INSTALL_ROOT" -gitType $ENV:GIT_INSTALL_TYPE -gitPathUser $gitPathUser + $env:Path = Set-GitPath -GitRoot "$ENV:GIT_INSTALL_ROOT" -GitType $ENV:GIT_INSTALL_TYPE -GitPathUser $gitPathUser } +# Create 'vi' alias for 'vim' if vim is available if (Get-Command -Name "vim" -ErrorAction SilentlyContinue) { New-Alias -name "vi" -value vim -errorAction SilentlyContinue } +# PSReadline configuration if (Get-Module PSReadline -ErrorAction "SilentlyContinue") { + # Display an extra prompt line between the prompt and the command input Set-PSReadlineOption -ExtraPromptLineCount 1 + + # Invoked when Enter is pressed to submit a command + if ($env:WT_SESSION) { + Set-PSReadLineKeyHandler -Key Enter -ScriptBlock { + # Get the current command line + $line = $null + $cursor = $null + [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) + + # Accept the line first + [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() + + # Emit OSC 133;C to mark start of command output + # This is written directly to the console after the command is accepted + [Console]::Write("$([char]0x1B)]133;C$([char]7)") + } + } } -# Pre-assign default prompt hooks so the first run of cmder gets a working prompt. +# Pre-assign default prompt hooks so the first run of Cmder gets a working prompt $env:gitLoaded = $null [ScriptBlock]$PrePrompt = {} [ScriptBlock]$PostPrompt = {} [ScriptBlock]$CmderPrompt = { - # Check if we're currently running under Admin privileges. + # Check if we're currently running under Admin privileges $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal] $identity $adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator @@ -107,7 +144,7 @@ $env:gitLoaded = $null $Host.UI.RawUI.ForegroundColor = "White" Microsoft.PowerShell.Utility\Write-Host "PS " -NoNewline -ForegroundColor $color Microsoft.PowerShell.Utility\Write-Host $pwd.ProviderPath -NoNewLine -ForegroundColor Green - checkGit($pwd.ProviderPath) + Show-GitStatus -Path $pwd.ProviderPath Microsoft.PowerShell.Utility\Write-Host "`nλ" -NoNewLine -ForegroundColor "DarkGray" } @@ -196,6 +233,28 @@ if ( $(Get-Command prompt).Definition -match 'PS \$\(\$executionContext.SessionS [ScriptBlock]$Prompt = { $lastSUCCESS = $? $realLastExitCode = $LastExitCode + + # Terminal-specific escape sequences for Windows Terminal and ConEmu + if ($env:WT_SESSION -or $env:ConEmuPID) { + # Emit OSC 133;D to mark the end of command execution with exit code + if ($env:WT_SESSION) { + Microsoft.PowerShell.Utility\Write-Host -NoNewline "$([char]0x1B)]133;D;$realLastExitCode$([char]7)" + } + + # Emit OSC 9;9 to enable directory tracking + # Enables "Duplicate Tab" and "Split Pane" to preserve the working directory + $loc = $executionContext.SessionState.Path.CurrentLocation + if ($loc.Provider.Name -eq "FileSystem") { + Microsoft.PowerShell.Utility\Write-Host -NoNewline "$([char]0x1B)]9;9;`"$($loc.ProviderPath)`"$([char]0x1B)\" + } + + # Emit OSC 133;A to mark the start of the prompt + # Enables features like command navigation, selection, and visual separators + if ($env:WT_SESSION) { + Microsoft.PowerShell.Utility\Write-Host -NoNewline "$([char]0x1B)]133;A$([char]7)" + } + } + $host.UI.RawUI.WindowTitle = Microsoft.PowerShell.Management\Split-Path $pwd.ProviderPath -Leaf Microsoft.PowerShell.Utility\Write-Host -NoNewline "$([char]0x200B)`r$([char]0x1B)[K" if ($lastSUCCESS -or ($LastExitCode -ne 0)) { @@ -204,6 +263,12 @@ if ( $(Get-Command prompt).Definition -match 'PS \$\(\$executionContext.SessionS PrePrompt | Microsoft.PowerShell.Utility\Write-Host -NoNewline CmderPrompt PostPrompt | Microsoft.PowerShell.Utility\Write-Host -NoNewline + + # Emit OSC 133;B to mark the start of command input (after prompt, before user types) + if ($env:WT_SESSION) { + Microsoft.PowerShell.Utility\Write-Host -NoNewline "$([char]0x1B)]133;B$([char]7)" + } + $global:LastExitCode = $realLastExitCode return " " } diff --git a/vendor/psmodules/Cmder.ps1 b/vendor/psmodules/Cmder.ps1 index c9a11df..ad46b4e 100644 --- a/vendor/psmodules/Cmder.ps1 +++ b/vendor/psmodules/Cmder.ps1 @@ -1,178 +1,250 @@ -function readVersion($gitPath) { - $gitExecutable = "${gitPath}\git.exe" +function Get-GitVersion { + param( + [Parameter(Mandatory = $true)] + [string]$GitPath + ) - if (-not (Test-Path "$gitExecutable")) { + $gitExecutable = Join-Path $GitPath "git.exe" + + if (-not (Test-Path $gitExecutable)) { return $null } - $gitVersion = (cmd /c "${gitExecutable}" --version) + # Execute 'git --version' and capture output + $gitVersion = & $gitExecutable --version 2>$null - if ($gitVersion -match 'git version') { - ($trash1, $trash2, $gitVersion) = $gitVersion.split(' ', 3) - } else { - pause - return $null + if ($gitVersion -match 'git version\s+(\S+)') { + return $Matches[1] } - return $gitVersion.toString() + Write-Debug "Git executable path: $gitExecutable" + Write-Error "'git --version' returned an improper version string!" + Write-Error "Unable to determine Git version from output: $gitVersion" + + return $null } -function isGitShim($gitPath) { - # check if there is a shim file - if yes, read the actual executable path +function Get-GitShimPath { + param( + [Parameter(Mandatory = $true)] + [string]$GitPath + ) + # Check if there is a shim file - if yes, read the actual executable path # See: github.com/ScoopInstaller/Shim - if (Test-Path "${gitPath}\git.shim") { - $shim = (get-content "${gitPath}\git.shim") - ($trash, $gitPath) = $shim.replace(' ', '').split('=') - - $gitPath = $gitPath.replace('\git.exe', '') + $shimFile = Join-Path $GitPath "git.shim" + if (Test-Path $shimFile) { + $shimContent = Get-Content $shimFile -Raw + if ($shimContent -match '^\s*path\s*=\s*(.+)\s*$') { + $GitPath = $Matches[1].Trim().Replace('\git.exe', '') + } } - return $gitPath.toString() + return $GitPath } -function compareVersions($userVersion, $vendorVersion) { - if ($null -ne $userVersion) { - ($userMajor, $userMinor, $userPatch, $userBuild) = $userVersion.split('.', 4) - } else { - return -1 +function Compare-Version { + param( + [Parameter(Mandatory = $false)] + [AllowNull()] + [string]$UserVersion, + [Parameter(Mandatory = $false)] + [AllowNull()] + [string]$VendorVersion + ) + + if ([string]::IsNullOrEmpty($UserVersion)) { return -1 } + if ([string]::IsNullOrEmpty($VendorVersion)) { return 1 } + + # Split version strings by dots to compare segment by segment + # For "2.49.0.windows.1", we get: ["2", "49", "0", "windows", "1"] + $userParts = $UserVersion -split '\.' + $vendorParts = $VendorVersion -split '\.' + + $maxLength = [Math]::Max($userParts.Count, $vendorParts.Count) + + for ($i = 0; $i -lt $maxLength; $i++) { + $userPart = if ($i -lt $userParts.Count) { $userParts[$i] } else { '' } + $vendorPart = if ($i -lt $vendorParts.Count) { $vendorParts[$i] } else { '' } + + # Check if both parts are purely numeric + $userIsNumeric = $userPart -match '^\d+$' + $vendorIsNumeric = $vendorPart -match '^\d+$' + + if ($userIsNumeric -and $vendorIsNumeric) { + # Both numeric: compare as integers (so 49 > 5, not lexicographic) + $userNum = [int]$userPart + $vendorNum = [int]$vendorPart + + if ($userNum -gt $vendorNum) { return 1 } + if ($userNum -lt $vendorNum) { return -1 } + } + elseif ($userIsNumeric -and -not $vendorIsNumeric) { + # Numeric segment comes before text segment (e.g., "2.0" < "2.0.rc1") + return -1 + } + elseif (-not $userIsNumeric -and $vendorIsNumeric) { + # Text segment comes after numeric segment + return 1 + } + else { + # Both are text: use case-insensitive lexicographic comparison + $cmp = [string]::Compare($userPart, $vendorPart, $true) + if ($cmp -ne 0) { return [Math]::Sign($cmp) } + } } - if ($null -ne $vendorVersion) { - ($vendorMajor, $vendorMinor, $vendorPatch, $vendorBuild) = $vendorVersion.split('.', 4) - } else { - return 1 - } - - if (($userMajor -eq $vendorMajor) -and ($userMinor -eq $vendorMinor) -and ($userPatch -eq $vendorPatch) -and ($userBuild -eq $vendorBuild)) { - return 1 - } - - if ($userMajor -gt $vendorMajor) { return 1 } - if ($userMajor -lt $vendorMajor) { return -1 } - - if ($userMinor -gt $vendorMinor) { return 1 } - if ($userMinor -lt $vendorMinor) { return -1 } - - if ($userPatch -gt $vendorPatch) { return 1 } - if ($userPatch -lt $vendorPatch) { return -1 } - - if ($userBuild -gt $vendorBuild) { return 1 } - if ($userBuild -lt $vendorBuild) { return -1 } - return 0 } -function compare_git_versions($userVersion, $vendorVersion) { - $result = compareVersions -userVersion $userVersion -vendorVersion $vendorVersion +function Compare-GitVersion { + param( + [Parameter(Mandatory = $false)] + [AllowNull()] + [string]$UserVersion, + [Parameter(Mandatory = $false)] + [AllowNull()] + [string]$VendorVersion + ) - Write-Debug "Compare Versions Result: ${result}" + $result = Compare-Version -UserVersion $UserVersion -VendorVersion $VendorVersion + + Write-Debug "Compare Versions Result: $result" if ($result -ge 0) { - return $userVersion - } - else { - return $vendorVersion + return $UserVersion } + return $VendorVersion } -function Configure-Git($gitRoot, $gitType, $gitPathUser) { +function Set-GitPath { + param( + [Parameter(Mandatory = $true)] + [string]$GitRoot, + [Parameter(Mandatory = $true)] + [string]$GitType, + [Parameter(Mandatory = $false)] + [string]$GitPathUser + ) + # Proposed Behavior # Modify the path if we are using VENDORED Git, do nothing if using USER Git. # If User Git is installed but is older, match its path config adding paths # in the same path positions allowing a user to configure Cmder Git path # using locally installed Git Path Config. - if ($gitType -eq 'VENDOR') { - # If User Git is installed replace its path config with Newer Vendored Git Path - if (($null -ne $gitPathUser) -and ($gitPathUser -ne '')) { - Write-Verbose "Cmder 'profile.ps1': Replacing older user Git path '$gitPathUser' with newer vendored Git path '$gitRoot' in the system path..." - $newPath = ($env:path -ireplace [regex]::Escape($gitPathUser), $gitRoot) - } - else { - if (-not ($env:Path -match [regex]::Escape("$gitRoot\cmd"))) { - Write-Debug "Adding $gitRoot\cmd to the path" - $newPath = $($gitRoot + "\cmd" + ";" + $env:Path) - } - - # Add "$gitRoot\mingw[32|64]\bin" to the path if exists and not done already - if ((Test-Path "$gitRoot\mingw32\bin") -and -not ($env:path -match [regex]::Escape("$gitRoot\mingw32\bin"))) { - Write-Debug "Adding $gitRoot\mingw32\bin to the path" - $newPath = "$newPath;$gitRoot\mingw32\bin" - } - elseif ((Test-Path "$gitRoot\mingw64\bin") -and -not ($env:path -match [regex]::Escape("$gitRoot\mingw64\bin"))) { - Write-Debug "Adding $gitRoot\mingw64\bin to the path" - $newPath = "$newPath;$gitRoot\mingw64\bin" - } - - # Add "$gitRoot\usr\bin" to the path if exists and not done already - if ((Test-Path "$gitRoot\usr\bin") -and -not ($env:path -match [regex]::Escape("$gitRoot\usr\bin"))) { - Write-Debug "Adding $gitRoot\usr\bin to the path" - $newPath = "$newPath;$gitRoot\usr\bin" - } - } - - return $newPath + if ($GitType -ne 'VENDOR') { + return $env:Path } - return $env:path + $newPath = $env:Path + + # Replace user Git path with vendored Git if user path exists + if ($GitPathUser) { + Write-Verbose "Cmder 'profile.ps1': Replacing older user Git path '$GitPathUser' with newer vendored Git path '$GitRoot' in the system path..." + $newPath = $newPath -ireplace [regex]::Escape($GitPathUser), $GitRoot + } else { + # Add Git cmd directory to the path + $gitCmd = Join-Path $GitRoot "cmd" + if (-not ($newPath -match [regex]::Escape($gitCmd))) { + Write-Debug "Adding $gitCmd to the path" + $newPath = "$gitCmd;$newPath" + } + + # Add mingw[32|64]\bin directories to the path, if they exist and not already present + # Prefer mingw64 on 64-bit systems, mingw32 on 32-bit systems + $is64Bit = [Environment]::Is64BitOperatingSystem + $mingwDirs = if ($is64Bit) { @('mingw64', 'mingw32') } else { @('mingw32') } + + foreach ($mingw in $mingwDirs) { + $mingwBin = Join-Path $GitRoot "$mingw\bin" + if ((Test-Path $mingwBin) -and -not ($newPath -match [regex]::Escape($mingwBin))) { + Write-Debug "Adding $mingwBin to the path" + $newPath = "$newPath;$mingwBin" + break + } + } + + # Add usr\bin directory to the path + $usrBin = Join-Path $GitRoot "usr\bin" + if ((Test-Path $usrBin) -and -not ($newPath -match [regex]::Escape($usrBin))) { + Write-Debug "Adding $usrBin to the path" + $newPath = "$newPath;$usrBin" + } + } + + return $newPath } -function Import-Git() { - $GitModule = Get-Module -Name Posh-Git -ListAvailable - if ($GitModule | Select-Object version | Where-Object version -le ([version]"0.6.1.20160330")) { - Import-Module Posh-Git > $null - } - if ($GitModule | Select-Object version | Where-Object version -ge ([version]"1.0.0")) { - Import-Module Posh-Git > $null - $GitPromptSettings.AnsiConsole = $false - } - if (-not $GitModule) { - Write-Host -NoNewline "`r`n" +function Import-Git { + $gitModule = Get-Module -Name Posh-Git -ListAvailable + + if (-not $gitModule) { + Microsoft.PowerShell.Utility\Write-Host -NoNewline "`r`n" Write-Warning "Missing git support, install posh-git with 'Install-Module posh-git' and restart Cmder." - Write-Host -NoNewline "`r$([char]0x1B)[A" + Microsoft.PowerShell.Utility\Write-Host -NoNewline "`r$([char]0x1B)[A" return $false } - # Make sure we only run once by always returning true + + # Import posh-git module (works for all versions) + Import-Module Posh-Git -ErrorAction SilentlyContinue | Out-Null + + # Apply version-specific settings for posh-git 1.0.0+ + if (($gitModule.Version -ge [version]"1.0.0") -and (Get-Variable -Name GitPromptSettings -ErrorAction SilentlyContinue)) { + $GitPromptSettings.AnsiConsole = $false + } + return $true } -function checkGit($Path) { +function Show-GitStatus { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + if (-not (Get-Command git -ErrorAction SilentlyContinue)) { return } - if (-not (Test-Path -Path (Join-Path $Path '.git'))) { - $SplitPath = Split-Path $path - if ($SplitPath) { checkGit($SplitPath) } + + $gitDir = Join-Path $Path '.git' + if (-not (Test-Path $gitDir)) { + $parentPath = Split-Path $Path + if ($parentPath) { + Show-GitStatus -Path $parentPath + } return } - if (getGitStatusSetting -eq $true) { + + if (Get-GitStatusSetting) { if ($null -eq $env:gitLoaded) { $env:gitLoaded = Import-Git } if ($env:gitLoaded -eq $true) { Write-VcsStatus } - } - else { - $headContent = Get-Content (Join-Path $Path '.git/HEAD') - if ($headContent -like "ref: refs/heads/*") { - $branchName = $headContent.Substring(16) + } else { + $headFile = Join-Path $gitDir 'HEAD' + if (Test-Path $headFile) { + $headContent = Get-Content $headFile -Raw + if ($headContent -match 'ref: refs/heads/(.+)') { + $branchName = $Matches[1].Trim() + } else { + $shortHash = $headContent.Substring(0, [Math]::Min(7, $headContent.Length)) + $branchName = "HEAD detached at $shortHash" + } + Microsoft.PowerShell.Utility\Write-Host " [$branchName]" -NoNewline -ForegroundColor White } - else { - $branchName = "HEAD detached at $($headContent.Substring(0, 7))" - } - Write-Host " [$branchName]" -NoNewline -ForegroundColor White } } -function getGitStatusSetting() { - $gitStatus = (git --no-pager config -l) | Out-String +function Get-GitStatusSetting { + $gitConfig = git --no-pager config -l 2>$null | Out-String - foreach ($line in $($gitStatus -split "`r`n")) { - if (($line -match 'cmder.status=false') -or ($line -match 'cmder.psstatus=false')) { - return $false - } + # Check if git status display is disabled via config + # Matches: cmder.status=false or cmder.psstatus=false (PowerShell-specific) + if ($gitConfig -match '(?m)^cmder\.(ps)?status=false$') { + return $false } return $true diff --git a/vendor/sources.json b/vendor/sources.json index 1a62384..f86c7fc 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -1,27 +1,27 @@ [ - { - "name": "windows-terminal", - "version": "1.20.11271.0", - "url": "https://github.com/microsoft/terminal/releases/download/v1.20.11271.0/Microsoft.WindowsTerminal_1.20.11271.0_x64.zip" - }, { "name": "git-for-windows", - "version": "2.47.0.windows.1", - "url": "https://github.com/git-for-windows/git/releases/download/v2.47.0.windows.1/PortableGit-2.47.0-64-bit.7z.exe" + "version": "2.51.2.windows.1", + "url": "https://github.com/git-for-windows/git/releases/download/v2.51.2.windows.1/PortableGit-2.51.2-64-bit.7z.exe" }, { "name": "clink", - "version": "1.7.3", - "url": "https://github.com/chrisant996/clink/releases/download/v1.7.3/clink.1.7.3.f8fb96.zip" + "version": "1.8.8", + "url": "https://github.com/chrisant996/clink/releases/download/v1.8.8/clink.1.8.8.a63364.zip" }, { "name": "conemu-maximus5", "version": "23.07.24", - "url": "https://github.com/Maximus5/ConEmu/releases/download/v23.07.24/ConEmuPack.230724.7z" + "url": "https://github.com/ConEmu/ConEmu/releases/download/v23.07.24/ConEmuPack.230724.7z" + }, + { + "name": "windows-terminal", + "version": "1.23.12811.0", + "url": "https://github.com/microsoft/terminal/releases/download/v1.23.12811.0/Microsoft.WindowsTerminal_1.23.12811.0_x64.zip" }, { "name": "clink-completions", - "version": "0.6.0", - "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.6.0.zip" + "version": "0.6.6", + "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.6.6.zip" } ]