diff --git a/.github/workflows/branches.yml b/.github/workflows/branches.yml index 6c4428ec4..a974d740d 100644 --- a/.github/workflows/branches.yml +++ b/.github/workflows/branches.yml @@ -9,6 +9,10 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +concurrency: + group: update-development + cancel-in-progress: false + permissions: actions: write contents: write @@ -25,7 +29,9 @@ jobs: # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it - uses: actions/checkout@v7 with: + ref: development fetch-depth: 0 # fetch all history for all branches and tags + token: ${{ secrets.BRANCH_SYNC_TOKEN || github.token }} - name: Summary - Merge operation started shell: bash @@ -55,12 +61,119 @@ jobs: # Runs a single command using the runners shell - name: Merge master into development + shell: bash + env: + HAS_BRANCH_SYNC_TOKEN: ${{ secrets.BRANCH_SYNC_TOKEN != '' }} run: | + set -euo pipefail + + failure_log="$RUNNER_TEMP/branch-sync-failure.log" + short_diff_file="$RUNNER_TEMP/branch-sync-short-diff.txt" + last_command_file="$RUNNER_TEMP/branch-sync-last-command.txt" + command_log="$RUNNER_TEMP/branch-sync-commands.log" + : > "$failure_log" + : > "$short_diff_file" + : > "$last_command_file" + : > "$command_log" + + quote_command() { + local quoted="" + local arg + for arg in "$@"; do + printf -v quoted_arg "%q" "$arg" + quoted+="${quoted_arg} " + done + printf "%s" "${quoted% }" + } + + capture_short_diff() { + local diff_file="$1" + local max_lines=180 + local tmp_file + + tmp_file="$(mktemp)" + + { + echo "## git status --short" + git status --short || true + echo "" + + mapfile -t unmerged_files < <(git diff --name-only --diff-filter=U 2>/dev/null || true) + if [[ "${#unmerged_files[@]}" -gt 0 ]]; then + echo "## conflict diff" + git diff --cc -- "${unmerged_files[@]}" || true + elif ! git diff --quiet -- . 2>/dev/null; then + echo "## worktree diff" + git diff -- . || true + elif ! git diff --cached --quiet -- . 2>/dev/null; then + echo "## staged diff" + git diff --cached -- . || true + elif git rev-parse --verify origin/development >/dev/null 2>&1 && ! git diff --quiet origin/development HEAD -- . 2>/dev/null; then + echo "## branch diff against origin/development" + git diff --stat origin/development HEAD -- . || true + echo "" + git diff --patch --find-renames origin/development HEAD -- . || true + else + echo "No local or branch diff was available after the failure." + fi + } > "$tmp_file" + + sed -n "1,${max_lines}p" "$tmp_file" > "$diff_file" + if [[ "$(wc -l < "$tmp_file")" -gt "$max_lines" ]]; then + echo "" >> "$diff_file" + echo "[diff truncated after ${max_lines} lines]" >> "$diff_file" + fi + + rm -f "$tmp_file" + } + + run_command() { + local command_display + local output + local status + + command_display="$(quote_command "$@")" + printf "%s\n" "$command_display" > "$last_command_file" + printf "$ %s\n" "$command_display" >> "$command_log" + + set +e + output="$("$@" 2>&1)" + status=$? + set -e + + if [[ -n "$output" ]]; then + printf "%s\n" "$output" + printf "%s\n" "$output" >> "$command_log" + fi + + if [[ "$status" -ne 0 ]]; then + { + printf "Command: %s\n" "$command_display" + printf "Exit code: %s\n" "$status" + printf "\n" + printf "%s\n" "$output" + } > "$failure_log" + capture_short_diff "$short_diff_file" + return "$status" + fi + } + git config user.name "${{ github.actor }}" git config user.email "${{ github.actor }}@users.noreply.github.com" - git checkout development - git merge --no-ff master - git push origin development + run_command git fetch origin master development + run_command git checkout -B development origin/development + run_command git reset --hard origin/development + run_command git clean -fdx + run_command git merge --no-ff origin/master + + if git diff --name-only origin/development HEAD | grep -q '^\.github/workflows/'; then + echo "This merge updates workflow files. Configure a BRANCH_SYNC_TOKEN secret with workflow scope so GitHub accepts the sync push." >> "$GITHUB_STEP_SUMMARY" + if [[ "$HAS_BRANCH_SYNC_TOKEN" != "true" ]]; then + echo "::warning::This merge updates workflow files, but BRANCH_SYNC_TOKEN is not configured. GitHub may reject the push because GITHUB_TOKEN cannot update workflow files." + fi + fi + + run_command git push origin HEAD:development - name: Summary - Merge completed if: success() @@ -77,3 +190,147 @@ jobs: echo "**Merge type:** No fast-forward merge" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "> The [\`development\`]($target_branch_url) branch is now synchronized with the latest changes from [\`master\`]($source_branch_url)." >> $GITHUB_STEP_SUMMARY + + - name: Summary - Merge failed + if: failure() + shell: bash + run: | + failure_log="$RUNNER_TEMP/branch-sync-failure.log" + short_diff_file="$RUNNER_TEMP/branch-sync-short-diff.txt" + command_log="$RUNNER_TEMP/branch-sync-commands.log" + + extract_reason() { + local log_file="$1" + if [[ ! -s "$log_file" ]]; then + printf "No command stderr/stdout was captured. Open the failed step log for the raw runner output." + return + fi + + awk ' + /error:|fatal:|CONFLICT|Aborting|refusing to allow|rejected|would be overwritten|Please commit your changes|Merge with strategy|non-fast-forward|fetch first|Permission denied|not authorized|workflow scope/ { + print + } + ' "$log_file" + } + + add_suggestions() { + local log_text="$1" + + if [[ "$log_text" =~ "would be overwritten by merge" || "$log_text" =~ "Please commit your changes or stash them before you merge" ]]; then + cat <<'EOF' + ```bash + git fetch origin master development + git checkout development + git status --short + git diff + git restore --worktree --staged + git merge --no-ff origin/master + git push origin development + ``` + EOF + return + fi + + if [[ "$log_text" =~ "refusing to allow a GitHub App to create or update workflow" ]]; then + cat <<'EOF' + ```bash + # Create a fine-grained PAT that can write Contents and Workflows, + # then save it as the repository secret BRANCH_SYNC_TOKEN. + gh secret set BRANCH_SYNC_TOKEN --repo cmderdev/cmder + + # After the secret is configured, rerun the failed branch-sync workflow. + gh run rerun ${{ github.run_id }} --repo ${{ github.repository }} --failed + ``` + EOF + return + fi + + if [[ "$log_text" =~ "non-fast-forward" || "$log_text" =~ "fetch first" ]]; then + cat <<'EOF' + ```bash + git fetch origin master development + git checkout development + git merge --no-ff origin/master + git push origin development + ``` + EOF + return + fi + + if [[ "$log_text" =~ "CONFLICT" ]]; then + cat <<'EOF' + ```bash + git fetch origin master development + git checkout development + git merge --no-ff origin/master + git status + # Resolve the conflicted files, then: + git add + git commit + git push origin development + ``` + EOF + return + fi + + cat <<'EOF' + ```bash + git fetch origin master development + git checkout development + git merge --no-ff origin/master + git status + ``` + EOF + } + + log_text="" + if [[ -s "$failure_log" ]]; then + log_text="$(cat "$failure_log")" + fi + + reason="$(extract_reason "$failure_log" | sed '/^[[:space:]]*$/d')" + if [[ -z "$reason" && -n "$log_text" ]]; then + reason="$log_text" + fi + + echo "### โŒ Merge Failed" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Failed command:**" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo '```bash' >> "$GITHUB_STEP_SUMMARY" + if [[ -s "$failure_log" ]]; then + sed -n 's/^Command: //p' "$failure_log" | head -n 1 >> "$GITHUB_STEP_SUMMARY" + else + echo "Unknown; failure happened before command capture was initialized." >> "$GITHUB_STEP_SUMMARY" + fi + echo '```' >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Extracted reason:**" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo '```text' >> "$GITHUB_STEP_SUMMARY" + printf "%s\n" "$reason" >> "$GITHUB_STEP_SUMMARY" + echo '```' >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Suggested fix commands:**" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + add_suggestions "$log_text" >> "$GITHUB_STEP_SUMMARY" + + if [[ -s "$short_diff_file" ]]; then + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Short relevant diff:**" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo '```diff' >> "$GITHUB_STEP_SUMMARY" + cat "$short_diff_file" >> "$GITHUB_STEP_SUMMARY" + echo '```' >> "$GITHUB_STEP_SUMMARY" + fi + + if [[ -s "$command_log" ]]; then + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "
Captured command output" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo '```text' >> "$GITHUB_STEP_SUMMARY" + cat "$command_log" >> "$GITHUB_STEP_SUMMARY" + echo '```' >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "
" >> "$GITHUB_STEP_SUMMARY" + fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1454b8898..eb62466bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -79,6 +79,11 @@ jobs: $branchLink = "https://github.com/${{ github.repository }}/tree/$refName" } + Write-Host "::notice title=Build info::Cmder $cmderVersion was built from branch '$actualBranchName' via '$eventName'." + if ($prNumber) { + Write-Host "::notice title=Pull request::Associated with PR #$prNumber." + } + $summary = @" ## ๐Ÿ“ฆ Build Cmder - Workflow Summary @@ -88,7 +93,8 @@ jobs: | Property | Value | | --- | --- | | Repository | [``${{ github.repository }}``](https://github.com/${{ github.repository }}) | - | Branch | [``$actualBranchName``]($branchLink) | + | Source Branch | [``$actualBranchName``]($branchLink) | + | Event | ``$eventName`` | "@ if ($prNumber) { @@ -98,7 +104,7 @@ jobs: $summary += @" | Commit | [``${{ github.sha }}``](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) | | Actor | [@${{ github.actor }}](https://github.com/${{ github.actor }}) | - | Workflow | ``${{ github.workflow }}`` | + | Workflow | [``${{ github.workflow }}``](https://github.com/${{ github.repository }}/blob/${{ github.sha }}/.github/workflows/build.yml) | | Cmder Version | **$cmderVersion** | --- @@ -135,7 +141,6 @@ jobs: } $summary += "`n" - $summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 - name: Add MSBuild to PATH @@ -144,116 +149,194 @@ jobs: - name: Build Cmder Launcher shell: pwsh working-directory: scripts - run: .\build.ps1 -Compile -verbose + run: .\build.ps1 -Compile -Terminal all -Verbose - name: Summary - Build completed if: success() shell: pwsh run: | - $summary = @" - - --- - - โœ… Cmder built successfully. - - "@ - - $summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 + echo "### โœ… Build Status" >> $env:GITHUB_STEP_SUMMARY + echo "" >> $env:GITHUB_STEP_SUMMARY + echo "Cmder launcher successfully compiled." >> $env:GITHUB_STEP_SUMMARY + echo "" >> $env:GITHUB_STEP_SUMMARY - name: Pack the built files shell: pwsh working-directory: scripts - run: .\pack.ps1 -verbose + run: .\pack.ps1 -Terminal all -Verbose - - name: Upload artifact (cmder.zip) + - name: Upload artifact (cmder_launcher.7z) + id: upload_cmder_launcher_7z + uses: actions/upload-artifact@v7 + with: + path: build/cmder_launcher/cmder_launcher.7z + if-no-files-found: error + archive: false + + - name: Upload artifact (cmder_launcher.zip) + id: upload_cmder_launcher_zip uses: actions/upload-artifact@v7 with: - path: build/cmder.zip - name: cmder.zip + path: build/cmder_launcher/cmder_launcher.zip + if-no-files-found: error archive: false + + - name: Upload artifact (cmder_launcher_mini.zip) + id: upload_cmder_launcher_mini_zip + uses: actions/upload-artifact@v7 + with: + path: build/cmder_launcher/cmder_launcher_mini.zip if-no-files-found: error + archive: false - name: Upload artifact (cmder.7z) + id: upload_cmder_7z uses: actions/upload-artifact@v7 with: - path: build/cmder.7z - name: cmder.7z + path: build/cmder/cmder.7z + if-no-files-found: error + archive: false + + - name: Upload artifact (cmder.zip) + id: upload_cmder_zip + uses: actions/upload-artifact@v7 + with: + path: build/cmder/cmder.zip + if-no-files-found: error archive: false - name: Upload artifact (cmder_mini.zip) + id: upload_cmder_mini_zip + uses: actions/upload-artifact@v7 + with: + path: build/cmder/cmder_mini.zip + if-no-files-found: error + archive: false + + - name: Upload artifact (cmder_conemu.7z) + id: upload_cmder_conemu_7z uses: actions/upload-artifact@v7 with: - path: build/cmder_mini.zip - name: cmder_mini.zip + path: build/cmder_conemu/cmder_conemu.7z + if-no-files-found: error + archive: false + + - name: Upload artifact (cmder_conemu.zip) + id: upload_cmder_conemu_zip + uses: actions/upload-artifact@v7 + with: + path: build/cmder_conemu/cmder_conemu.zip + if-no-files-found: error + archive: false + + - name: Upload artifact (cmder_conemu_mini.zip) + id: upload_cmder_conemu_mini_zip + uses: actions/upload-artifact@v7 + with: + path: build/cmder_conemu/cmder_conemu_mini.zip + if-no-files-found: error archive: false - name: Upload artifact (hashes.txt) + id: upload_hashes_txt uses: actions/upload-artifact@v7 with: path: build/hashes.txt - name: hashes.txt + if-no-files-found: error archive: false - - name: Summary - Artifacts uploaded + - name: Summary - Package artifacts if: success() shell: pwsh env: GH_TOKEN: ${{ github.token }} + ARTIFACT_URL_CMDER_LAUNCHER_7Z: ${{ steps.upload_cmder_launcher_7z.outputs.artifact-url }} + ARTIFACT_URL_CMDER_LAUNCHER_ZIP: ${{ steps.upload_cmder_launcher_zip.outputs.artifact-url }} + ARTIFACT_URL_CMDER_LAUNCHER_MINI_ZIP: ${{ steps.upload_cmder_launcher_mini_zip.outputs.artifact-url }} + ARTIFACT_URL_CMDER_7Z: ${{ steps.upload_cmder_7z.outputs.artifact-url }} + ARTIFACT_URL_CMDER_ZIP: ${{ steps.upload_cmder_zip.outputs.artifact-url }} + ARTIFACT_URL_CMDER_MINI_ZIP: ${{ steps.upload_cmder_mini_zip.outputs.artifact-url }} + ARTIFACT_URL_CMDER_CONEMU_7Z: ${{ steps.upload_cmder_conemu_7z.outputs.artifact-url }} + ARTIFACT_URL_CMDER_CONEMU_ZIP: ${{ steps.upload_cmder_conemu_zip.outputs.artifact-url }} + ARTIFACT_URL_CMDER_CONEMU_MINI_ZIP: ${{ steps.upload_cmder_conemu_mini_zip.outputs.artifact-url }} + ARTIFACT_URL_HASHES_TXT: ${{ steps.upload_hashes_txt.outputs.artifact-url }} run: | # Source utility functions . scripts/utils.ps1 + function Get-ArtifactUrl { + param( + [Parameter(Mandatory = $true)] + [string]$ArtifactName + ) + + $envName = "ARTIFACT_URL_" + (($ArtifactName -replace '[^A-Za-z0-9]+', '_').Trim('_')).ToUpperInvariant() + $downloadUrl = [Environment]::GetEnvironmentVariable($envName) + if ($downloadUrl) { + return $downloadUrl + } + + return Get-ArtifactDownloadUrl -ArtifactName $ArtifactName -Repository "${{ github.repository }}" -RunId "${{ github.run_id }}" + } + $profiles = Get-CmderPackageProfiles -Terminal all $summary = @" - ### ๐Ÿ—ƒ๏ธ Artifacts - | Artifact | Size | Hash (SHA256) | - | --- | --- | --- | + ### ๐Ÿ—ƒ๏ธ Packages "@ - # Get all files from the build directory (excluding directories and hidden files) - if (Test-Path "build") { - $buildFiles = Get-ChildItem -Path "build" -File | Where-Object { -not $_.Name.StartsWith('.') } | Sort-Object Name + foreach ($profile in $profiles) { + $profilePath = Join-Path "build" $profile.outputFolder + if (-not (Test-Path $profilePath)) { + continue + } + + $summary += "`n`n#### ๐Ÿ“ $($profile.displayName) ``$($profile.outputFolder)``" + $summary += "`n`n| Artifact | Size | Hash (SHA256) |" + $summary += "`n| --- | --- | --- |" + $buildFiles = Get-ChildItem -Path $profilePath -File | Where-Object { -not $_.Name.StartsWith('.') } | Sort-Object Name foreach ($file in $buildFiles) { $artifact = $file.Name - $path = $file.FullName - $sizeFormatted = Format-FileSize -Bytes $file.Length - $hash = (Get-FileHash $path -Algorithm SHA256).Hash - - # Try to get the actual artifact download URL - $downloadUrl = Get-ArtifactDownloadUrl -ArtifactName $artifact -Repository "${{ github.repository }}" -RunId "${{ github.run_id }}" + $downloadUrl = Get-ArtifactUrl -ArtifactName $artifact $warning = "" if (-not $downloadUrl) { - # Fallback to workflow run page if artifact URL fetch fails $downloadUrl = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" $warning = " โš ๏ธ" } - # Determine emoji based on file type - if ($artifact -match '\.txt$') { - $emoji = "๐Ÿ“„" - } elseif ($artifact -match '\.(zip|rar|7z)$') { - $emoji = "๐Ÿ—„๏ธ" - } else { - $emoji = "๐Ÿ“ฆ" - } - + $emoji = Get-ArtifactTypeEmoji -Name $artifact + $sizeFormatted = Format-FileSize -Bytes $file.Length + $hash = (Get-FileHash $file.FullName -Algorithm SHA256).Hash $summary += "`n| $emoji [``$artifact``$warning]($downloadUrl) | $sizeFormatted | ``$hash`` |" } } - $summary += "`n" + $hashesPath = "build/hashes.txt" + if (Test-Path $hashesPath) { + $downloadUrl = Get-ArtifactUrl -ArtifactName "hashes.txt" + $warning = "" + + if (-not $downloadUrl) { + $downloadUrl = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + $warning = " โš ๏ธ" + } + + $hashesSize = Format-FileSize -Bytes (Get-Item $hashesPath).Length + $hashesHash = (Get-FileHash $hashesPath -Algorithm SHA256).Hash + $summary += "`n`n#### ๐Ÿงพ Hash Manifest" + $summary += "`n`n| Artifact | Size | Hash (SHA256) |" + $summary += "`n| --- | --- | --- |" + $summary += "`n| ๐Ÿ“„ [``hashes.txt``$warning]($downloadUrl) | $hashesSize | ``$hashesHash`` |" + } + + $summary += "`n" $summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 - name: Create Release uses: softprops/action-gh-release@v3 with: - files: | - build/cmder.zip - build/cmder.7z - build/cmder_mini.zip - build/hashes.txt + files: build/**/*.* draft: true generate_release_notes: true if: startsWith(github.ref, 'refs/tags/') @@ -262,6 +345,8 @@ jobs: if: startsWith(github.ref, 'refs/tags/') shell: pwsh run: | + . scripts/utils.ps1 + $profiles = Get-CmderPackageProfiles -Terminal all $summary = @" --- @@ -270,12 +355,12 @@ jobs: ๐Ÿš€ Draft release created for tag: **``${{ github.ref_name }}``** - Release includes: - - Full version (``cmder.zip``, ``cmder.7z``) - - Mini version (``cmder_mini.zip``) - - File hashes (``hashes.txt``) - - > โš ๏ธ Release is in **draft** mode. Please review and publish manually. + Release includes these package groups: "@ + foreach ($profile in $profiles) { + $summary += "`n- **$($profile.displayName)** ``$($profile.outputFolder)``" + } + + $summary += "`n`n> โš ๏ธ Release is in **draft** mode. Please review and publish manually.`n" $summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 91983d06e..669ff9332 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -108,6 +108,7 @@ jobs: uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} + build-mode: manual # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. @@ -121,7 +122,7 @@ jobs: - name: Build Cmder Launcher shell: pwsh working-directory: scripts - run: .\build.ps1 -Compile -verbose + run: .\build.ps1 -Compile -NoVendor -Verbose - name: Summary - Build status if: success() diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f7ceac8ce..ba19b5de6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -110,7 +110,7 @@ jobs: - name: Initialize vendors shell: pwsh working-directory: scripts - run: .\build.ps1 -verbose + run: .\build.ps1 -Verbose - name: Summary - Vendor initialization if: success() @@ -162,12 +162,104 @@ jobs: $summary | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 + - name: Testing Command Script Extensions + id: test-command-script-extensions + shell: pwsh + run: | + $startTime = Get-Date + $allowedBatFiles = @( + "Cmder.bat", + "vendor/init.bat" + ) + $trackedBatFiles = @(git ls-files "*.bat") + $unexpectedBatFiles = @($trackedBatFiles | Where-Object { $allowedBatFiles -notcontains $_ }) + + if ($unexpectedBatFiles.Count -gt 0) { + $message = @( + "Unexpected tracked .bat files were found.", + "Use .cmd for command scripts unless the file is explicitly allowed.", + "", + ($unexpectedBatFiles | ForEach-Object { "- $_" }) -join "`n" + ) -join "`n" + throw $message + } + + $duration = [math]::Round(((Get-Date) - $startTime).TotalSeconds, 2) + echo "duration=$duration" >> $env:GITHUB_OUTPUT + + - name: Summary - Command script extension test + if: success() + shell: pwsh + run: | + $duration = "${{ steps.test-command-script-extensions.outputs.duration }}" + if ($duration) { + $duration = "$duration s" + } else { + $duration = "N/A" + } + "| Command Script Extensions | โœ… Passed | $duration |" | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 + + - name: Testing init.bat Compatibility Shim + id: test-init-bat-compatibility-shim + shell: pwsh + run: | + $startTime = Get-Date + $repoRoot = $PWD.Path + $initShim = Join-Path $PWD "vendor\init.bat" + $shimRoot = Join-Path $env:RUNNER_TEMP "cmder-init-shim" + + if (-not (Test-Path $initShim)) { + throw "Expected tracked init.bat compatibility shim at '$initShim'." + } + + try { + Remove-Item -Path $shimRoot -Recurse -Force -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Path $shimRoot | Out-Null + + $shimContent = Get-Content -Path $initShim -Raw + if ($shimContent -notmatch "Please update your Cmder task or shell configuration" -or $shimContent -notmatch "call .*init\.cmd") { + throw "The tracked init.bat shim did not contain the expected notice and init.cmd call." + } + + $shimOutput = cmd /d /c "set `"CMDER_ROOT=$repoRoot`"&& set `"cmder_root=$repoRoot`"&& set CMDER_USER_CONFIG=&& set CMDER_CONFIGURED=&& call vendor\init.bat /f /c `"$shimRoot`"" 2>&1 + $shimOutputText = $shimOutput -join "`n" + + if ($LASTEXITCODE -ne 0) { + throw "Generated init.bat shim exited with code $LASTEXITCODE.`n$shimOutputText" + } + + if ($shimOutputText -notmatch "Please update your Cmder task or shell configuration" -or $shimOutputText -notmatch "init\.cmd") { + throw "Generated init.bat shim did not display the expected migration notice." + } + + if (-not (Test-Path (Join-Path $shimRoot "config\user_init.cmd"))) { + throw "Tracked init.bat shim did not load init.cmd and create user_init.cmd." + } + } finally { + Remove-Item -Path $shimRoot -Recurse -Force -ErrorAction SilentlyContinue + } + + $duration = [math]::Round(((Get-Date) - $startTime).TotalSeconds, 2) + echo "duration=$duration" >> $env:GITHUB_OUTPUT + + - name: Summary - init.bat compatibility shim test + if: success() + shell: pwsh + run: | + $duration = "${{ steps.test-init-bat-compatibility-shim.outputs.duration }}" + if ($duration) { + $duration = "$duration s" + } else { + $duration = "N/A" + } + "| init.bat Compatibility Shim | โœ… Passed | $duration |" | Add-Content -Path $env:GITHUB_STEP_SUMMARY -Encoding utf8 + - name: Testing Clink Shell id: test-clink shell: pwsh run: | $startTime = Get-Date - cmd /c vendor\init.bat /v /d /t + cmd /c vendor\init.cmd /v /d /t $duration = [math]::Round(((Get-Date) - $startTime).TotalSeconds, 2) echo "duration=$duration" >> $env:GITHUB_OUTPUT diff --git a/.github/workflows/vendor.yml b/.github/workflows/vendor.yml index 7fcbc1938..6fdc714b5 100644 --- a/.github/workflows/vendor.yml +++ b/.github/workflows/vendor.yml @@ -67,7 +67,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | $currentVersion = (Get-Content -Raw .\vendor\sources.json | ConvertFrom-Json) - . .\scripts\update.ps1 -verbose + . .\scripts\update.ps1 -Verbose # Export count of updated packages (update.ps1 is expected to set $count) if (-not ($count)) { $count = 0 } diff --git a/.gitignore b/.gitignore index 71475ec9e..3ca812444 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,10 @@ launcher/src/version.rc2 .vs/* .vscode .idea +.vagrant/ +scripts/packer/iso/*.iso +!scripts/packer/floppy/*.exe +scripts/packer/packer_cache +scripts/packer/output-* +*.box + diff --git a/CHANGELOG.md b/CHANGELOG.md index eca18db4c..669695dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Change Log + +## Unreleased + +### Adds + +- Add Windows Terminal support and make it the default bundled terminal when present, including portable Windows Terminal settings, Cmder/PowerShell/Bash profiles, admin profiles, color schemes, and launcher support for Windows Terminal profile/task selection. See [#2897](https://github.com/cmderdev/cmder/pull/2897), [#2943](https://github.com/cmderdev/cmder/pull/2943), and [#3090](https://github.com/cmderdev/cmder/pull/3090). +- Add the **Cmder Launcher** package profile for builds that include Cmder, Clink, and optional Git for Windows integration without bundling a terminal emulator. See [#2942](https://github.com/cmderdev/cmder/pull/2942). +- Add configurable package profiles in `scripts/package-profiles.json` so package display names, output folders, included vendors, and package variants are driven by JSON rather than hardcoded script branches. +- Add `-Terminal` support to `scripts/build.ps1` and `scripts/pack.ps1` for building or packing `all`, `none`, `windows-terminal`, or `conemu-maximus5` terminal profiles. +- Add grouped package outputs for `cmder_launcher`, `cmder`, and `cmder_conemu`, each with full and mini variants, plus one root `build/hashes.txt` manifest for all generated archives. +- Add Git Bash and Mintty launch helpers in `vendor/start_git_bash.cmd` and `vendor/start_git_mintty.cmd`, including support for vendored Git for Windows or external Git installations. +- Add `vendor/bin/create-cmdercfg.cmd`, `vendor/bin/create-cmdercfg.ps1`, `vendor/user_init.cmd.template`, and PowerShell template expansion helpers to generate an editable `config/user_init.cmd` from Cmder's discovered configuration. See [#2896](https://github.com/cmderdev/cmder/pull/2896) and [#3082](https://github.com/cmderdev/cmder/pull/3082). +- Add a `.cmd` script-extension guard and a legacy `init.bat` migration test to the test workflow so accidental tracked `.bat` command scripts are caught early. +- Add `.git-blame-ignore-revs` for whitespace-only cleanups, plus `.gitignore` and `packignore` updates for the new generated/package files. +- Add `scripts/README.md` describing the build, pack, update, shared helper, and package-profile configuration files. + +### Changes + +- Rename `vendor/init.bat` to `vendor/init.cmd` and update Cmder startup paths, generated templates, Windows Terminal defaults, ConEmu defaults, documentation, and tests to use the `.cmd` startup script. See [#3082](https://github.com/cmderdev/cmder/pull/3082). +- Preserve compatibility for existing `vendor/init.bat` installations by backing up the old file to `init.bat.old` or `init.bat.old.N`, creating a new `init.bat` shim that tells the user to update their configuration, and then calling `init.cmd`. +- Refactor `scripts/build.ps1`, `scripts/pack.ps1`, and `scripts/utils.ps1` around shared package-profile helpers, configurable included vendors, reusable artifact/hash helpers, and consistent `-Verbose` casing/placement. +- Change package selection from excluded-vendor logic to `includedVendors` so each profile and package variant explicitly declares what it contains. +- Update GitHub Actions build packaging to upload each generated archive as its own artifact with `actions/upload-artifact@v7`, `archive: false`, `if-no-files-found: error`, per-file artifact links, emoji-rich summaries, profile headings, and one downloadable `hashes.txt` manifest. +- Update Build, Run Tests, CodeQL, and vendor update workflow summaries with linked repository/branch/commit/workflow/run values, branch/build annotations, correct PR links, clearer auto-merge failure messaging, and newline-safe markdown output. See [#3091](https://github.com/cmderdev/cmder/pull/3091). +- Update CodeQL to use manual build mode and build the launcher with `-Compile -NoVendor -Verbose` so analysis does not redownload all vendors. See [#3085](https://github.com/cmderdev/cmder/pull/3085). +- Update `Cmder.bat` to select Windows Terminal when it is bundled, keep ConEmu as a supported launch path, and initialize/copy the appropriate terminal settings file. +- Update launcher command-line help and launcher internals to use terminal-emulator terminology, normalize ConEmu task names, support `--` as the terminal argument separator, and route supported options to Windows Terminal or ConEmu as appropriate. +- Update `vendor/ConEmu.xml.default`, `vendor/windows_terminal_default_settings.json`, and related shell/profile files so default tasks and profiles call `init.cmd` and the new Git Bash/Mintty helpers. +- Update `vendor/profile.ps1`, `vendor/cmder.sh`, `vendor/psmodules/Cmder.ps1`, `vendor/clink.lua`, `vendor/lib/lib_base.cmd`, and `vendor/lib/lib_path.cmd` for more consistent shell startup, path handling, Git path discovery, prompt behavior, and Windows Terminal shell-integration escape sequences. See [#2896](https://github.com/cmderdev/cmder/pull/2896), [#3034](https://github.com/cmderdev/cmder/pull/3034), [#3053](https://github.com/cmderdev/cmder/pull/3053), and [#3082](https://github.com/cmderdev/cmder/pull/3082). +- Update `vendor/bin/cmder_diag.ps1`, `vendor/bin/cexec.cmd`, `vendor/bin/cmder_diag.cmd`, `vendor/bin/cmder_shell.cmd`, `vendor/bin/vscode_init.cmd`, `vendor/bin/vscode_init_args.cmd.default`, `vendor/bin/timer.cmd`, and `vendor/user_profile.cmd.default` for casing, cleanup, and `.cmd` naming consistency. +- Update `README.md` and `config/Readme.md` for the launcher argument changes and current configuration filenames. + +### Fixes + +- Fix launcher backup/overwrite handling for terminal emulator settings so user ConEmu or Windows Terminal settings are preserved instead of being overwritten. Fixes [#2940](https://github.com/cmderdev/cmder/issues/2940); see [#2988](https://github.com/cmderdev/cmder/pull/2988). +- Fix path enhancement handling in `vendor/lib/lib_path.cmd`, including safer recursive path enhancement and positioning behavior. See [#3034](https://github.com/cmderdev/cmder/pull/3034). +- Fix `git_locale` quoting and path handling around Git discovery and locale detection. See [#3037](https://github.com/cmderdev/cmder/pull/3037). +- Fix Windows Terminal Bash startup so `CMDER_ROOT` is set correctly for vendored and external Git Bash scenarios. +- Fix PowerShell 5.1 parsing of build helpers by keeping `scripts/utils.ps1` UTF-8 with BOM while preserving emoji output in workflow summaries. +- Fix Windows PowerShell 5.1 `scripts/build.ps1` invocation by initializing default paths after `$PSScriptRoot` is available, including `powershell.exe -File ./scripts/build.ps1 -Verbose -Compile`. +- Fix build summary markdown regressions by restoring emoji headers, per-artifact emoji icons, profile heading formatting, and real artifact links instead of directory-level artifact downloads. +- Fix generated workflow summaries so table values and workflow rows are clickable and pull-request branch names do not render as `NNNN/merge`. +- Fix update-vendor workflow PR summaries so they state whether a PR was created or updated, link the `update-vendor` branch, include useful auto-merge failure diagnostics, and keep protected-branch push failures actionable. +- Fix nested `init.cmd`/`user_init.cmd` startup behavior so repeated initialization is guarded and generated `init.bat` compatibility shims do not continually create new backup files. +- Fix command-script naming regressions by testing that only explicitly allowed `.bat` files are tracked. + ## [1.3.25](https://github.com/cmderdev/cmder/tree/v1.3.25) (2024-05-31) ### Changes diff --git a/Cmder.bat b/Cmder.bat index d48b0eefb..423b2c8d6 100644 --- a/Cmder.bat +++ b/Cmder.bat @@ -1,20 +1,66 @@ @echo off + SET CMDER_ROOT=%~dp0 -:: Remove Trailing '\' -@if "%CMDER_ROOT:~-1%" == "\" SET CMDER_ROOT=%CMDER_ROOT:~0,-1% - -if not exist "%CMDER_ROOT%\config\user_ConEmu.xml" ( - if not exist "%CMDER_ROOT%\config" mkdir "%CMDER_ROOT%\config" 2>nul - copy "%CMDER_ROOT%\vendor\ConEmu.xml.default" "%CMDER_ROOT%\config\user_ConEmu.xml" 1>nul - if %errorlevel% neq 0 ( - echo ERROR: CMDER Initialization has Failed - exit /b 1 - ) +set CMDER_TERMINAL=conemu +if exist "%CMDER_ROOT%\vendor\windows-terminal\windowsterminal.exe" ( + SET CMDER_TERMINAL=windows-terminal ) -if exist "%~1" ( - start %~dp0/vendor/conemu-maximus5/ConEmu.exe /Icon "%CMDER_ROOT%\icons\cmder.ico" /Title Cmder /LoadCfgFile "%~1" -) else ( - start %~dp0/vendor/conemu-maximus5/ConEmu.exe /Icon "%CMDER_ROOT%\icons\cmder.ico" /Title Cmder /LoadCfgFile "%CMDER_ROOT%\config\user_ConEmu.xml" +if NOT "%~1" == "" ( + SET CMDER_TERMINAL=%~1 + shift ) + +:: Remove Trailing '\' +if "%CMDER_ROOT:~-1%" == "\" SET CMDER_ROOT=%CMDER_ROOT:~0,-1% + +if not exist "%CMDER_ROOT%\config" md "%CMDER_ROOT%\config" 2>nul + +call :%CMDER_TERMINAL% +exit /b + +:conemu + if not exist "%CMDER_ROOT%\config\user_ConEmu.xml" ( + copy "%CMDER_ROOT%\vendor\ConEmu.xml.default" "%CMDER_ROOT%\config\user_ConEmu.xml" 1>nul + if %errorlevel% neq 0 ( + echo ERROR: CMDER Initialization has Failed + exit /b 1 + ) + ) + + if exist "%~1" ( + start %cmder_root%\vendor\conemu-maximus5\ConEmu.exe /Icon "%CMDER_ROOT%\icons\cmder.ico" /Title Cmder /LoadCfgFile "%~1" + ) else ( + start %cmder_root%\vendor\conemu-maximus5\ConEmu.exe /Icon "%CMDER_ROOT%\icons\cmder.ico" /Title Cmder /LoadCfgFile "%CMDER_ROOT%\config\user_ConEmu.xml" + ) + exit /b + +:windows-terminal + if not exist "%CMDER_ROOT%\vendor\windows-terminal\settings" md "%CMDER_ROOT%\vendor\windows-terminal\settings" 2>nul + if not exist "%CMDER_ROOT%\vendor\windows-terminal\.portable" echo "This makes this installation of Windows Terminal portable" >"%CMDER_ROOT%\vendor\windows-terminal\.portable" 2>nul + + if exist "%CMDER_ROOT%\config\user_windows_terminal_settings.json" ( + if not exist "%CMDER_ROOT%\vendor\windows-terminal\settings\settings.json" ( + echo "Copying user Windows Terminal settings to '%CMDER_ROOT%\vendor\windows-terminal\settings\settings.json'..." + copy "%CMDER_ROOT%\config\user_windows_terminal_settings.json" "%CMDER_ROOT%\vendor\windows-terminal\settings\settings.json" 1>nul + ) + ) else if not exist "%CMDER_ROOT%\config\user_windows_terminal_settings.json" ( + if not exist "%CMDER_ROOT%\config" mkdir "%CMDER_ROOT%\config" 2>nul + echo "Copying default Windows Terminal settings to '%CMDER_ROOT%\config'..." + copy "%CMDER_ROOT%\vendor\windows_terminal_default_settings.json" "%CMDER_ROOT%\config\user_windows_terminal_settings.json" 1>nul + echo "Copying default Windows Terminal settings to '%CMDER_ROOT%\vendor\windows-terminal\settings\settings.json'..." + copy "%CMDER_ROOT%\vendor\windows_terminal_default_settings.json" "%CMDER_ROOT%\vendor\windows-terminal\settings\settings.json" 1>nul + + if %errorlevel% neq 0 ( + echo ERROR: CMDER Initialization has Failed + exit /b 1 + ) + ) else if exist "%cmder_root%\vendor\windows-terminal\settings\settings.json" ( + copy "%cmder_root%\vendor\windows-terminal\settings\settings.json" "%CMDER_ROOT%\config\user_windows_terminal_settings.json" + ) + + start %cmder_root%\vendor\windows-terminal\windowsterminal.exe + exit /b + + diff --git a/README.md b/README.md index 7b8a6fda5..a1f7c8fc9 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The Cmder's user interface is also designed to be more eye pleasing, and you can 2. Extract the archive to a shared location. 3. (optional) Place your own executable files and custom app folders into the `%cmder_root%\bin`. See: [bin/README.md](./bin/Readme.md) - This folder to be injected into your PATH by default. - - See `/max_depth [1-5]` in 'Command Line Arguments for `init.bat`' table to add subdirectories recursively. + - See `/max_depth [1-5]` in 'Command Line Arguments for `init.cmd`' table to add subdirectories recursively. 4. (optional) Place your own custom app folders into the `%cmder_root%\opt`. See: [opt/README.md](./opt/Readme.md) - This folder will NOT be injected into your PATH so you have total control of what gets added. 5. Run `Cmder.exe` with `/C` command line argument. Example: `cmder.exe /C %userprofile%\cmder_config` @@ -41,7 +41,7 @@ The Cmder's user interface is also designed to be more eye pleasing, and you can - (optional) Place your own executable files and custom app folders into `%userprofile%\cmder_config\bin`. - This folder to be injected into your PATH by default. - - See `/max_depth [1-5]` in 'Command Line Arguments for `init.bat`' table to add subdirectories recursively. + - See `/max_depth [1-5]` in 'Command Line Arguments for `init.cmd`' table to add subdirectories recursively. - (optional) Place your own custom app folders into the `%user_profile%\cmder_config\opt`. - This folder will NOT be injected into your PATH so you have total control of what gets added. @@ -60,7 +60,7 @@ The Cmder's user interface is also designed to be more eye pleasing, and you can | `/SINGLE` | Start Cmder in single mode. | | `/START [start_path]` | Folder path to start in. | | `/TASK [task_name]` | Task to start after launch. | -| `/X [ConEmu extras pars]` | Forwards parameters to ConEmu | +| `-- [ConEmu extras pars]` | Forwards ALL remaining parameters to ConEmu. | ## Context Menu Integration @@ -167,10 +167,10 @@ Documentation is in the file for each setting. *Note: Pay attention to the quotes!* ``` - cmd /s /k ""%ConEmuDir%\..\init.bat" [ADD ARGS HERE]" + cmd /s /k ""%ConEmuDir%\..\init.cmd" [ADD ARGS HERE]" ``` -##### Command Line Arguments for `init.bat` +##### Command Line Arguments for `init.cmd` | Argument | Description | Default | | ----------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------- | @@ -230,7 +230,7 @@ Aliases defined using the `alias.bat` command will automatically be saved in the To make an alias and/or any other profile settings permanent add it to one of the following: -Note: These are loaded in this order by `$CMDER_ROOT/vendor/init.bat`. Anything stored in `%CMDER_ROOT%` will be a portable setting and will follow Cmder to another machine. +Note: These are loaded in this order by `$CMDER_ROOT/vendor/init.cmd`. Anything stored in `%CMDER_ROOT%` will be a portable setting and will follow Cmder to another machine. * `%CMDER_ROOT%\config\profile.d\*.cmd` and `\*.bat` * `%CMDER_ROOT%\config\user_aliases.cmd` @@ -298,12 +298,12 @@ Uncomment and edit the line below in the script to use Cmder config even when la # CMDER_ROOT=${USERPROFILE}/cmder # This is not required if launched from Cmder. ``` -### Customizing user sessions using `init.bat` custom arguments. +### Customizing user sessions using `init.cmd` custom arguments. -You can pass custom arguments to `init.bat` and use `cexec.cmd` in your `user_profile.cmd` to evaluate these +You can pass custom arguments to `init.cmd` and use `cexec.cmd` in your `user_profile.cmd` to evaluate these arguments then execute commands based on a particular flag being detected or not. -`init.bat` creates two shortcuts for using `cexec.cmd` in your profile scripts. +`init.cmd` creates two shortcuts for using `cexec.cmd` in your profile scripts. #### `%ccall%` - Evaluates flags, runs commands if found, and returns to the calling script and continues. @@ -332,7 +332,7 @@ To conditionally start `notepad.exe` when you start a specific `cmder` task: ```batch - cmd.exe /k ""%ConEmuDir%\..\init.bat" /startnotepad" + cmd.exe /k ""%ConEmuDir%\..\init.cmd" /startnotepad" ``` diff --git a/config/Readme.md b/config/Readme.md index c8befd282..d3620f968 100644 --- a/config/Readme.md +++ b/config/Readme.md @@ -1,9 +1,9 @@ ## Config -All config files must be in this folder. If there is no option to set this folder +All config files must be in this folder. If there is no option to set this folder directly, it has to be hardlinked. -* `user_aliases.cmd`: aliases in cmd; called from vendor\init.bat; autocreated from +* `user_aliases.cmd`: aliases in cmd; called from vendor\init.cmd; autocreated from `vendor\user_aliases.cmd.default`. * `*.lua`: clink completions and prompt filters; autoloaded after all prompt filter and clink completions are initialized; add your own. diff --git a/launcher/CmderLauncher.vcxproj b/launcher/CmderLauncher.vcxproj index 2662957c9..6d49ed943 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 b4609f169..adc877d4b 100644 --- a/launcher/src/CmderLauncher.cpp +++ b/launcher/src/CmderLauncher.cpp @@ -119,9 +119,9 @@ std::wstring NormalizeTaskName(std::wstring taskName) 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 }; @@ -129,7 +129,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr wchar_t cpuCfgPath[MAX_PATH] = { 0 }; wchar_t userCfgPath[MAX_PATH] = { 0 }; wchar_t defaultCfgPath[MAX_PATH] = { 0 }; - wchar_t conEmuPath[MAX_PATH] = { 0 }; + wchar_t terminalPath[MAX_PATH] = { 0 }; wchar_t configDirPath[MAX_PATH] = { 0 }; wchar_t userConfigDirPath[MAX_PATH] = { 0 }; wchar_t userBinDirPath[MAX_PATH] = { 0 }; @@ -140,22 +140,35 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr wchar_t legacyUserAliasesPath[MAX_PATH] = { 0 }; wchar_t args[MAX_PATH * 2 + 256] = { 0 }; wchar_t userConEmuCfgPath[MAX_PATH] = { 0 }; - + wchar_t windowsTerminalDir[MAX_PATH] = { 0 }; + wchar_t conEmuDir[MAX_PATH] = { 0 }; + wchar_t winDir[MAX_PATH] = { 0 }; + wchar_t vendorDir[MAX_PATH] = { 0 }; + wchar_t initCmd[MAX_PATH] = { 0 }; + wchar_t initPowerShell[MAX_PATH] = { 0 }; + wchar_t initBash[MAX_PATH] = { 0 }; + wchar_t initMintty[MAX_PATH] = { 0 }; + wchar_t vendoredGit[MAX_PATH] = { 0 }; + wchar_t amdx64Git[MAX_PATH] = { 0 }; + wchar_t x86Git[MAX_PATH] = { 0 }; + wchar_t programFiles[MAX_PATH] = { 0 }; + wchar_t programFilesX86[MAX_PATH] = { 0 }; + wchar_t minTTYPath[MAX_PATH] = { 0 }; std::wstring cmderStart = path; std::wstring cmderTask = taskName; cmderTask = NormalizeTaskName(cmderTask); std::wstring cmderTitle = title; - std::wstring cmderConEmuArgs = conemu_args; + std::wstring cmderTerminalArgs = conemu_args; std::copy(cfgRoot.begin(), cfgRoot.end(), userConfigDirPath); userConfigDirPath[cfgRoot.length()] = 0; 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); @@ -179,8 +192,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr { PathCombine(userProfilePath, configDirPath, L"user_profile.cmd"); - char *lPr = (char *)malloc(MAX_PATH); - char *pR = (char *)malloc(MAX_PATH); + char* lPr = (char*)malloc(MAX_PATH); + char* pR = (char*)malloc(MAX_PATH); size_t i; wcstombs_s(&i, lPr, (size_t)MAX_PATH, legacyUserProfilePath, (size_t)MAX_PATH); @@ -197,8 +210,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr { PathCombine(userAliasesPath, configDirPath, L"user_aliases.cmd"); - char *lPr = (char *)malloc(MAX_PATH); - char *pR = (char *)malloc(MAX_PATH); + char* lPr = (char*)malloc(MAX_PATH); + char* pR = (char*)malloc(MAX_PATH); size_t i; wcstombs_s(&i, lPr, (size_t)MAX_PATH, legacyUserAliasesPath, (size_t)MAX_PATH); @@ -235,8 +248,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr { PathCombine(userProfilePath, userConfigDirPath, L"user_profile.cmd"); - char *lPr = (char *)malloc(MAX_PATH); - char *pR = (char *)malloc(MAX_PATH); + char* lPr = (char*)malloc(MAX_PATH); + char* pR = (char*)malloc(MAX_PATH); size_t i; wcstombs_s(&i, lPr, (size_t)MAX_PATH, legacyUserProfilePath, (size_t)MAX_PATH); @@ -253,8 +266,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr { PathCombine(userAliasesPath, userConfigDirPath, L"user_aliases.cmd"); - char *lPr = (char *)malloc(MAX_PATH); - char *pR = (char *)malloc(MAX_PATH); + char* lPr = (char*)malloc(MAX_PATH); + char* pR = (char*)malloc(MAX_PATH); size_t i; wcstombs_s(&i, lPr, (size_t)MAX_PATH, legacyUserAliasesPath, (size_t)MAX_PATH); @@ -264,71 +277,158 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr } } - // Set path to vendored ConEmu config file - PathCombine(cfgPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu.xml"); + PathCombine(vendorDir, exeDir, L"vendor"); + PathCombine(windowsTerminalDir, vendorDir, L"windows-terminal"); + PathCombine(conEmuDir, vendorDir, L"conemu-maximus5"); + GetEnvironmentVariable(L"WINDIR", winDir, MAX_PATH); - // Set path to Cmder default ConEmu config file - PathCombine(defaultCfgPath, exeDir, L"vendor\\ConEmu.xml.default"); + if (PathFileExists(windowsTerminalDir)) + { + // Set path to vendored ConEmu config file + PathCombine(cfgPath, windowsTerminalDir, L"settings\\settings.json"); - // Check for machine-specific then user config source file. - PathCombine(cpuCfgPath, userConfigDirPath, L"ConEmu-%COMPUTERNAME%.xml"); - ExpandEnvironmentStrings(cpuCfgPath, cpuCfgPath, sizeof(cpuCfgPath) / sizeof(cpuCfgPath[0])); + // Set path to Cmder default ConEmu config file + PathCombine(defaultCfgPath, exeDir, L"vendor\\windows_terminal_default_settings.json"); - // Set path to Cmder user ConEmu config file - PathCombine(userCfgPath, userConfigDirPath, L"user-ConEmu.xml"); + // Check for machine-specific then user config source file. + PathCombine(cpuCfgPath, userConfigDirPath, L"windows_terminal_%COMPUTERNAME%_settings.json"); + ExpandEnvironmentStrings(cpuCfgPath, cpuCfgPath, sizeof(cpuCfgPath) / sizeof(cpuCfgPath[0])); - if ( PathFileExists(cpuCfgPath) || use_user_cfg == false ) // config/ConEmu-%COMPUTERNAME%.xml file exists or /m was specified on command line, use machine specific config. + // Set path to Cmder user ConEmu config file + PathCombine(userCfgPath, userConfigDirPath, L"user_windows_terminal_settings.json"); + } + else if (PathFileExists(conEmuDir)) + { + // Set path to vendored ConEmu config file + PathCombine(cfgPath, conEmuDir, L"ConEmu.xml"); + + // Set path to Cmder default ConEmu config file + PathCombine(defaultCfgPath, exeDir, L"vendor\\ConEmu.xml.default"); + + // Check for machine-specific then user config source file. + PathCombine(cpuCfgPath, userConfigDirPath, L"ConEmu-%COMPUTERNAME%.xml"); + ExpandEnvironmentStrings(cpuCfgPath, cpuCfgPath, sizeof(cpuCfgPath) / sizeof(cpuCfgPath[0])); + + // Set path to Cmder user ConEmu config file + PathCombine(userCfgPath, userConfigDirPath, L"user-ConEmu.xml"); + } + + if (wcscmp(cpuCfgPath, L"") != 0 && (PathFileExists(cpuCfgPath) || use_user_cfg == false)) // config/[host specific terminal emulator config] file exists or /m was specified on command line, use machine specific config. { if (cfgRoot.length() == 0) // '/c [path]' was NOT specified { - if (PathFileExists(cfgPath)) // vendor/conemu-maximus5/ConEmu.xml file exists, copy vendor/conemu-maximus5/ConEmu.xml to config/ConEmu-%COMPUTERNAME%.xml. + if (PathFileExists(cfgPath)) // [terminal emulator config] file exists, copy [terminal emulator config] to config/user_[terminal emulator config] file to backup any settings changes from previous sessions. { if (!CopyFile(cfgPath, cpuCfgPath, FALSE)) { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml! Access Denied." - : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); + if (PathFileExists(windowsTerminalDir)) { + 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_terminal_%COMPUTERNAME%_settigns.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml! Access Denied." + : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } } } - else // vendor/conemu-maximus5/ConEmu.xml config file does not exist, copy config/ConEmu-%COMPUTERNAME%.xml to vendor/conemu-maximus5/ConEmu.xml file + else // [terminal emulator config] file does not exist, copy config/[host specific terminal emulator config] file to [terminal emulator config] file { if (!CopyFile(cpuCfgPath, cfgPath, FALSE)) { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy config/ConEmu-%COMPUTERNAME%.xml file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." - : L"Failed to copy config/ConEmu-%COMPUTERNAME%.xml file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); + 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." + : L"Failed to copy config/windows_terminal_%COMPUTERNAME%_settings.json file to vendor/windows-terminal/settings/settings.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy config/ConEmu-%COMPUTERNAME%.xml file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." + : L"Failed to copy config/ConEmu-%COMPUTERNAME%.xml file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } } } } - else // '/c [path]' was specified, don't copy anything and use existing conemu-%COMPUTERNAME%.xml to start comemu. + } + else if (wcscmp(userCfgPath, L"") != 0 && PathFileExists(userCfgPath)) // config/user[terminal emulator config] file exists, use it. + { + if (cfgRoot.length() == 0) // '/c [path]' was NOT specified { - if (use_user_cfg == false && PathFileExists(cfgPath) && !PathFileExists(cpuCfgPath)) // vendor/conemu-maximus5/ConEmu.xml file exists, copy vendor/conemu-maximus5/ConEmu.xml to config/ConEmu-%COMPUTERNAME%.xml. + if (PathFileExists(cfgPath)) // [terminal emulator config] file exists, copy [terminal emulator config] to config/user_[terminal emulator config] file to backup any settings changes from previous sessions. { - if (!CopyFile(cfgPath, cpuCfgPath, FALSE)) + if (!CopyFile(cfgPath, userCfgPath, FALSE)) { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml! Access Denied." - : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/ConEmu-%COMPUTERNAME%.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); + if (PathFileExists(windowsTerminalDir)) + { + 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_terminal_settigns.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml! Access Denied." + : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } } } - - PathCombine(userConEmuCfgPath, userConfigDirPath, L"ConEmu-%COMPUTERNAME%.xml"); - ExpandEnvironmentStrings(userConEmuCfgPath, userConEmuCfgPath, sizeof(userConEmuCfgPath) / sizeof(userConEmuCfgPath[0])); + else // [terminal emulator config] file does not exist, copy config/user_[terminal emulator config] file to [terminal emulator config] file + { + if (!CopyFile(userCfgPath, cfgPath, FALSE)) + { + if (PathFileExists(windowsTerminalDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy config/user_windows_terminal_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied." + : L"Failed to copy config/user_windows_terminal_settings.json file to vendor/windows-terminal/settings/settings.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy config/user-conemu.xml file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." + : L"Failed to copy config/user-conemu.xml file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + } + } + } + else if (!PathFileExists(windowsTerminalDir)) { // '/c [path]' was specified, don't copy anything and use existing user_[terminal emulator config] file. + PathCombine(userConEmuCfgPath, userConfigDirPath, L"user-ConEmu.xml"); } } - else if (PathFileExists(userCfgPath)) // config/user_conemu.xml exists, use it. + else if (cfgRoot.length() == 0) // '/c [path]' was NOT specified { - if (cfgRoot.length() == 0) // '/c [path]' was NOT specified + if (PathFileExists(cfgPath)) // [terminal emulator config] file exists, copy [terminal emulator config] file to config/user_[terminal emulator config] file. { - if (PathFileExists(cfgPath)) // vendor/conemu-maximus5/ConEmu.xml exists, copy vendor/conemu-maximus5/ConEmu.xml to config/user_conemu.xml. + if (!CopyFile(cfgPath, userCfgPath, FALSE)) { - if (!CopyFile(cfgPath, userCfgPath, FALSE)) + if (PathFileExists(windowsTerminalDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settings.json! Access Denied." + : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settigns.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) { MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) @@ -337,128 +437,198 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr exit(1); } } - else // vendor/conemu-maximus5/ConEmu.xml does not exist, copy config/user-conemu.xml to vendor/conemu-maximus5/ConEmu.xml + else // vendor/[terminal emulator config].default config exists, copy Cmder vendor/[terminal emulator config].default file to [terminal emulator config] file. { - if (!CopyFile(userCfgPath, cfgPath, FALSE)) + if (!CopyFile(defaultCfgPath, cfgPath, FALSE)) { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy config/user-conemu.xml file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." - : L"Failed to copy config/user-conemu.xml file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); + if (PathFileExists(windowsTerminalDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied." + : L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to vendor/windows-terminal/settings/settigns.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." + : L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } } } } - else // '/c [path]' was specified, don't copy anything and use existing user_conemu.xml to start comemu. + else if (!CopyFile(defaultCfgPath, cfgPath, FALSE) && PathFileExists(conEmuDir)) { - PathCombine(userConEmuCfgPath, userConfigDirPath, L"user-ConEmu.xml"); + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." + : L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); } } - else if (cfgRoot.length() == 0) // '/c [path]' was NOT specified + else if (wcscmp(cfgPath, L"") != 0 && PathFileExists(cfgPath)) // This is a first time Cmder.exe run and [terminal emulator config] file exists, copy [terminal emulator config] file to config/user_[terminal emulator config] file. { - if (PathFileExists(cfgPath)) // vendor/conemu-maximus5/ConEmu.xml exists, copy vendor/conemu-maximus5/ConEmu.xml to config/user_conemu.xml + if (!CopyFile(cfgPath, userCfgPath, FALSE)) { - if (!CopyFile(cfgPath, userCfgPath, FALSE)) + if (PathFileExists(windowsTerminalDir)) { MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml! Access Denied." - : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml!", MB_TITLE, MB_ICONSTOP); + ? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settings_settings.json! Access Denied." + : L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settings_settigns.json!", MB_TITLE, MB_ICONSTOP); exit(1); } - else // vendor/ConEmu.xml.default config exists, copy Cmder vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml. - { - if (!CopyFile(defaultCfgPath, cfgPath, FALSE)) - { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." - : L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); - } - } - } - else { - if (!CopyFile(defaultCfgPath, cfgPath, FALSE)) + else { MessageBox(NULL, (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied." - : L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml! Access Denied." + : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml!", MB_TITLE, MB_ICONSTOP); exit(1); } } - } - else if (PathFileExists(cfgPath)) // vendor/conemu-maximus5/ConEmu.xml exists, copy vendor/conemu-maximus5/ConEmu.xml to config/user_conemu.xml - { - if (!CopyFile(cfgPath, userCfgPath, FALSE)) - { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml! Access Denied." - : L"Failed to copy vendor/conemu-maximus5/ConEmu.xml file to config/user-conemu.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); - } PathCombine(userConEmuCfgPath, userConfigDirPath, L"user-ConEmu.xml"); } - else // '/c [path]' was specified and 'vendor/ConEmu.xml.default' config exists, copy Cmder 'vendor/ConEmu.xml.default' file to '[user specified path]/config/user_ConEmu.xml'. + else if (wcscmp(defaultCfgPath, L"") != 0) // '/c [path]' was specified and 'vendor/[terminal emulator config].default' config exists, copy Cmder 'vendor/[terminal emulator config].default' file to '[user specified path]/config/user_[terminal emulator config]'. { if ( ! CopyFile(defaultCfgPath, userCfgPath, FALSE)) { - MessageBox(NULL, - (GetLastError() == ERROR_ACCESS_DENIED) - ? L"Failed to copy vendor/ConEmu.xml.default file to [user specified path]/config/user_ConEmu.xml! Access Denied." - : L"Failed to copy vendor/ConEmu.xml.default file to [user specified path]/config/user_ConEmu.xml!", MB_TITLE, MB_ICONSTOP); - exit(1); + if (PathFileExists(windowsTerminalDir)) + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to [user specified path]/config/user_windows_terminal_settings.json! Access Denied." + : L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to [user specified path]/config/user_windows_terminal_settings.json!", MB_TITLE, MB_ICONSTOP); + exit(1); + } + else + { + MessageBox(NULL, + (GetLastError() == ERROR_ACCESS_DENIED) + ? L"Failed to copy vendor/ConEmu.xml.default file to [user specified path]/config/user_ConEmu.xml! Access Denied." + : L"Failed to copy vendor/ConEmu.xml.default file to [user specified path]/config/user_ConEmu.xml!", MB_TITLE, MB_ICONSTOP); + exit(1); + } } PathCombine(userConEmuCfgPath, userConfigDirPath, L"user-ConEmu.xml"); } + GetEnvironmentVariable(L"ProgramFiles", programFiles, MAX_PATH); + GetEnvironmentVariable(L"ProgramFiles(x86)", programFilesX86, MAX_PATH); + + PathCombine(vendoredGit, vendorDir, L"git-for-windows"); + PathCombine(amdx64Git, programFiles, L"Git"); + PathCombine(x86Git, programFilesX86, L"Git"); + SYSTEM_INFO sysInfo; GetNativeSystemInfo(&sysInfo); - if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + if (PathFileExists(windowsTerminalDir)) { - PathCombine(conEmuPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu64.exe"); + PathCombine(terminalPath, exeDir, L"vendor\\windows-terminal\\WindowsTerminal.exe"); } - else + else if (PathFileExists(conEmuDir)) { - PathCombine(conEmuPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu.exe"); + swprintf_s(args, L"%s /Icon \"%s\"", args, icoPath); + swprintf_s(args, L"%s /title \"%s\"", args, cmderTitle.c_str()); + PathCombine(terminalPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu64.exe"); } + else + { + PathCombine(terminalPath, winDir, L"system32\\cmd.exe"); - swprintf_s(args, L"%s /Icon \"%s\"", args, icoPath); + if (streqi(cmderTask.c_str(), L"powershell")) + { + PathCombine(terminalPath, winDir, L"System32\\WindowsPowerShell\\v1.0\\powershell.exe"); + } + /* + else if (streqi(cmderTask.c_str(), L"mintty")) + { + if (PathFileExists(vendoredGit)) + { + PathCombine(terminalPath, vendoredGit, L"git-bash.exe"); + } + else if (PathFileExists(amdx64Git)) + { + PathCombine(terminalPath, amdx64Git, L"git-bash.exe"); + } + else if (PathFileExists(x86Git)) + { + PathCombine(terminalPath, x86Git, L"git-bash.exe"); + } + } + */ + } if (!streqi(cmderStart.c_str(), L"")) { - swprintf_s(args, L"%s /dir \"%s\"", args, cmderStart.c_str()); + if (PathFileExists(windowsTerminalDir)) { + swprintf_s(args, L"%s -d \"%s\"", args, cmderStart.c_str()); + } + else + { + swprintf_s(args, L"%s /dir \"%s\"", args, cmderStart.c_str()); + } } if (is_single_mode) { - swprintf_s(args, L"%s /single", args); - } - - if (!streqi(cmderTitle.c_str(), L"")) - { - swprintf_s(args, L"%s /title \"%s\"", args, cmderTitle.c_str()); + if (!PathFileExists(windowsTerminalDir)) { + swprintf_s(args, L"%s /single", args); + } } if (cfgRoot.length() != 0) { - swprintf_s(args, L"%s -loadcfgfile \"%s\"", args, userConEmuCfgPath); + if (!PathFileExists(windowsTerminalDir)) { + swprintf_s(args, L"%s -loadcfgfile \"%s\"", args, userConEmuCfgPath); + } } - if (!streqi(cmderConEmuArgs.c_str(), L"")) + if (!streqi(cmderTerminalArgs.c_str(), L"")) { - swprintf_s(args, L"%s %s", args, cmderConEmuArgs.c_str()); + swprintf_s(args, L"%s %s", args, cmderTerminalArgs.c_str()); } // The `/run` arg and its value MUST be the last arg of ConEmu // see : https://conemu.github.io/en/ConEmuArgs.html // > This must be the last used switch (excepting -new_console and -cur_console) + PathCombine(initCmd, vendorDir, L"init.cmd"); + PathCombine(initPowerShell, vendorDir, L"profile.ps1"); + PathCombine(initBash, vendorDir, L"start_git_bash.cmd"); + PathCombine(initMintty, vendorDir, L"start_git_mintty.cmd"); + if (!streqi(cmderTask.c_str(), L"")) { - swprintf_s(args, L"%s /run {%s}", args, cmderTask.c_str()); + if (PathFileExists(windowsTerminalDir)) { + swprintf_s(args, L"%s -p \"%s\"", args, cmderTask.c_str()); + } + else if (PathFileExists(conEmuDir)) + { + swprintf_s(args, L"%s /run {%s}", args, cmderTask.c_str()); + } + else + { + if (streqi(cmderTask.c_str(), L"powershell")) + { + swprintf_s(args, L"%s -ExecutionPolicy Bypass -NoLogo -NoProfile -NoExit -Command \"Invoke-Expression 'Import-Module ''%s'''\"", args, initPowerShell); + } + else if (streqi(cmderTask.c_str(), L"bash")) + { + swprintf_s(args, L"%s /c \"%s\"", args, initBash); + } + else if (streqi(cmderTask.c_str(), L"mintty")) + { + swprintf_s(args, L"%s /c \"%s\"", args, initMintty); + } + else if (streqi(cmderTask.c_str(), L"cmder")) + { + swprintf_s(args, L"%s /k \"%s\"", args, initCmd); + } + } } SetEnvironmentVariable(L"CMDER_ROOT", exeDir); @@ -468,18 +638,52 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr SetEnvironmentVariable(L"CMDER_USER_BIN", userBinDirPath); } + // Try to find m'intty.exe' so ConEmu can launch using %MINTTY_EXE% in external Git for Cmder Mini. + // See: https://github.com/Maximus5/ConEmu/issues/2559 for why this is commented. + + /* + if (PathFileExists(vendoredGit)) + { + PathCombine(minTTYPath, vendoredGit, L"usr\\bin\\mintty.exe"); + SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath); + } + else if (PathFileExists(amdx64Git)) + { + PathCombine(minTTYPath, amdx64Git, L"usr\\bin\\mintty.exe"); + SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath); + } + else if (PathFileExists(x86Git)) + { + PathCombine(minTTYPath, x86Git, L"usr\\bin\\mintty.exe"); + SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath); + } + */ + // Ensure EnvironmentVariables are propagated. 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; - if (!CreateProcess(conEmuPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) { - MessageBox(NULL, _T("Unable to create the ConEmu process!"), _T("Error"), MB_OK); + + if (!CreateProcess(terminalPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) + { + if (PathFileExists(windowsTerminalDir)) + { + MessageBox(NULL, _T("Unable to create the Windows Terminal process!"), _T("Error"), MB_OK); + } + else if (PathFileExists(conEmuDir)) + { + MessageBox(NULL, _T("Unable to create the ConEmu process!"), _T("Error"), MB_OK); + } + else + { + MessageBox(NULL, _T("Unable to create the Cmd process!"), _T("Error"), MB_OK); + } return; } } @@ -534,11 +738,11 @@ void RegisterShellMenu(std::wstring opt, wchar_t* keyBaseName, std::wstring cfgR wchar_t commandStr[MAX_PATH + 20] = { 0 }; wchar_t baseCommandStr[MAX_PATH + 20] = { 0 }; - if (!single) { - swprintf_s(baseCommandStr, L"\"%s\"", exePath); + if (single) { + swprintf_s(baseCommandStr, L"\"%s\" /single", exePath); } else { - swprintf_s(baseCommandStr, L"\"%s\" /single", exePath); + swprintf_s(baseCommandStr, L"\"%s\"", exePath); } if (cfgRoot.length() == 0) // '/c [path]' was NOT specified @@ -596,7 +800,7 @@ struct cmderOptions std::wstring cmderTitle = L"Cmder"; std::wstring cmderIcon = L""; std::wstring cmderRegScope = L"USER"; - std::wstring cmderConEmuArgs = L""; + std::wstring cmderTerminalArgs = L""; bool cmderSingle = false; bool cmderUserCfg = true; bool registerApp = false; @@ -610,11 +814,22 @@ cmderOptions GetOption() LPWSTR *szArgList; int argCount; + wchar_t windowsTerminalDir[MAX_PATH] = { 0 }; + wchar_t conEmuDir[MAX_PATH] = { 0 }; + wchar_t vendorDir[MAX_PATH] = { 0 }; + wchar_t exeDir[MAX_PATH] = { 0 }; + + GetModuleFileName(NULL, exeDir, sizeof(exeDir)); + PathRemoveFileSpec(exeDir); + + PathCombine(vendorDir, exeDir, L"vendor"); + PathCombine(windowsTerminalDir, vendorDir, L"windows-terminal"); + PathCombine(conEmuDir, vendorDir, L"ConEmu-Maximus5"); + szArgList = CommandLineToArgvW(GetCommandLine(), &argCount); for (int i = 1; i < argCount; i++) { - // MessageBox(NULL, szArgList[i], L"Arglist contents", MB_OK); if (cmderOptions.error == false) { if (_wcsicmp(L"/c", szArgList[i]) == 0) @@ -651,26 +866,31 @@ cmderOptions GetOption() MessageBox(NULL, szArgList[i + 1], L"/START - Folder does not exist!", MB_OK); } } - else if (_wcsicmp(L"/task", szArgList[i]) == 0) + else if (_wcsicmp(L"/task", szArgList[i]) == 0 || PathFileExists(windowsTerminalDir) || PathFileExists(conEmuDir)) { cmderOptions.cmderTask = szArgList[i + 1]; i++; } - else if (_wcsicmp(L"/title", szArgList[i]) == 0) + else if ((_wcsicmp(L"bash", szArgList[i]) == 0 || _wcsicmp(L"powershell", szArgList[i]) == 0) || PathFileExists(windowsTerminalDir) || PathFileExists(conEmuDir)) + { + cmderOptions.cmderTask = szArgList[i]; + i++; + } + else if (_wcsicmp(L"/title", szArgList[i]) == 0 && !PathFileExists(windowsTerminalDir) && PathFileExists(conEmuDir)) { cmderOptions.cmderTitle = szArgList[i + 1]; i++; } - else if (_wcsicmp(L"/icon", szArgList[i]) == 0) + else if (_wcsicmp(L"/icon", szArgList[i]) == 0 && !PathFileExists(windowsTerminalDir) && PathFileExists(conEmuDir)) { cmderOptions.cmderIcon = szArgList[i + 1]; i++; } - else if (_wcsicmp(L"/single", szArgList[i]) == 0) + else if (_wcsicmp(L"/single", szArgList[i]) == 0 && !PathFileExists(windowsTerminalDir) && PathFileExists(conEmuDir)) { cmderOptions.cmderSingle = true; } - else if (_wcsicmp(L"/m", szArgList[i]) == 0) + else if (_wcsicmp(L"/m", szArgList[i]) == 0 && !PathFileExists(windowsTerminalDir) && PathFileExists(conEmuDir)) { cmderOptions.cmderUserCfg = false; } @@ -703,7 +923,7 @@ cmderOptions GetOption() /* Used for passing arguments to conemu prog */ else if (_wcsicmp(L"/x", szArgList[i]) == 0) { - cmderOptions.cmderConEmuArgs = szArgList[i + 1]; + cmderOptions.cmderTerminalArgs = szArgList[i + 1]; i++; } /* Bare double dash, remaining commandline is for conemu */ @@ -713,7 +933,7 @@ cmderOptions GetOption() auto doubledash = cmdline.find(L" -- "); if (doubledash != std::string::npos) { - cmderOptions.cmderConEmuArgs = cmdline.substr(doubledash + 4); + cmderOptions.cmderTerminalArgs = cmdline.substr(doubledash + 4); } break; } @@ -740,7 +960,11 @@ cmderOptions GetOption() cmderOptions.error = true; } } + } + if (!PathFileExists(windowsTerminalDir) && !PathFileExists(conEmuDir) && streqi(cmderOptions.cmderTask.c_str(), L"")) + { + cmderOptions.cmderTask = L"cmder"; } if (cmderOptions.error == true) @@ -769,12 +993,29 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, cmderOptions cmderOptions = GetOption(); + wchar_t windowsTerminalDir[MAX_PATH] = { 0 }; + wchar_t exeDir[MAX_PATH] = { 0 }; + + GetModuleFileName(NULL, exeDir, sizeof(exeDir)); + PathRemoveFileSpec(exeDir); + PathCombine(windowsTerminalDir, exeDir, L"vendor\\windows-terminal"); + if (cmderOptions.registerApp == true) { - RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); - RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_LISTITEM, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); - RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); - RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_LISTITEM, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); + if (PathFileExists(windowsTerminalDir)) + { + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_LISTITEM, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_LISTITEM, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle); + } + else + { + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, false); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_LISTITEM, cmderOptions.cmderCfgRoot, false); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, false); + RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_LISTITEM, cmderOptions.cmderCfgRoot, false); + } } else if (cmderOptions.unRegisterApp == true) { @@ -789,7 +1030,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, } else { - StartCmder(cmderOptions.cmderStart, cmderOptions.cmderSingle, cmderOptions.cmderTask, cmderOptions.cmderTitle, cmderOptions.cmderIcon, cmderOptions.cmderCfgRoot, cmderOptions.cmderUserCfg, cmderOptions.cmderConEmuArgs); + 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 5960625a6..8602089e0 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 088730753..d8feb4d8b 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 /c [CMDER User Root Path]\n /task [ConEmu Task Name]\n /icon [CMDER Icon Path]\n [/start [Start in Path] | [Start in Path]]\n /single\n /m\n /x [ConEmu extra arguments]\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/packignore b/packignore index 1fd4315d4..7059f3cc3 100644 --- a/packignore +++ b/packignore @@ -23,5 +23,6 @@ appveyor.yml vendor\cmder.sh vendor\git-prompt.sh config\user-* +config\user_* clink_history* *.log diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 000000000..9c85306e0 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,51 @@ +# Scripts + +This folder contains helper scripts used to: + +- Update sources for vendor components. +- Build the launcher and download vendor components. +- Package release archives. + +The scripts share a small library of helper functions located in `utils.ps1`. + +**Overview** +- **build.ps1**: Builds the Cmder distribution. It downloads and unpacks vendor components, preserves user configuration (ConEmu / Windows Terminal), prepares portable components, and can optionally compile the launcher when run with the `-Compile` switch. It supports skipping vendor downloads (`-NoVendor`), selecting which terminal to include (`-Terminal`), and customizing paths (`-sourcesPath`, `-saveTo`, `-launcher`, `-config`). The script uses `msbuild` when compiling the launcher and utilities like `7z` for extraction. +- **pack.ps1**: Packages the built distribution into the distributable archives declared in `package-profiles.json`. Output is grouped by terminal profile under `build//`. +- **package-profiles.json**: Central configuration for the terminal profiles, output folders, included vendors, and package variants used by `build.ps1`, `pack.ps1`, and the CI workflow. +- **update.ps1**: Updates what will be bundled by `build.ps1`. + +**Shared helpers** +- **utils.ps1**: A shared library of helper functions used by the other scripts. Common utilities include: + - environment and executable checks (e.g. `Ensure-Executable`, `Ensure-Exists`) + - download and archive helpers (e.g. `Download-File`, `Extract-Archive`) + - file operations and cleanup (e.g. `Delete-Existing`, `Flatten-Directory`) + - build helpers (e.g. `Create-RC`, `Get-VersionStr`) + - logging and verbosity helpers + +The scripts dot-source `utils.ps1` at runtime to reuse the above functions and centralize error handling, logging, and platform-specific behavior. + +**Packaging variations** +- Edit [`scripts/package-profiles.json`](./package-profiles.json) to rename, add, or remove package variations. +- Each profile defines a default `includedVendors` list for the full variants, and each package entry can override that list when a variation needs a different vendor set. +- If a package entry omits `includedVendors`, it inherits the profile default. +- `outputFolder` controls the `build//` directory, while each package entry's `name` controls the archive filename written inside that folder. +- `pack.ps1` also writes a single root `build/hashes.txt` manifest containing all package hashes for the run. + +**Quick examples** +- Run a default build (downloads vendors and prepares distribution): + +```powershell +.\build.ps1 -Verbose +``` + +- Build and compile the launcher (requires `msbuild`/VS build tools): + +```powershell +.\build.ps1 -Compile -Verbose +``` + +- Compile but skip vendor downloads (quick launcher build): + +```powershell +.\build.ps1 -Compile -NoVendor -Verbose +``` diff --git a/scripts/build.ps1 b/scripts/build.ps1 index cfce5fa8d..1944a01c3 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -21,7 +21,7 @@ Skip all downloads and only build launcher. .EXAMPLE - .\build -verbose + .\build.ps1 -Verbose Execute the build and see what's going on. .EXAMPLE @@ -33,35 +33,58 @@ Samuel Vasko, Jack Bennett Part of the Cmder project. .LINK - http://cmder.app/ - Project Home + https://github.com/cmderdev/cmder - Project Home #> [CmdletBinding(SupportsShouldProcess = $true)] Param( # CmdletBinding will give us; - # -verbose switch to turn on logging and + # -Verbose switch to turn on logging and # -whatif switch to not actually make changes # Path to the vendor configuration source file - [string]$sourcesPath = "$PSScriptRoot\..\vendor\sources.json", + [string]$sourcesPath, # Vendor folder location - [string]$saveTo = "$PSScriptRoot\..\vendor\", + [string]$saveTo, # Launcher folder location - [string]$launcher = "$PSScriptRoot\..\launcher", + [string]$launcher, # Config folder location - [string]$config = "$PSScriptRoot\..\config", + [string]$config, # 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', + # Build launcher if you have MSBuild tools installed [switch]$Compile ) # Get the scripts and Cmder root dirs we are building in. -$cmder_root = Resolve-Path "$PSScriptRoot\.." +$cmder_root = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path + +if ([string]::IsNullOrWhiteSpace($sourcesPath)) { + $sourcesPath = Join-Path $cmder_root 'vendor\sources.json' +} + +if ([string]::IsNullOrWhiteSpace($saveTo)) { + $saveTo = Join-Path $cmder_root 'vendor' +} + +if ([string]::IsNullOrWhiteSpace($launcher)) { + $launcher = Join-Path $cmder_root 'launcher' +} + +if ([string]::IsNullOrWhiteSpace($config)) { + $config = Join-Path $cmder_root 'config' +} + +if (-not $saveTo.EndsWith([System.IO.Path]::DirectorySeparatorChar) -and -not $saveTo.EndsWith([System.IO.Path]::AltDirectorySeparatorChar)) { + $saveTo += [System.IO.Path]::DirectorySeparatorChar +} # Dot source util functions into this scope . "$PSScriptRoot\utils.ps1" @@ -95,6 +118,7 @@ if (-not $noVendor) { # Get the vendor sources $sources = Get-Content $sourcesPath | Out-String | ConvertFrom-Json + $includedVendors = Get-CmderTerminalIncludedVendors -Terminal $Terminal Push-Location -Path $saveTo New-Item -Type Directory -Path (Join-Path $saveTo "/tmp/") -ErrorAction SilentlyContinue >$null @@ -113,15 +137,31 @@ if (-not $noVendor) { } else { $ConEmuXml = "" } - # Kill ssh-agent.exe if it is running from the $env:cmder_root we are building + # Preserve modified (by user) Windows Terminal setting file + if ($config -ne "") { + $WinTermSettingsJson = Join-Path $saveTo "windows-terminal\settings\settings.json" + if (Test-Path $WinTermSettingsJson -pathType leaf) { + $WinTermSettingsJsonSave = Join-Path $config "windows_terminal_settings.json" + Write-Verbose "Backup '$WinTermSettingsJson' to '$WinTermSettingsJsonSave'" + Copy-Item $WinTermSettingsJson $WinTermSettingsJsonSave + } + else { $WinTermSettingsJson = "" } + } + else { $WinTermSettingsJson = "" } + + # Kill ssh-agent.exe if it is running from the Cmder root we are building 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_root.Replace('\', '\\')) { Write-Verbose $("Stopping " + $ssh_agent.path + "!") Stop-Process $ssh_agent.id } } foreach ($s in $sources) { + if ($includedVendors -notcontains $s.name) { + continue + } + Write-Verbose "Getting vendored $($s.name) $($s.version)..." # We do not care about the extensions/type of archive @@ -132,6 +172,16 @@ if (-not $noVendor) { Download-File -Url $s.url -File $vend\$tempArchive -ErrorAction Stop Extract-Archive $tempArchive $s.name + # 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 + } + if ((Get-ChildItem $s.name).Count -eq 1) { Flatten-Directory($s.name) } @@ -146,6 +196,12 @@ if (-not $noVendor) { Copy-Item $ConEmuXmlSave $ConEmuXml } + # Restore Windows Terminal user configuration + if ($WinTermSettingsJson -ne "") { + Write-Verbose "Restore '$WinTermSettingsJsonSave' to '$WinTermSettingsJson'" + Copy-Item $WinTermSettingsJsonSave $WinTermSettingsJson + } + # Put vendor\cmder.sh in /etc/profile.d so it runs when we start bash or mintty if ( (Test-Path $($saveTo + "git-for-windows/etc/profile.d") ) ) { Write-Verbose "Adding cmder.sh /etc/profile.d" diff --git a/scripts/pack.ps1 b/scripts/pack.ps1 index da6fc6e0d..4b5b0f2b7 100644 --- a/scripts/pack.ps1 +++ b/scripts/pack.ps1 @@ -11,7 +11,7 @@ Creates default archives for Cmder .EXAMPLE - .\pack.ps1 -verbose + .\pack.ps1 -Verbose Creates default archives for Cmder with plenty of information .NOTES @@ -25,52 +25,103 @@ [CmdletBinding(SupportsShouldProcess = $true)] Param( # CmdletBinding will give us; - # -verbose switch to turn on logging and + # -Verbose switch to turn on logging and # -whatif switch to not actually make changes # Path to the vendor configuration source file [string]$cmderRoot = "$PSScriptRoot\..", + # Using this option will pack artifacts for a specific included terminal emulator [none, all, conemu-maximus5, or windows-terminal] + [string]$Terminal = 'all', + # Vendor folder locaton [string]$saveTo = "$PSScriptRoot\..\build" ) -$cmderRoot = Resolve-Path $cmderRoot +$cmder_root = Resolve-Path $cmderRoot . "$PSScriptRoot\utils.ps1" $ErrorActionPreference = "Stop" Ensure-Executable "7z" -$targets = @{ - "cmder.7z" = "-t7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on -myx=7 -mqs=on"; - "cmder.zip" = "-mm=Deflate -mfb=128 -mpass=3"; - "cmder_mini.zip" = "-xr!`"vendor\git-for-windows`""; +function Get-ArchiveFlags { + param( + [Parameter(Mandatory = $true)] + [string]$Kind, + + [string[]]$IncludedVendors = @(), + + [string[]]$AllVendors = @() + ) + + if ($Kind -eq "7z") { + $flags = "-t7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on -myx=7 -mqs=on" + } else { + $flags = "-mm=Deflate -mfb=128 -mpass=3" + } + + $archiveExcludedVendors = @($AllVendors | Where-Object { $IncludedVendors -notcontains $_ }) + + foreach ($vendor in $archiveExcludedVendors) { + $flags += " -xr!`"vendor\$vendor`"" + } + + return $flags } -Push-Location -Path $cmderRoot +Push-Location -Path $cmder_root -Delete-Existing "$cmderRoot\Version*" -Delete-Existing "$cmderRoot\build\*" +Delete-Existing "$cmder_root\Version*" +Delete-Existing "$saveTo\*" if (-not (Test-Path -PathType container $saveTo)) { (New-Item -ItemType Directory -Path $saveTo) | Out-Null } $saveTo = Resolve-Path $saveTo - +$profiles = Get-CmderPackageProfiles -Terminal $Terminal +$allVendors = @(Get-CmderVendorNames) $version = Get-VersionStr -(New-Item -ItemType file "$cmderRoot\Version $version") | Out-Null +(New-Item -ItemType file "$cmder_root\Version $version") | Out-Null if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { Write-Verbose "Packing Cmder $version in $saveTo..." - $excluded = (Get-Content -Path "$cmderRoot\packignore") -Split [System.Environment]::NewLine | Where-Object { $_ } - Get-ChildItem $cmderRoot -Force -Exclude $excluded + $excluded = (Get-Content -Path "$cmder_root\packignore") -Split [System.Environment]::NewLine | Where-Object { $_ } + Get-ChildItem $cmder_root -Force -Exclude $excluded } -foreach ($t in $targets.GetEnumerator()) { - Create-Archive "$cmderRoot" "$saveTo\$($t.Name)" $t.Value - $hash = (Digest-Hash "$saveTo\$($t.Name)") - Add-Content -path "$saveTo\hashes.txt" -value ($t.Name + "`t" + $hash) +foreach ($profile in $profiles) { + $profilePath = Join-Path $saveTo $profile.outputFolder + if (-not (Test-Path -PathType container $profilePath)) { + (New-Item -ItemType Directory -Path $profilePath) | Out-Null + } + + if (-not $profile.packages) { + throw "Missing package variants for profile '$($profile.displayName)'. Edit scripts/package-profiles.json to add package entries." + } + $packages = @($profile.packages) + + # Package variations live in scripts/package-profiles.json so names and vendor mixes stay configurable. + foreach ($package in $packages) { + if ([string]::IsNullOrWhiteSpace($package.name)) { + throw "A package entry for profile '$($profile.displayName)' is missing a name in scripts/package-profiles.json." + } + + if ([string]::IsNullOrWhiteSpace($package.kind)) { + throw "A package entry for profile '$($profile.displayName)' is missing a kind in scripts/package-profiles.json." + } + + $outputPath = Join-Path $profilePath $package.name + $includedVendors = @($profile.includedVendors) + if ($package.PSObject.Properties.Name -contains "includedVendors" -and $package.includedVendors) { + $includedVendors = @($package.includedVendors) + } + + $flags = Get-ArchiveFlags -Kind $package.kind -IncludedVendors $includedVendors -AllVendors $allVendors + Create-Archive "$cmder_root" $outputPath $flags + $hash = Digest-Hash $outputPath + Add-Content -Path (Join-Path $saveTo "hashes.txt") -Value ($profile.outputFolder + "/" + $package.name + "`t" + $hash) + } } Pop-Location diff --git a/scripts/package-profiles.json b/scripts/package-profiles.json new file mode 100644 index 000000000..7c831e3ed --- /dev/null +++ b/scripts/package-profiles.json @@ -0,0 +1,92 @@ +{ + "profiles": [ + { + "displayName": "Cmder Launcher", + "terminal": "none", + "outputFolder": "cmder_launcher", + "includedVendors": [ + "git-for-windows", + "clink", + "clink-completions" + ], + "packages": [ + { + "name": "cmder_launcher.7z", + "kind": "7z" + }, + { + "name": "cmder_launcher.zip", + "kind": "zip" + }, + { + "name": "cmder_launcher_mini.zip", + "kind": "zip", + "includedVendors": [ + "clink", + "clink-completions" + ] + } + ] + }, + { + "displayName": "Windows Terminal", + "terminal": "windows-terminal", + "outputFolder": "cmder", + "includedVendors": [ + "git-for-windows", + "clink", + "windows-terminal", + "clink-completions" + ], + "packages": [ + { + "name": "cmder.7z", + "kind": "7z" + }, + { + "name": "cmder.zip", + "kind": "zip" + }, + { + "name": "cmder_mini.zip", + "kind": "zip", + "includedVendors": [ + "clink", + "windows-terminal", + "clink-completions" + ] + } + ] + }, + { + "displayName": "ConEmu", + "terminal": "conemu-maximus5", + "outputFolder": "cmder_conemu", + "includedVendors": [ + "git-for-windows", + "clink", + "conemu-maximus5", + "clink-completions" + ], + "packages": [ + { + "name": "cmder_conemu.7z", + "kind": "7z" + }, + { + "name": "cmder_conemu.zip", + "kind": "zip" + }, + { + "name": "cmder_conemu_mini.zip", + "kind": "zip", + "includedVendors": [ + "clink", + "conemu-maximus5", + "clink-completions" + ] + } + ] + } + ] +} diff --git a/scripts/update.ps1 b/scripts/update.ps1 index b511bf03e..b76a9af8b 100644 --- a/scripts/update.ps1 +++ b/scripts/update.ps1 @@ -5,17 +5,17 @@ This script updates dependencies to the latest version in vendor/sources.json file. 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 .\build.ps1 + Then unblock the script for execution with UnblockFile .\update.ps1 .EXAMPLE - .\build.ps1 + .\update.ps1 Updates the dependency sources in the default location, the vendor/sources.json file. .EXAMPLE - .\build -verbose + .\update.ps1 -Verbose Updates the dependency sources and see what's going on. .EXAMPLE - .\build.ps1 -SourcesPath '~/custom/vendors.json' + .\update.ps1 -SourcesPath '~/custom/vendors.json' Specify the path to update dependency sources file at. .NOTES @@ -23,12 +23,12 @@ David Refoua Part of the Cmder project. .LINK - http://cmder.app/ - Project Home + https://github.com/cmderdev/cmder - Project Home #> [CmdletBinding(SupportsShouldProcess = $true)] Param( # CmdletBinding will give us; - # -verbose switch to turn on logging and + # -Verbose switch to turn on logging and # -whatif switch to not actually make changes # Path to the vendor configuration source file diff --git a/scripts/utils.ps1 b/scripts/utils.ps1 index e0c107b92..4bccdee78 100644 --- a/scripts/utils.ps1 +++ b/scripts/utils.ps1 @@ -1,7 +1,7 @@ -๏ปฟfunction Ensure-Exists($path) { +๏ปฟ# Keep this file as UTF-8 with BOM so Windows PowerShell 5.1 can parse literal emoji strings. +function Ensure-Exists($path) { if (-not (Test-Path $path)) { - Write-Error "Missing required $path! Ensure it is installed" - exit 1 + throw "Missing required $path! Ensure it is installed" } return $true > $null } @@ -16,8 +16,7 @@ function Ensure-Executable($command) { Set-Alias -Name "7z" -Value "$env:programw6432\7-zip\7z.exe" -Scope script } else { - Write-Error "Missing $command! Ensure it is installed and on in the PATH" - exit 1 + throw "Missing $command! Ensure it is installed and on in the PATH" } } } @@ -330,6 +329,21 @@ function Format-FileSize { } } +function Get-ArtifactTypeEmoji { + param( + [Parameter(Mandatory = $true)] + [string]$Name + ) + + if ($Name -match '\.txt$') { + return "๐Ÿ“„" + } elseif ($Name -match '\.(zip|rar|7z)$') { + return "๐Ÿ—„๏ธ" + } + + return "๐Ÿ“ฆ" +} + function Get-VersionChangeType { <# .SYNOPSIS @@ -492,3 +506,88 @@ function Get-ArtifactDownloadUrl { return $null } + +function Get-CmderPackageConfig { + $configPath = Join-Path $PSScriptRoot "package-profiles.json" + if (-not (Test-Path $configPath)) { + throw "Missing package configuration file: $configPath" + } + + return Get-Content -Raw $configPath | ConvertFrom-Json +} + +function Get-CmderVendorNames { + $sourcesPath = Join-Path $PSScriptRoot "..\vendor\sources.json" + if (-not (Test-Path $sourcesPath)) { + throw "Missing vendor sources file: $sourcesPath" + } + + $sourceData = Get-Content -Raw $sourcesPath | ConvertFrom-Json + $sourceEntries = @($sourceData) + + # Allow either a top-level array or an object wrapper with a "sources" property. + if ( + $sourceEntries.Count -eq 1 -and + $sourceEntries[0] -and + $sourceEntries[0].PSObject.Properties.Name -contains "sources" + ) { + $sourceEntries = @($sourceEntries[0].sources) + } + + $vendorNames = @( + $sourceEntries | ForEach-Object { + if ($_ -and $_.PSObject.Properties.Name -contains "name") { + $_.name + } + } + ) + + if (-not $vendorNames) { + throw "No vendor names could be read from $sourcesPath" + } + + return $vendorNames +} + +function Get-CmderPackageProfiles { + param( + [string]$Terminal = "all" + ) + + $config = Get-CmderPackageConfig + $profiles = @($config.profiles) + + if ($Terminal -eq "all") { + return $profiles + } + + $profile = $profiles | Where-Object { $_.terminal -eq $Terminal } | Select-Object -First 1 + if (-not $profile) { + throw "Unknown Cmder terminal profile '$Terminal'" + } + + return @($profile) +} + +function Get-CmderTerminalIncludedVendors { + param( + [string]$Terminal = "all" + ) + + if ($Terminal -eq "all") { + return @(Get-CmderVendorNames) + } + + $profile = Get-CmderPackageProfiles -Terminal $Terminal | Select-Object -First 1 + $includedVendors = @($profile.includedVendors) + + if ($profile.packages) { + foreach ($package in @($profile.packages)) { + if ($package -and $package.PSObject.Properties.Name -contains "includedVendors" -and $package.includedVendors) { + $includedVendors += @($package.includedVendors) + } + } + } + + return @($includedVendors | Select-Object -Unique) +} diff --git a/vendor/ConEmu.xml.default b/vendor/ConEmu.xml.default index a4e5cc1fb..a993e38f3 100644 --- a/vendor/ConEmu.xml.default +++ b/vendor/ConEmu.xml.default @@ -1,7 +1,7 @@ - + @@ -42,8 +42,8 @@ - - + + @@ -58,7 +58,7 @@ - + @@ -78,7 +78,6 @@ - @@ -113,13 +112,13 @@ - + - + - + @@ -128,8 +127,8 @@ - - + + @@ -166,19 +165,19 @@ - + - + - + - + @@ -413,15 +412,15 @@ - + - + - + @@ -484,12 +483,12 @@ - - + + - - + + @@ -497,8 +496,8 @@ - - + + @@ -507,8 +506,8 @@ - - + + @@ -516,61 +515,78 @@ - - - + + + - + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + - - + - + + - - + - - + + - + - + - @@ -676,7 +692,7 @@ - + @@ -845,13 +861,13 @@ - - + + - + - + @@ -869,10 +885,16 @@ + + + + + + - + @@ -902,6 +924,15 @@ + + + + + + + + + diff --git a/vendor/bin/cexec.cmd b/vendor/bin/cexec.cmd index 2d9247b33..f504e74ad 100644 --- a/vendor/bin/cexec.cmd +++ b/vendor/bin/cexec.cmd @@ -77,7 +77,7 @@ exit /b echo. echo CExec - Conditional Exec echo. -echo Handles with custom arguments for cmder's init.bat. +echo Handles with custom arguments for cmder's init.cmd. echo written by xiazeyu, inspired DRSDavidSoft. echo. echo Usage: @@ -115,9 +115,9 @@ echo The following command in `user_profile.cmd` would execute "notepad.exe" a echo. echo "%ccall%" "/startNotepad" "start" "notepad.exe" echo. -echo If you pass parameter to init.bat like: +echo If you pass parameter to init.cmd like: echo. -echo init.bat /startNotepad +echo init.cmd /startNotepad echo. echo Case 2: echo. @@ -125,9 +125,9 @@ echo The following command in `user_profile.cmd` would execute "notepad.exe" a echo. echo "%cexec%" NOT "/dontStartNotepad" "start" "notepad.exe" echo. -echo UNLESS you pass parameter to init.bat like: +echo UNLESS you pass parameter to init.cmd like: echo. -echo init.bat /dontStartNotepad +echo init.cmd /dontStartNotepad echo. endlocal exit /b diff --git a/vendor/bin/cmder_diag.cmd b/vendor/bin/cmder_diag.cmd index f526cff62..d806ee6b2 100644 --- a/vendor/bin/cmder_diag.cmd +++ b/vendor/bin/cmder_diag.cmd @@ -2,9 +2,9 @@ (echo. echo ------------------------------------ -echo set +echo Get Cmder env variables... echo ------------------------------------ -set +set | findstr -i -r "^aliases= architecture_bits ccall= cexec= ^clink_ ^cmder ^debug_output= fast_init= ^GIT_INSTALL_ROOT= ^git_locale= ^HOME= ^max_depth= ^nix_tools= ^path_position= ^path= ^PLINK_PROTOCOL= ^print_ ^SVN_SSH= ^time_init= ^user_aliases= ^verbose_output=" echo. echo ------------------------------------ diff --git a/vendor/bin/cmder_diag.ps1 b/vendor/bin/cmder_diag.ps1 index c211c6412..44e17194e 100644 --- a/vendor/bin/cmder_diag.ps1 +++ b/vendor/bin/cmder_diag.ps1 @@ -1,64 +1,64 @@ -if (Test-Path $env:temp\cmder_diag_ps.log) { - Remove-Item $env:temp\cmder_diag_ps.log +if (Test-Path "$env:TEMP\cmder_diag_ps.log") { + Remove-Item "$env:TEMP\cmder_diag_ps.log" } -$cmder_diag = { -"" -"------------------------------------" -"get-childitem env:" -"------------------------------------" -Get-ChildItem env: | Format-Table -AutoSize -Wrap 2>&1 +$CmderDiag = { + "" + "------------------------------------" + "Get-ChildItem env:" + "------------------------------------" + Get-ChildItem env: | Format-Table -AutoSize -Wrap 2>&1 -"" -"------------------------------------" -"get-command git -all -ErrorAction SilentlyContinue" -"------------------------------------" -Get-Command git -All -ErrorAction SilentlyContinue + "" + "------------------------------------" + "Get-Command git -All -ErrorAction SilentlyContinue" + "------------------------------------" + Get-Command git -All -ErrorAction SilentlyContinue -"" -"------------------------------------" -"get-command clink -all -ErrorAction SilentlyContinue" -"------------------------------------" -Get-Command clink -All -ErrorAction SilentlyContinue + "" + "------------------------------------" + "Get-Command clink -All -ErrorAction SilentlyContinue" + "------------------------------------" + Get-Command clink -All -ErrorAction SilentlyContinue -"" -"------------------------------------" -"systeminfo" -"------------------------------------" -systeminfo 2>&1 + "" + "------------------------------------" + "Systeminfo" + "------------------------------------" + systeminfo 2>&1 -"------------------------------------" -"get-childitem '$env:CMDER_ROOT'" -"------------------------------------" -Get-ChildItem "$env:CMDER_ROOT" | Format-Table LastWriteTime, mode, length, FullName + "------------------------------------" + "Get-ChildItem '$env:CMDER_ROOT'" + "------------------------------------" + Get-ChildItem "$env:CMDER_ROOT" | Format-Table LastWriteTime, Mode, Length, FullName -"" -"------------------------------------" -"get-childitem '$env:CMDER_ROOT/vendor'" -"------------------------------------" -Get-ChildItem "$env:CMDER_ROOT/vendor" | Format-Table LastWriteTime, mode, length, FullName + "" + "------------------------------------" + "Get-ChildItem '$env:CMDER_ROOT/vendor'" + "------------------------------------" + Get-ChildItem "$env:CMDER_ROOT/vendor" | Format-Table LastWriteTime, Mode, Length, FullName -"" -"------------------------------------" -"get-childitem -s '$env:CMDER_ROOT/bin'" -"------------------------------------" -Get-ChildItem -Recurse "$env:CMDER_ROOT/bin" | Format-Table LastWriteTime, mode, length, FullName + "" + "------------------------------------" + "Get-ChildItem -Recurse '$env:CMDER_ROOT/bin'" + "------------------------------------" + Get-ChildItem -Recurse "$env:CMDER_ROOT/bin" | Format-Table LastWriteTime, Mode, Length, FullName -"" -"------------------------------------" -"get-childitem -s '$env:CMDER_ROOT/config'" -"------------------------------------" -Get-ChildItem -Recurse "$env:CMDER_ROOT/config" | Format-Table LastWriteTime, mode, length, FullName + "" + "------------------------------------" + "Get-ChildItem -Recurse '$env:CMDER_ROOT/config'" + "------------------------------------" + Get-ChildItem -Recurse "$env:CMDER_ROOT/config" | Format-Table LastWriteTime, Mode, Length, FullName -"" -"------------------------------------" -"Make sure you sanitize this output of private data prior to posting it online for review by the CMDER Team!" -"------------------------------------" + "" + "------------------------------------" + "Make sure you sanitize this output of private data prior to posting it online for review by the CMDER Team!" + "------------------------------------" } -& $cmder_diag | Out-File -FilePath $env:temp\cmder_diag_ps.log +& $CmderDiag | Out-File -FilePath "$env:TEMP\cmder_diag_ps.log" -Get-Content "$env:temp\cmder_diag_ps.log" +Get-Content "$env:TEMP\cmder_diag_ps.log" Write-Output "" -Write-Output "Above output was saved in $env:temp\cmder_diag_ps.log" +Write-Output "Above output was saved in $env:TEMP\cmder_diag_ps.log" diff --git a/vendor/bin/cmder_shell.cmd b/vendor/bin/cmder_shell.cmd index 11eeb270b..545a272da 100644 --- a/vendor/bin/cmder_shell.cmd +++ b/vendor/bin/cmder_shell.cmd @@ -9,5 +9,5 @@ if "%cmder_init%" == "1" ( ) pushd "%CMDER_ROOT%" -call "%CMDER_ROOT%\vendor\init.bat" /f %* +call "%CMDER_ROOT%\vendor\init.cmd" /f %* popd diff --git a/vendor/bin/create-cmdercfg.cmd b/vendor/bin/create-cmdercfg.cmd new file mode 100644 index 000000000..cc8c7116b --- /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/bin/create-cmdercfg.ps1 b/vendor/bin/create-cmdercfg.ps1 new file mode 100644 index 000000000..2c53affee --- /dev/null +++ b/vendor/bin/create-cmdercfg.ps1 @@ -0,0 +1,34 @@ +[CmdletBinding()] +param( + [Parameter()] + [string]$Shell = 'cmd', + [string]$OutFile = "$env:cmder_config_dir\user_init.cmd" +) + +if ($Shell -match 'powershell') { + Write-Host "'$Shell' is not supported at this time!" + exit 0 +} +elseif ($Shell -match 'bash') { + Write-Host "'$Shell' is not supported at this time!" + exit 0 +} +elseif ($Shell -notmatch 'cmd') { + exit 0 +} + +$CmderModulePath = Join-Path $env:cmder_root 'vendor/psmodules/' +$CmderFunctions = Join-Path $CmderModulePath 'Cmder.ps1' + +. $CmderFunctions + +if ($Shell -match 'cmd') { + Write-Host "Generating Cmder Config for '$Shell' shell in '$OutFile'..." + TemplateExpand "$env:cmder_root\vendor\user_init.cmd.template" "$OutFile" +} +elseif ($Shell -match 'powershell') { + Write-Host "'$Shell' is not supported at this time!" +} +elseif ($Shell -match 'bash') { + Write-Host "'$Shell' is not supported at this time!" +} diff --git a/vendor/bin/timer.cmd b/vendor/bin/timer.cmd index e0b84249d..68a5bc328 100644 --- a/vendor/bin/timer.cmd +++ b/vendor/bin/timer.cmd @@ -11,6 +11,7 @@ set /a hours=%end_h%-%start_h% set /a mins=%end_m%-%start_m% set /a secs=%end_s%-%start_s% set /a ms=%end_ms%-%start_ms% + if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms% if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs% if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins% @@ -20,3 +21,26 @@ if 1%ms% lss 100 set ms=0%ms% :: Mission accomplished set /a totalsecs = %hours%*3600 + %mins%*60 + %secs% echo Elapsed Time: %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total) + +:: cleanup +set start= +set end= +set options= + +set start_h= +set start_m= +set start_s= +set start_ms= + +set end_h= +set end_m= +set end_s= +set end_ms= + +set hours= +set mins= +set secs= +set ms= + +set totalsecs= + diff --git a/vendor/bin/vscode_init.cmd b/vendor/bin/vscode_init.cmd index 79b0ea84b..fffc85f29 100644 --- a/vendor/bin/vscode_init.cmd +++ b/vendor/bin/vscode_init.cmd @@ -23,7 +23,7 @@ if not exist "%CMDER_VSCODE_INIT_ARGS%" ( IF [%1] == [] ( REM -- manually opened console (Ctrl + Shift + `) -- - CALL "%~dp0..\init.bat" + CALL "%~dp0..\init.cmd" ) ELSE ( REM -- task -- CALL cmd %* diff --git a/vendor/bin/vscode_init_args.cmd.default b/vendor/bin/vscode_init_args.cmd.default index 4a17d93d3..86e653f30 100644 --- a/vendor/bin/vscode_init_args.cmd.default +++ b/vendor/bin/vscode_init_args.cmd.default @@ -11,7 +11,7 @@ rem `/c [cmder_user_cfg_root] rem set cmder_user_bin=[cmder_user_cfg_root]\bin rem set cmder_user_config=[cmder_user_cfg_root]\config rem -rem `init.bat` Arguments +rem `init.cmd` Arguments rem -------------------- rem rem `/d` diff --git a/vendor/clink.lua b/vendor/clink.lua index 804f9c649..b9d6d046e 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -1,4 +1,4 @@ --- default script for clink, called by init.bat when injecting clink +-- default script for clink, called by init.cmd when injecting clink -- !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED -- !!! Use "%CMDER_ROOT%\config\.lua" to add your lua startup scripts @@ -800,6 +800,10 @@ for _,lua_module in ipairs(clink.find_files(completions_dir..'*.lua')) do end end +-- If Cmder is launched with '/c [folderPath]', indicating Cmder is installed globally and +-- each user has a private '[folderPath]\config' folder, Clink won't know about the global +-- '%cmder_root%\config dir, so we need to load scripts from there before . Clink loads lua +-- scripts from the profile directory given to it when it was injected. if clink.get_env('CMDER_USER_CONFIG') then local cmder_config_dir = clink.get_env('CMDER_ROOT')..'/config/' for _,lua_module in ipairs(clink.find_files(cmder_config_dir..'*.lua')) do diff --git a/vendor/cmder.sh b/vendor/cmder.sh index 8467593b3..37f6d336d 100644 --- a/vendor/cmder.sh +++ b/vendor/cmder.sh @@ -22,7 +22,11 @@ function runProfiled { } # We do this for bash as admin sessions since $CMDER_ROOT is not being set -if [ "$CMDER_ROOT" == "" ] ; then +if [ -z "$CMDER_ROOT" ] && [ -n "$cmder_root" ] ; then + export CMDER_ROOT=$(cygpath -u $cmder_root) +fi + +if [ -z "$CMDER_ROOT" ] ; then case "$ConEmuDir" in *\\*) CMDER_ROOT=$( cd "$(cygpath -u "$ConEmuDir")/../.." ; pwd );; esac else case "$CMDER_ROOT" in *\\*) CMDER_ROOT="$(cygpath -u "$CMDER_ROOT")";; esac @@ -45,6 +49,16 @@ if [[ ! "$PATH" =~ "${GIT_INSTALL_ROOT}/bin:" ]] ; then PATH="${GIT_INSTALL_ROOT}/bin:$PATH" fi +if [ "$PROCESSOR_ARCHITECTURE" == "x86" ] && [ "$GIT_INSTALL_ROOT/mingw32" ] ; then + git_mingw_bin="$GIT_INSTALL_ROOT/mingw32/bin" +elif [ "$PROCESSOR_ARCHITECTURE" == "AMD64" ] && [ -d "$GIT_INSTALL_ROOT/mingw64" ] ; then + git_mingw_bin="$GIT_INSTALL_ROOT/mingw64/bin" +fi + +if [[ ! "$PATH" =~ "${git_mingw_bin}:" ]] ; then + PATH="${git_mingw_bin}:$PATH" +fi + PATH="${CMDER_ROOT}/bin:${CMDER_ROOT}/vendor/bin:$PATH:${CMDER_ROOT}" export PATH diff --git a/vendor/cmder_exinit b/vendor/cmder_exinit index 4ec3351af..edb12c7ec 100644 --- a/vendor/cmder_exinit +++ b/vendor/cmder_exinit @@ -26,15 +26,14 @@ function runProfiled { unset profile_d_scripts pushd "${1}" >/dev/null - if [ ! "x${ZSH_VERSION}" = "x" ]; then + if [ -n "${ZSH_VERSION}" ]; then profile_d_scripts=$(ls *.zsh 2>/dev/null) - elif [ ! "x${BASH_VERSION}" = "x" ]; then + elif [ -n "${BASH_VERSION}" ]; then profile_d_scripts=$(ls *.sh 2>/dev/null) fi - if [ ! "x${profile_d_scripts}" = "x" ] ; then + if [ -n "${profile_d_scripts}" ] ; then for x in ${profile_d_scripts} ; do - echo Sourcing "${1}/${x}"... . "${1}/${x}" done fi @@ -44,23 +43,23 @@ function runProfiled { # Check that we haven't already been sourced. [[ -z ${CMDER_EXINIT} ]] && CMDER_EXINIT="1" || return +if [ -z "$CMDER_ROOT" ] && [ -n "$cmder_root" ] ; then + export CMDER_ROOT=$(cygpath -u $cmder_root) +fi + # We do this for bash as admin sessions since $CMDER_ROOT is not being set if [ "$CMDER_ROOT" = "" -a "$ConEmuDir" != "" ] ; then - if [ -d "${ConEmuDir}../../vendor" ] ; then + if [ -d "${ConEmuDir}/../../vendor" ] ; then case "$ConEmuDir" in *\\*) CMDER_ROOT=$( cd "$(cygpath -u "$ConEmuDir")/../.." ; pwd );; esac - else - echo "Running in ConEmu without Cmder, skipping Cmder integration." fi elif [ "$CMDER_ROOT" != "" ] ; then case "$CMDER_ROOT" in *\\*) CMDER_ROOT="$(cygpath -u "$CMDER_ROOT")";; esac fi -if [ ! "$CMDER_ROOT" = "" ] ; then +if [ -n "$CMDER_ROOT" ] ; then # Remove any trailing '/' CMDER_ROOT=$(echo $CMDER_ROOT | sed 's:/*$::') - echo "Using \"CMDER_ROOT\" at \"${CMDER_ROOT}\"." - export CMDER_ROOT PATH=${CMDER_ROOT}/bin:${CMDER_ROOT}/vendor/bin:$PATH:${CMDER_ROOT} diff --git a/vendor/init.bat b/vendor/init.bat index bd5242f7b..0984ae58f 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -1,501 +1,6 @@ @echo off +rem Cmder init.cmd compatibility shim, do not delete this file it is a part of the Cmder package and will be recreated on update of Cmder. +echo Cmder's cmd startup script has moved from "%~f0" to "%~dp0init.cmd". +echo Please update your Cmder task or shell configuration to call "%~dp0init.cmd" directly. -set CMDER_INIT_START=%time% - -:: Init Script for cmd.exe shell -:: Created as part of cmder project - -:: !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED -:: !!! Use "%CMDER_ROOT%\config\user_profile.cmd" to add your own startup commands - -:: Use /v command line arg or set to > 0 for verbose output to aid in debugging. -if not defined verbose_output set verbose_output=0 - -:: Use /d command line arg or set to 1 for debug output to aid in debugging. -if not defined debug_output set debug_output=0 - -:: Use /t command line arg or set to 1 to display init time. -if not defined time_init set time_init=0 - -:: Use /f command line arg to speed up init at the expense of some functionality. -if not defined fast_init set fast_init=0 - -:: Use /max_depth 1-5 to set max recurse depth for calls to `enhance_path_recursive` -if not defined max_depth set max_depth=1 - -:: Add *nix tools to end of path. 0 turns off *nix tools, 2 adds *nix tools to the front of the path. -if not defined nix_tools set nix_tools=1 - -set "CMDER_USER_FLAGS= " - -:: Find root dir -if not defined CMDER_ROOT ( - if defined ConEmuDir ( - for /f "delims=" %%i in ("%ConEmuDir%\..\..") do ( - set "CMDER_ROOT=%%~fi" - ) - ) else ( - for /f "delims=" %%i in ("%~dp0\..") do ( - set "CMDER_ROOT=%%~fi" - ) - ) -) - -:: Remove trailing '\' from %CMDER_ROOT% -if "%CMDER_ROOT:~-1%" == "\" SET "CMDER_ROOT=%CMDER_ROOT:~0,-1%" - -:: Include Cmder libraries -call "%cmder_root%\vendor\bin\cexec.cmd" /setpath -call "%cmder_root%\vendor\lib\lib_console" -call "%cmder_root%\vendor\lib\lib_base" -call "%cmder_root%\vendor\lib\lib_path" -call "%cmder_root%\vendor\lib\lib_git" -call "%cmder_root%\vendor\lib\lib_profile" - -:var_loop - if "%~1" == "" ( - goto :start - ) else if /i "%1" == "/f" ( - set fast_init=1 - ) else if /i "%1" == "/t" ( - set time_init=1 - ) else if /i "%1" == "/v" ( - set verbose_output=1 - ) else if /i "%1" == "/d" ( - set debug_output=1 - ) else if /i "%1" == "/max_depth" ( - if "%~2" geq "1" if "%~2" leq "5" ( - set "max_depth=%~2" - shift - ) else ( - %print_error% "'/max_depth' requires a number between 1 and 5!" - exit /b - ) - ) else if /i "%1" == "/c" ( - if exist "%~2" ( - if not exist "%~2\bin" mkdir "%~2\bin" - set "cmder_user_bin=%~2\bin" - if not exist "%~2\config\profile.d" mkdir "%~2\config\profile.d" - set "cmder_user_config=%~2\config" - shift - ) - ) else if /i "%1" == "/user_aliases" ( - if exist "%~2" ( - set "user_aliases=%~2" - shift - ) - ) else if /i "%1" == "/git_install_root" ( - if exist "%~2" ( - set "GIT_INSTALL_ROOT=%~2" - shift - ) else ( - %print_error% "The Git install root folder "%~2" that you specified does not exist!" - exit /b - ) - ) else if /i "%1" == "/nix_tools" ( - if "%2" equ "0" ( - REM Do not add *nix tools to path - set nix_tools=0 - shift - ) else if "%2" equ "1" ( - REM Add *nix tools to end of path - set nix_tools=1 - shift - ) else if "%2" equ "2" ( - REM Add *nix tools to front of path - set nix_tools=2 - shift - ) - ) else if /i "%1" == "/home" ( - if exist "%~2" ( - set "HOME=%~2" - shift - ) else ( - %print_error% The home folder "%2" that you specified does not exist! - exit /b - ) - ) else if /i "%1" == "/svn_ssh" ( - set SVN_SSH=%2 - shift - ) else ( - set "CMDER_USER_FLAGS=%1 %CMDER_USER_FLAGS%" - ) - shift -goto :var_loop - -:start -:: Enable console related methods if verbose/debug is turned on -if %debug_output% gtr 0 (set print_debug=%lib_console% debug_output) -if %verbose_output% gtr 0 ( - set print_verbose=%lib_console% verbose_output - set print_warning=%lib_console% show_warning -) - -:: Sets CMDER_SHELL, CMDER_CLINK, CMDER_ALIASES variables -%lib_base% cmder_shell -%print_debug% init.bat "Env Var - CMDER_ROOT=%CMDER_ROOT%" -%print_debug% init.bat "Env Var - debug_output=%debug_output%" - -:: Set the Cmder directory paths -set CMDER_CONFIG_DIR=%CMDER_ROOT%\config - -:: Check if we're using Cmder individual user profile -if defined CMDER_USER_CONFIG ( - %print_debug% init.bat "CMDER IS ALSO USING INDIVIDUAL USER CONFIG FROM '%CMDER_USER_CONFIG%'!" - - if not exist "%CMDER_USER_CONFIG%\..\opt" md "%CMDER_USER_CONFIG%\..\opt" - set CMDER_CONFIG_DIR=%CMDER_USER_CONFIG% -) - -if not "%CMDER_SHELL%" == "cmd" ( - %print_warning% "Incompatible 'ComSpec/Shell' Detected: %CMDER_SHELL%" - set CMDER_CLINK=0 - set CMDER_ALIASES=0 -) - -:: Pick the right version of Clink -:: TODO: Support for ARM -if "%PROCESSOR_ARCHITECTURE%"=="x86" ( - set clink_architecture=x86 - set architecture_bits=32 -) else if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - set clink_architecture=x64 - set architecture_bits=64 -) else ( - %print_warning% "Incompatible Processor Detected: %PROCESSOR_ARCHITECTURE%" - set CMDER_CLINK=0 -) - -if "%CMDER_CLINK%" == "1" ( - REM TODO: Detect if clink is already injected, if so goto :CLINK_FINISH - goto :INJECT_CLINK -) - -goto :SKIP_CLINK - -:INJECT_CLINK - %print_verbose% "Injecting Clink!" - - :: Check if Clink is not present - if not exist "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" ( - %print_error% "Clink executable is not present in 'vendor\clink\clink_%clink_architecture%.exe'" - goto :SKIP_CLINK - ) - - :: Run Clink - if not exist "%CMDER_CONFIG_DIR%\settings" if not exist "%CMDER_CONFIG_DIR%\clink_settings" ( - echo Generating Clink initial settings in "%CMDER_CONFIG_DIR%\clink_settings" - copy "%CMDER_ROOT%\vendor\clink_settings.default" "%CMDER_CONFIG_DIR%\clink_settings" - echo Additional *.lua files in "%CMDER_CONFIG_DIR%" are loaded on startup. - ) - - if not exist "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" ( - echo Creating Cmder prompt config file: "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" - copy "%CMDER_ROOT%\vendor\cmder_prompt_config.lua.default" "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" - ) - - :: Cleanup legacy Clink Settings file - if exist "%CMDER_CONFIG_DIR%\settings" if exist "%CMDER_CONFIG_DIR%\clink_settings" ( - del "%CMDER_CONFIG_DIR%\settings" - ) - - :: Cleanup legacy Clink history file - if exist "%CMDER_CONFIG_DIR%\.history" if exist "%CMDER_CONFIG_DIR%\clink_history" ( - del "%CMDER_CONFIG_DIR%\.history" - ) - - "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" inject --quiet --profile "%CMDER_CONFIG_DIR%" --scripts "%CMDER_ROOT%\vendor" - - :: Check if a fatal error occurred when trying to inject Clink - if errorlevel 2 ( - REM %print_error% "Clink injection has failed with error code: %errorlevel%" - goto :SKIP_CLINK - ) - - goto :CLINK_FINISH - -:SKIP_CLINK - %print_warning% "Skipping Clink Injection!" - - for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x - chcp 65001>nul - - :: 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 - -:CLINK_FINISH - -if "%CMDER_CONFIGURED%" GTR "1" ( - %print_verbose% "Cmder is already configured, skipping Cmder Init!" - - goto :USER_ALIASES -) else if "%CMDER_CONFIGURED%" == "1" ( - %print_verbose% "Cmder is already configured, skipping to Cmder User Init!" - - goto :USER_CONFIG_START -) - -:: Prepare for git-for-windows - -:: Detect which git.exe version to use -:: * if the user points to a specific git, use that -:: * test if git is in path and if yes, use that -:: * last, use our vendored git -:: also check that we have a recent enough version of git by examining the version string -if defined GIT_INSTALL_ROOT ( - if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" goto :SPECIFIED_GIT - set GIT_INSTALL_ROOT= -) else if "%fast_init%" == "1" ( - if exist "%CMDER_ROOT%\vendor\git-for-windows\cmd\git.exe" ( - %print_debug% init.bat "Skipping Git Auto-Detect!" - goto :VENDORED_GIT - ) - - %print_debug% init.bat "Fast init is enabled, vendored Git does not exist" - for /F "delims=" %%F in ('where git.exe 2^>nul') do ( - set "EXT_GIT_EXE=%%~fF" - %print_debug% init.bat "Found User installed Git at '%%~fF'. Skipping Git Auto-Detect!" - goto :SET_ENV - ) -) - -%print_debug% init.bat "Looking for Git install root..." - -:: Get the version information for vendored git binary -%lib_git% read_version VENDORED "%CMDER_ROOT%\vendor\git-for-windows\cmd" 2>nul -%lib_git% validate_version VENDORED %GIT_VERSION_VENDORED% - -:: Check if git is in path -for /F "delims=" %%F in ('where git.exe 2^>nul') do call :check_git "%%~fF" - -if defined GIT_INSTALL_ROOT ( - goto :FOUND_GIT -) else ( - goto :VENDORED_GIT -) - -:check_git - set full_path="%~f1" - if not defined GIT_INSTALL_ROOT ( - if not [\%full_path:\cmd\git.exe=:%]==[\%full_path%] ( - :: Get the absolute path to the user provided git binary - %lib_git% is_git_shim "%~dp1" - %lib_git% get_user_git_version - %lib_git% compare_git_versions - ) - ) - exit /b - -:: Our last hope: use vendored git -:VENDORED_GIT -if exist "%CMDER_ROOT%\vendor\git-for-windows" ( - set "GIT_INSTALL_ROOT=%CMDER_ROOT%\vendor\git-for-windows" - %print_debug% init.bat "Using vendored Git '%GIT_VERSION_VENDORED%'..." - goto :CONFIGURE_GIT -) else ( - goto :NO_GIT -) - -:SPECIFIED_GIT -%print_debug% init.bat "Using /GIT_INSTALL_ROOT..." -goto :CONFIGURE_GIT - -:FOUND_GIT -%print_debug% init.bat "Using found Git '%GIT_VERSION_USER%' from '%GIT_INSTALL_ROOT%..." -goto :CONFIGURE_GIT - -:CONFIGURE_GIT -%print_debug% init.bat "Using Git from '%GIT_INSTALL_ROOT%..." -:: Add git to the path -if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" %lib_path% enhance_path "%GIT_INSTALL_ROOT%\cmd" "" - -:: Add the unix commands at the end to not shadow windows commands like `more` and `find` -if %nix_tools% equ 1 ( - %print_verbose% "Preferring Windows commands" - set "path_position=append" -) else ( - %print_verbose% "Preferring *nix commands" - set "path_position=" -) - -if %nix_tools% geq 1 ( - if exist "%GIT_INSTALL_ROOT%\mingw32" ( - %lib_path% enhance_path "%GIT_INSTALL_ROOT%\mingw32\bin" %path_position% - ) else if exist "%GIT_INSTALL_ROOT%\mingw64" ( - %lib_path% enhance_path "%GIT_INSTALL_ROOT%\mingw64\bin" %path_position% - ) - if exist "%GIT_INSTALL_ROOT%\usr\bin" ( - %lib_path% enhance_path "%GIT_INSTALL_ROOT%\usr\bin" %path_position% - ) -) - -:SET_ENV - -:: Plink (PuTTY Link) is a command-line connection tool similar to ssh, setting its protocol to ssh -set PLINK_PROTOCOL=ssh - -:: Define SVN_SSH so we can use git svn with ssh svn repositories -if not defined SVN_SSH set "SVN_SSH=%GIT_INSTALL_ROOT:\=\\%\\bin\\ssh.exe" - -:: Find locale.exe: From the git install root, from the path, using the git installed env, or fallback using the env from the path. -setlocal enabledelayedexpansion -if not defined git_locale if defined EXT_GIT_EXE ( - set "GIT_INSTALL_ROOT=!EXT_GIT_EXE:\cmd\git.exe=!" -) -endlocal && set GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT% - -if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\locale.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\locale.exe" -if not defined git_locale for /F "tokens=* delims=" %%F in ('where locale.exe 2^>nul') do ( if not defined git_locale set git_locale="%%F" ) -if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\env.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\env.exe" /usr/bin/locale -if not defined git_locale for /F "tokens=* delims=" %%F in ('where env.exe 2^>nul') do ( if not defined git_locale set git_locale="%%F" /usr/bin/locale ) - -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 ( - set "LANG=%%F" - ) - ) -) -endlocal && set LANG=%LANG% - -%print_debug% init.bat "Env Var - GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT%" -%print_debug% init.bat "Found Git in: '%GIT_INSTALL_ROOT%'" -goto :PATH_ENHANCE - -:NO_GIT -:: Skip this if GIT WAS FOUND else we did 'endlocal' above! -endlocal - -:PATH_ENHANCE -%lib_path% enhance_path "%CMDER_ROOT%\vendor\bin" - -:USER_CONFIG_START -%lib_path% enhance_path_recursive "%CMDER_ROOT%\bin" 0 %max_depth% -if defined CMDER_USER_BIN ( - %lib_path% enhance_path_recursive "%CMDER_USER_BIN%" 0 %max_depth% -) -%lib_path% enhance_path "%CMDER_ROOT%" append - -:: Drop *.bat and *.cmd files into "%CMDER_ROOT%\config\profile.d" -:: to run them at startup. -%lib_profile% run_profile_d "%CMDER_ROOT%\config\profile.d" -if defined CMDER_USER_CONFIG ( - %lib_profile% run_profile_d "%CMDER_USER_CONFIG%\profile.d" -) - -:USER_ALIASES -:: Allows user to override default aliases store using profile.d -:: scripts run above by setting the 'aliases' env variable. -:: -:: Note: If overriding default aliases store file the aliases -:: must also be self executing, see '.\user_aliases.cmd.default', -:: and be in profile.d folder. -if not defined user_aliases ( - set "user_aliases=%CMDER_CONFIG_DIR%\user_aliases.cmd" -) - -if "%CMDER_ALIASES%" == "1" ( - REM The aliases environment variable is used by alias.bat to id - REM the default file to store new aliases in. - if not defined aliases ( - set "aliases=%user_aliases%" - ) - - REM Make sure we have a self-extracting user_aliases.cmd file - if not exist "%user_aliases%" ( - echo Creating initial user_aliases store in "%user_aliases%"... - copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%" - ) else ( - %lib_base% update_legacy_aliases - ) - - :: Update old 'user_aliases' to new self executing 'user_aliases.cmd' - if exist "%CMDER_ROOT%\config\aliases" ( - echo Updating old "%CMDER_ROOT%\config\aliases" to new format... - type "%CMDER_ROOT%\config\aliases" >> "%user_aliases%" - del "%CMDER_ROOT%\config\aliases" - ) else if exist "%user_aliases%.old_format" ( - echo Updating old "%user_aliases%" to new format... - type "%user_aliases%.old_format" >> "%user_aliases%" - del "%user_aliases%.old_format" - ) -) - -:: Add aliases to the environment -type "%user_aliases%" | %WINDIR%\System32\findstr /b /l /i "history=cat " >nul -if "%ERRORLEVEL%" == "0" ( - echo Migrating alias 'history' to new Clink 1.x.x... - call "%CMDER_ROOT%\vendor\bin\alias.cmd" /d history - echo Restart the session to activate changes! -) - -call "%user_aliases%" - -if "%CMDER_CONFIGURED%" gtr "1" goto :CMDER_CONFIGURED - -:: See vendor\git-for-windows\README.portable for why we do this -:: Basically we need to execute this post-install.bat because we are -:: manually extracting the archive rather than executing the 7z sfx -if exist "%GIT_INSTALL_ROOT%\post-install.bat" ( - echo Running Git for Windows one time Post Install.... - pushd "%GIT_INSTALL_ROOT%\" - "%GIT_INSTALL_ROOT%\git-cmd.exe" --no-needs-console --no-cd --command=post-install.bat - popd -) - -:: Set home path -if not defined HOME set "HOME=%USERPROFILE%" -%print_debug% init.bat "Env Var - HOME=%HOME%" - -set "initialConfig=%CMDER_ROOT%\config\user_profile.cmd" -if exist "%CMDER_ROOT%\config\user_profile.cmd" ( - REM Create this file and place your own command in there - %print_debug% init.bat "Calling - %CMDER_ROOT%\config\user_profile.cmd" - call "%CMDER_ROOT%\config\user_profile.cmd" -) - -if defined CMDER_USER_CONFIG ( - set "initialConfig=%CMDER_USER_CONFIG%\user_profile.cmd" - if exist "%CMDER_USER_CONFIG%\user_profile.cmd" ( - REM Create this file and place your own command in there - %print_debug% init.bat "Calling - %CMDER_USER_CONFIG%\user_profile.cmd" - call "%CMDER_USER_CONFIG%\user_profile.cmd" - ) -) - -if not exist "%initialConfig%" ( - echo Creating user startup file: "%initialConfig%" - copy "%CMDER_ROOT%\vendor\user_profile.cmd.default" "%initialConfig%" -) - -if "%CMDER_ALIASES%" == "1" if exist "%CMDER_ROOT%\bin\alias.bat" if exist "%CMDER_ROOT%\vendor\bin\alias.cmd" ( - echo Cmder's 'alias' command has been moved into "%CMDER_ROOT%\vendor\bin\alias.cmd" - echo to get rid of this message either: - echo. - echo Delete the file "%CMDER_ROOT%\bin\alias.bat" - echo. - echo or - echo. - echo If you have customized it and want to continue using it instead of the included version - echo * Rename "%CMDER_ROOT%\bin\alias.bat" to "%CMDER_ROOT%\bin\alias.cmd". - echo * Search for 'user-aliases' and replace it with 'user_aliases'. -) - -set initialConfig= - -:CMDER_CONFIGURED -if not defined CMDER_CONFIGURED set CMDER_CONFIGURED=1 - -set CMDER_INIT_END=%time% - -if %time_init% gtr 0 ( - "%cmder_root%\vendor\bin\timer.cmd" "%CMDER_INIT_START%" "%CMDER_INIT_END%" -) -exit /b +call "%~dp0init.cmd" %* diff --git a/vendor/init.cmd b/vendor/init.cmd new file mode 100644 index 000000000..b47fa8338 --- /dev/null +++ b/vendor/init.cmd @@ -0,0 +1,575 @@ +@echo off + +set CMDER_INIT_START=%time% + +:: Init Script for cmd.exe shell +:: Created as part of cmder project + +:: !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED +:: !!! Use "%CMDER_ROOT%\config\user_profile.cmd" to add your own startup commands + +:: Use /v command line arg or set to > 0 for verbose output to aid in debugging. +if not defined verbose_output set verbose_output=0 + +:: Use /d command line arg or set to 1 for debug output to aid in debugging. +if not defined debug_output set debug_output=0 + +:: Use /t command line arg or set to 1 to display init time. +if not defined time_init set time_init=0 + +:: Use /f command line arg to speed up init at the expense of some functionality. +if not defined fast_init set fast_init=0 + +:: Use /max_depth 1-5 to set max recurse depth for calls to `enhance_path_recursive` +if not defined max_depth set max_depth=1 + +:: Add *nix tools to end of path. 0 turns off *nix tools, 2 adds *nix tools to the front of the path. +if not defined nix_tools set nix_tools=1 + +set "CMDER_USER_FLAGS= " + +:: Find root dir +if not defined CMDER_ROOT ( + if defined ConEmuDir ( + for /f "delims=" %%i in ("%ConEmuDir%\..\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) else ( + for /f "delims=" %%i in ("%~dp0\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) +) + +:: Remove trailing '\' from %CMDER_ROOT% +if "%CMDER_ROOT:~-1%" == "\" SET "CMDER_ROOT=%CMDER_ROOT:~0,-1%" + +:: Include Cmder libraries +call "%cmder_root%\vendor\bin\cexec.cmd" /setpath +call "%cmder_root%\vendor\lib\lib_console" +call "%cmder_root%\vendor\lib\lib_base" +call "%cmder_root%\vendor\lib\lib_path" +call "%cmder_root%\vendor\lib\lib_git" +call "%cmder_root%\vendor\lib\lib_profile" + +:var_loop + if "%~1" == "" ( + goto :start + ) else if /i "%1" == "/f" ( + set fast_init=1 + ) else if /i "%1" == "/t" ( + set time_init=1 + ) else if /i "%1" == "/v" ( + set verbose_output=1 + ) else if /i "%1" == "/d" ( + set debug_output=1 + ) else if /i "%1" == "/max_depth" ( + if "%~2" geq "1" if "%~2" leq "5" ( + set "max_depth=%~2" + shift + ) else ( + %print_error% "'/max_depth' requires a number between 1 and 5!" + exit /b + ) + ) else if /i "%1" == "/c" ( + if exist "%~2" ( + if not exist "%~2\bin" mkdir "%~2\bin" + set "cmder_user_bin=%~2\bin" + if not exist "%~2\config\profile.d" mkdir "%~2\config\profile.d" + set "cmder_user_config=%~2\config" + shift + ) + ) else if /i "%1" == "/user_aliases" ( + if exist "%~2" ( + set "user_aliases=%~2" + shift + ) + ) else if /i "%1" == "/git_install_root" ( + if exist "%~2" ( + set "GIT_INSTALL_ROOT=%~2" + shift + ) else ( + %print_error% "The Git install root folder "%~2" that you specified does not exist!" + exit /b + ) + ) else if /i "%1" == "/nix_tools" ( + if "%2" equ "0" ( + REM Do not add *nix tools to path + set nix_tools=0 + shift + ) else if "%2" equ "1" ( + REM Add *nix tools to end of path + set nix_tools=1 + shift + ) else if "%2" equ "2" ( + REM Add *nix tools to front of path + set nix_tools=2 + shift + ) + ) else if /i "%1" == "/home" ( + if exist "%~2" ( + set "HOME=%~2" + shift + ) else ( + %print_error% The home folder "%2" that you specified does not exist! + exit /b + ) + ) else if /i "%1" == "/svn_ssh" ( + set SVN_SSH=%2 + shift + ) else ( + set "CMDER_USER_FLAGS=%1 %CMDER_USER_FLAGS%" + ) + shift +goto :var_loop + +:start +:: Enable console related methods if verbose/debug is turned on +if %debug_output% gtr 0 (set print_debug=%lib_console% debug_output) +if %verbose_output% gtr 0 ( + set print_verbose=%lib_console% verbose_output + set print_warning=%lib_console% show_warning +) + +:: Sets CMDER_SHELL, CMDER_CLINK, CMDER_ALIASES variables +%lib_base% cmder_shell +%print_debug% init.cmd "Env Var - CMDER_ROOT=%CMDER_ROOT%" +%print_debug% init.cmd "Env Var - debug_output=%debug_output%" + +:: Set the Cmder directory paths +set "CMDER_CONFIG_DIR=%CMDER_ROOT%\config" + +:: Check if we're using Cmder individual user profile +if defined CMDER_USER_CONFIG ( + %print_debug% init.cmd "CMDER IS ALSO USING INDIVIDUAL USER CONFIG FROM '%CMDER_USER_CONFIG%'!" + + if not exist "%CMDER_USER_CONFIG%\..\opt" md "%CMDER_USER_CONFIG%\..\opt" + set "CMDER_CONFIG_DIR=%CMDER_USER_CONFIG%" +) + +if not "%CMDER_SHELL%" == "cmd" ( + %print_warning% "Incompatible 'ComSpec/Shell' Detected: %CMDER_SHELL%" + set CMDER_CLINK=0 + set CMDER_ALIASES=0 +) + +:: Pick the right version of Clink +:: TODO: Support for ARM +if "%PROCESSOR_ARCHITECTURE%"=="x86" ( + set clink_architecture=x86 + set architecture_bits=32 +) else if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + set clink_architecture=x64 + set architecture_bits=64 +) else ( + %print_warning% "Incompatible Processor Detected: %PROCESSOR_ARCHITECTURE%" + set CMDER_CLINK=0 +) + +set "cmder_root_user_init=%CMDER_ROOT%\config\user_init.cmd" +if defined CMDER_USER_CONFIG set "cmder_user_init=%CMDER_USER_CONFIG%\user_init.cmd" + +if exist "%cmder_root_user_init%" ( + call "%cmder_root_user_init%" + exit /b +) + +if defined CMDER_USER_CONFIG if exist "%cmder_user_init%" ( + call "%cmder_user_init%" + exit /b +) + +if "%CMDER_CLINK%" == "1" ( + REM TODO: Detect if clink is already injected, if so goto :CLINK_FINISH + goto :INJECT_CLINK +) else if "%CMDER_CLINK%" == "2" ( + goto :CLINK_FINISH +) + +goto :SKIP_CLINK + +:INJECT_CLINK + %print_verbose% "Injecting Clink!" + + :: Check if Clink is not present + if not exist "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" ( + %print_error% "Clink executable is not present in 'vendor\clink\clink_%clink_architecture%.exe'" + goto :SKIP_CLINK + ) + + :: Run Clink + if not exist "%CMDER_CONFIG_DIR%\settings" if not exist "%CMDER_CONFIG_DIR%\clink_settings" ( + echo Generating Clink initial settings in "%CMDER_CONFIG_DIR%\clink_settings" + copy "%CMDER_ROOT%\vendor\clink_settings.default" "%CMDER_CONFIG_DIR%\clink_settings" + echo Additional *.lua files in "%CMDER_CONFIG_DIR%" are loaded on startup. + ) + + if not exist "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" ( + echo Creating Cmder prompt config file: "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" + copy "%CMDER_ROOT%\vendor\cmder_prompt_config.lua.default" "%CMDER_CONFIG_DIR%\cmder_prompt_config.lua" + ) + + :: Cleanup legacy Clink Settings file + if exist "%CMDER_CONFIG_DIR%\settings" if exist "%CMDER_CONFIG_DIR%\clink_settings" ( + del "%CMDER_CONFIG_DIR%\settings" + ) + + :: Cleanup legacy Clink history file + if exist "%CMDER_CONFIG_DIR%\.history" if exist "%CMDER_CONFIG_DIR%\clink_history" ( + del "%CMDER_CONFIG_DIR%\.history" + ) + + "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" inject --quiet --profile "%CMDER_CONFIG_DIR%" --scripts "%CMDER_ROOT%\vendor" + + :: Check if a fatal error occurred when trying to inject Clink + if errorlevel 2 ( + REM %print_error% "Clink injection has failed with error code: %errorlevel%" + goto :SKIP_CLINK + ) + set CMDER_CLINK=2 + + goto :CLINK_FINISH + +:SKIP_CLINK + %print_warning% "Skipping Clink Injection!" + + for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x + chcp 65001>nul + + :: 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 + +:CLINK_FINISH + +if "%CMDER_CONFIGURED%" GTR "1" ( + %print_verbose% "Cmder is already configured, skipping Cmder Init!" + + goto :USER_ALIASES +) else if "%CMDER_CONFIGURED%" == "1" ( + %print_verbose% "Cmder is already configured, skipping to Cmder User Init!" + + goto :USER_CONFIG_START +) + +:: Prepare for git-for-windows + +:: Detect which git.exe version to use +:: * if the user points to a specific git, use that +:: * test if git is in path and if yes, use that +:: * last, use our vendored git +:: also check that we have a recent enough version of git by examining the version string +if defined GIT_INSTALL_ROOT ( + if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" goto :SPECIFIED_GIT + set GIT_INSTALL_ROOT= +) else if "%fast_init%" == "1" ( + if exist "%CMDER_ROOT%\vendor\git-for-windows\cmd\git.exe" ( + %print_debug% init.cmd "Skipping Git Auto-Detect!" + goto :VENDORED_GIT + ) + + %print_debug% init.cmd "Fast init is enabled, vendored Git does not exist" + for /F "delims=" %%F in ('where git.exe 2^>nul') do ( + set "EXT_GIT_EXE=%%~fF" + %print_debug% init.cmd "Found User installed Git at '%%~fF'. Skipping Git Auto-Detect!" + goto :SET_ENV + ) +) + +%print_debug% init.cmd "Looking for Git install root..." + +:: Get the version information for vendored git binary +%lib_git% read_version VENDORED "%CMDER_ROOT%\vendor\git-for-windows\cmd" 2>nul +%lib_git% validate_version VENDORED %GIT_VERSION_VENDORED% + +:: Check if git is in path +for /F "delims=" %%F in ('where git.exe 2^>nul') do call :check_git "%%~fF" + +if defined GIT_INSTALL_ROOT ( + goto :FOUND_GIT +) else ( + goto :VENDORED_GIT +) + +:check_git + set full_path="%~f1" + if not defined GIT_INSTALL_ROOT ( + if not [\%full_path:\cmd\git.exe=:%]==[\%full_path%] ( + :: Get the absolute path to the user provided git binary + %lib_git% is_git_shim "%~dp1" + %lib_git% get_user_git_version + %lib_git% compare_git_versions + ) + ) + exit /b + +:: Our last hope: use vendored git +:VENDORED_GIT +if exist "%CMDER_ROOT%\vendor\git-for-windows" ( + set "GIT_INSTALL_ROOT=%CMDER_ROOT%\vendor\git-for-windows" + %print_debug% init.cmd "Using vendored Git '%GIT_VERSION_VENDORED%'..." + goto :CONFIGURE_GIT +) else ( + goto :NO_GIT +) + +:SPECIFIED_GIT +%print_debug% init.cmd "Using specified GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT%...." +goto :CONFIGURE_GIT + +:FOUND_GIT +%print_debug% init.cmd "Using found Git '%GIT_VERSION_USER%' from '%GIT_INSTALL_ROOT%..." +goto :CONFIGURE_GIT + +:CONFIGURE_GIT +%print_debug% init.cmd "Using Git from '%GIT_INSTALL_ROOT%..." + +:: Add git to the path +%print_debug% init.cmd "START - git.exe(prepend): Env Var - PATH=%path%" +if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" ( + set "path=%GIT_INSTALL_ROOT%\cmd;%path%" +) +%print_debug% init.cmd "END - git.exe(prepend): Env Var - PATH=%path%" + +:: Add the unix commands at the end to not shadow windows commands like `more` and `find` +if %nix_tools% equ 1 ( + %print_verbose% "Preferring Windows commands" + set "path_position=append" +) else ( + %print_verbose% "Preferring *nix commands" + set "path_position=" +) + +%print_debug% init.cmd "START - nix_tools(%path_position%): Env Var - PATH=%path%" +set "git_mingw_bin=" +if exist "%GIT_INSTALL_ROOT%\mingw32" ( + set "git_mingw_bin=%GIT_INSTALL_ROOT%\mingw32\bin" +) else if exist "%GIT_INSTALL_ROOT%\mingw64" ( + set "git_mingw_bin=%GIT_INSTALL_ROOT%\mingw64\bin" +) + +%lib_path% add_path_with_position "%git_mingw_bin%" "%path_position%" +%lib_path% add_path_with_position "%GIT_INSTALL_ROOT%\usr\bin" "%path_position%" +%print_debug% init.cmd "END - nix_tools(%path_position%): Env Var - PATH=%path%" + +:SET_ENV + +:: Plink (PuTTY Link) is a command-line connection tool similar to ssh, setting its protocol to ssh +set PLINK_PROTOCOL=ssh + +:: Define SVN_SSH so we can use git svn with ssh svn repositories +if not defined SVN_SSH set "SVN_SSH=%GIT_INSTALL_ROOT:\=\\%\\bin\\ssh.exe" + +:: Find locale.exe: From the git install root, from the path, using the git installed env, or fallback using the env from the path. +setlocal enabledelayedexpansion +if not defined git_locale if defined EXT_GIT_EXE ( + set "GIT_INSTALL_ROOT=!EXT_GIT_EXE:\cmd\git.exe=!" +) +endlocal && set GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT% + +if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\locale.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\locale.exe" +if not defined git_locale for /F "tokens=* delims=" %%F in ('where locale.exe 2^>nul') do ( if not defined git_locale set git_locale="%%F" ) +if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\env.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\env.exe" /usr/bin/locale +if not defined git_locale for /F "tokens=* delims=" %%F in ('where env.exe 2^>nul') do ( if not defined git_locale set git_locale="%%F" /usr/bin/locale ) + +setlocal enabledelayedexpansion +if defined git_locale ( + REM %print_debug% init.cmd "Env Var - git_locale=!git_locale!" + if not defined LANG ( + for /F "delims=" %%F in ('"!git_locale!" -uU 2') do ( + set "LANG=%%F" + ) + ) +) +endlocal && set LANG=%LANG% + +%print_debug% init.cmd "Found Git in: 'GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT%'" +goto :PATH_ENHANCE + +:NO_GIT +:: Skip this if GIT WAS FOUND else we did 'endlocal' above! +endlocal + +:PATH_ENHANCE +%print_debug% init.cmd "START - vendor/bin(prepend): Env Var - PATH=%path%" +set "path=%CMDER_ROOT%\vendor\bin;%path%" +%print_debug% init.cmd "END - vendor/bin(prepend): Env Var - PATH=%path%" + +:USER_CONFIG_START +%print_debug% init.cmd "START - bin(prepend): Env Var - PATH=%path%" +if %max_depth% gtr 1 ( + %lib_path% enhance_path_recursive "%CMDER_ROOT%\bin" 0 %max_depth% +) else ( + set "path=%CMDER_ROOT%\bin;%path%" +) +%print_debug% init.cmd "END - bin(prepend): Env Var - PATH=%path%" + +:: The CMDER_USER_BIN variable is set in the launcher. +if defined CMDER_USER_BIN ( + %print_debug% init.cmd "START - user_bin(prepend): Env Var - PATH=%path%" + if %max_depth% gtr 1 ( + %lib_path% enhance_path_recursive "%CMDER_USER_BIN%" 0 %max_depth% + ) else ( + set "path=%CMDER_USER_BIN%;%path%" + ) + %print_debug% init.cmd "END - user_bin(prepend): Env Var - PATH=!path!" +) + +%print_debug% init.cmd "START - cmder_root(append): Env Var - PATH=%path%" +set "path=%path%;%CMDER_ROOT%" +%print_debug% init.cmd "END - cmder_root(append): Env Var - PATH=%path%" + +:: Drop *.bat and *.cmd files into "%CMDER_ROOT%\config\profile.d" +:: to run them at startup. +%lib_profile% run_profile_d "%CMDER_ROOT%\config\profile.d" +if defined CMDER_USER_CONFIG ( + %lib_profile% run_profile_d "%CMDER_USER_CONFIG%\profile.d" +) + +:USER_ALIASES +:: Allows user to override default aliases store using profile.d +:: scripts run above by setting the 'aliases' env variable. +:: +:: Note: If overriding default aliases store file the aliases +:: must also be self executing, see '.\user_aliases.cmd.default', +:: and be in profile.d folder. +if not defined user_aliases ( + set "user_aliases=%CMDER_CONFIG_DIR%\user_aliases.cmd" +) + +if "%CMDER_ALIASES%" == "1" ( + REM The aliases environment variable is used by alias.bat to id + REM the default file to store new aliases in. + if not defined aliases ( + set "aliases=%user_aliases%" + ) + + REM Make sure we have a self-extracting user_aliases.cmd file + if not exist "%user_aliases%" ( + echo Creating initial user_aliases store in "%user_aliases%"... + copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%" + ) else ( + %lib_base% update_legacy_aliases + ) + + :: Update old 'user_aliases' to new self executing 'user_aliases.cmd' + if exist "%CMDER_ROOT%\config\aliases" ( + echo Updating old "%CMDER_ROOT%\config\aliases" to new format... + type "%CMDER_ROOT%\config\aliases" >> "%user_aliases%" + del "%CMDER_ROOT%\config\aliases" + ) else if exist "%user_aliases%.old_format" ( + echo Updating old "%user_aliases%" to new format... + type "%user_aliases%.old_format" >> "%user_aliases%" + del "%user_aliases%.old_format" + ) +) + +:: Add aliases to the environment +type "%user_aliases%" | %WINDIR%\System32\findstr /b /l /i "history=cat " >nul +if "%ERRORLEVEL%" == "0" ( + echo Migrating alias 'history' to new Clink 1.x.x... + call "%CMDER_ROOT%\vendor\bin\alias.cmd" /d history + echo Restart the session to activate changes! +) + +call "%user_aliases%" + +if "%CMDER_CONFIGURED%" gtr "1" goto :CMDER_CONFIGURED + +:: See vendor\git-for-windows\README.portable for why we do this +:: Basically we need to execute this post-install.bat because we are +:: manually extracting the archive rather than executing the 7z sfx +if exist "%GIT_INSTALL_ROOT%\post-install.bat" ( + echo Running Git for Windows one time Post Install.... + pushd "%GIT_INSTALL_ROOT%\" + "%GIT_INSTALL_ROOT%\git-cmd.exe" --no-needs-console --no-cd --command=post-install.bat + popd +) + +:: Set home path +if not defined HOME set "HOME=%USERPROFILE%" +%print_debug% init.cmd "Env Var - HOME=%HOME%" + +set "initialConfig=%CMDER_ROOT%\config\user_profile.cmd" +if exist "%CMDER_ROOT%\config\user_profile.cmd" ( + REM Create this file and place your own command in there + %print_debug% init.cmd "Calling - %CMDER_ROOT%\config\user_profile.cmd" + call "%CMDER_ROOT%\config\user_profile.cmd" +) + +if defined CMDER_USER_CONFIG ( + set "initialConfig=%CMDER_USER_CONFIG%\user_profile.cmd" + if exist "%CMDER_USER_CONFIG%\user_profile.cmd" ( + REM Create this file and place your own command in there + %print_debug% init.cmd "Calling - %CMDER_USER_CONFIG%\user_profile.cmd" + call "%CMDER_USER_CONFIG%\user_profile.cmd" + ) +) + +if not exist "%initialConfig%" ( + echo Creating user startup file: "%initialConfig%" + copy "%CMDER_ROOT%\vendor\user_profile.cmd.default" "%initialConfig%" +) + +if "%CMDER_ALIASES%" == "1" if exist "%CMDER_ROOT%\bin\alias.bat" if exist "%CMDER_ROOT%\vendor\bin\alias.cmd" ( + echo Cmder's 'alias' command has been moved into "%CMDER_ROOT%\vendor\bin\alias.cmd" + echo to get rid of this message either: + echo. + echo Delete the file "%CMDER_ROOT%\bin\alias.bat" + echo. + echo or + echo. + echo If you have customized it and want to continue using it instead of the included version + echo * Rename "%CMDER_ROOT%\bin\alias.bat" to "%CMDER_ROOT%\bin\alias.cmd". + echo * Search for 'user-aliases' and replace it with 'user_aliases'. +) + +set initialConfig= + +if not exist "%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_CONFIG_DIR%\user_init.cmd" ( + %print_error% "Failed to generate Cmder config" + ) +) + +:CMDER_CONFIGURED + if not defined CMDER_CONFIGURED set CMDER_CONFIGURED=1 + set CMDER_INIT_END=%time% + + if "%time_init%" == "1" if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( + call "%cmder_root%\vendor\bin\timer.cmd" "%CMDER_INIT_START%" "%CMDER_INIT_END%" + ) + +:CLEANUP + set architecture_bits= + set cmder_root_user_init= + set cmder_user_init= + set cmder_legacy_init= + set cmder_legacy_init_backup= + set cmder_legacy_init_shim= + set CMDER_ALIASES= + set CMDER_INIT_END= + set CMDER_INIT_START= + set CMDER_USER_FLAGS= + set CMDER_CLINK= + set debug_output= + set fast_init= + set git_mingw_bin= + set max_depth= + set nix_tools= + set path_position= + set print_debug= + set print_error= + set print_verbose= + set print_warning= + set time_init= + set verbose_output= + set user_aliases= + +exit /b diff --git a/vendor/lib/lib_base.cmd b/vendor/lib/lib_base.cmd index 39371c71e..e498aa891 100644 --- a/vendor/lib/lib_base.cmd +++ b/vendor/lib/lib_base.cmd @@ -98,10 +98,9 @@ exit /b :::. ::: This function checks if the user_aliases file contains the marker ::: ";= Add aliases below here". If the marker is not found, it creates -::: an initial user_aliases store by copying the default user_aliases file -::: from the CMDER_ROOT directory. If the CMDER_USER_CONFIG environment -::: variable is defined, it creates a backup of the existing user_aliases -::: file before copying the default file. +::: an initial user_aliases store by backing up the existing file to +::: `*.old_format` and then copying the default user_aliases file from +::: the CMDER_ROOT directory. :::. :::include: :::. @@ -116,12 +115,7 @@ exit /b type "%user_aliases%" | %WINDIR%\System32\findstr /i ";= Add aliases below here" >nul if "%errorlevel%" == "1" ( echo Creating initial user_aliases store in "%user_aliases%"... - if defined CMDER_USER_CONFIG ( - copy "%user_aliases%" "%user_aliases%.old_format" - copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%" - ) else ( - copy "%user_aliases%" "%user_aliases%.old_format" - copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%" - ) + copy "%user_aliases%" "%user_aliases%.old_format" + copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%" ) exit /b diff --git a/vendor/lib/lib_path.cmd b/vendor/lib/lib_path.cmd index 4415388b6..d50d45c4e 100644 --- a/vendor/lib/lib_path.cmd +++ b/vendor/lib/lib_path.cmd @@ -91,13 +91,13 @@ exit /b 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!" @@ -149,16 +149,55 @@ exit /b exit /b +:add_path_with_position +:::=============================================================================== +:::add_path_with_position - Add a directory to PATH at the start or end. +::: +:::include: +::: +::: call "lib_path.cmd" +::: +:::usage: +::: +::: %lib_path% add_path_with_position "[dir_path]" [append] +::: +:::required: +::: +::: [dir_path] Fully qualified directory path. Ex: "c:\bin" +::: +:::options: +::: +::: append Append to the path env variable rather than pre-pend. +::: +:::output: +::: +::: path Updates the path env variable when the directory exists. +:::------------------------------------------------------------------------------- + if "%~1" == "" exit /b + if not exist "%~1" exit /b + + if /i "%~2" == "append" ( + set "path=%path%;%~1" + ) else ( + set "path=%~1;%path%" + ) + + exit /b + :set_found if "%ERRORLEVEL%" == "0" ( - set found=1 + set found=1 ) exit /b :enhance_path_recursive + call :set_path_recursive "%~1" "%~2" "%~3" + exit /b + +:set_path_recursive :::=============================================================================== -:::enhance_path_recursive - Add a directory and subs to the path env variable if +:::set_path_recursive - Add a directory and subs to the path env variable if ::: required. :::. :::include: @@ -167,7 +206,7 @@ exit /b :::. :::usage: :::. -::: call "%~DP0lib_path" enhance_path_recursive "[dir_path]" [max_depth] [append] +::: call "%~DP0lib_path" set_path_recursive "[dir_path]" [max_depth] [append] :::. :::required: :::. @@ -190,13 +229,28 @@ exit /b exit /b 1 ) + rem Parse arguments robustly: + rem Accept either public form: "[dir_path]" [max_depth] [append] + rem or internal recursive form: "[dir_path]" [depth] [max_depth] [append] set "depth=%~2" set "max_depth=%~3" + set "position=" - if "%~4" neq "" if /i "%~4" == "append" ( - set "position=%~4" - ) else ( - set "position=" + if /i "%~4" == "append" set "position=append" + if /i "%~3" == "append" ( + set "position=append" + set "max_depth=" + ) + + if not defined depth set "depth=0" + if not defined max_depth ( + if defined depth ( + rem If only one numeric argument provided, treat it as max_depth + set "max_depth=%depth%" + set "depth=0" + ) else ( + set "max_depth=1" + ) ) dir "%add_path%" 2>NUL | findstr -i -e "%find_pathext%" >NUL @@ -209,7 +263,11 @@ exit /b if "%fast_init%" == "1" ( if "%add_to_path%" neq "" ( - call :enhance_path "%add_to_path%" %position% + if "%position%" == "append" ( + set "path=%path%;%add_to_path%" + ) else ( + set "path=%add_to_path%;%path%" + ) ) ) @@ -218,22 +276,24 @@ exit /b exit /b ) - %print_debug% :enhance_path_recursive "Env Var - add_path=%add_to_path%" - %print_debug% :enhance_path_recursive "Env Var - position=%position%" - %print_debug% :enhance_path_recursive "Env Var - depth=%depth%" - %print_debug% :enhance_path_recursive "Env Var - max_depth=%max_depth%" + %print_debug% :set_path_recursive "Env Var - add_path=%add_to_path%" + %print_debug% :set_path_recursive "Env Var - position=%position%" + %print_debug% :set_path_recursive "Env Var - depth=%depth%" + %print_debug% :set_path_recursive "Env Var - max_depth=%max_depth%" if %max_depth% gtr %depth% ( if "%add_to_path%" neq "" ( - %print_debug% :enhance_path_recursive "Adding parent directory - '%add_to_path%'" - call :enhance_path "%add_to_path%" %position% + %print_debug% :set_path_recursive "Adding parent directory - '%add_to_path%'" + if "%position%" == "append" ( + set "path=%path%;%add_to_path%" + ) else ( + set "path=%add_to_path%;%path%" + ) ) call :set_depth call :loop_depth ) - set "PATH=%PATH%" - exit /b :set_depth @@ -246,9 +306,9 @@ exit /b ) for /d %%i in ("%add_path%\*") do ( - %print_debug% :enhance_path_recursive "Env Var BEFORE - depth=%depth%" - %print_debug% :enhance_path_recursive "Found Subdirectory - '%%~fi'" - call :enhance_path_recursive "%%~fi" %depth% %max_depth% %position% - %print_debug% :enhance_path_recursive "Env Var AFTER- depth=%depth%" + %print_debug% :set_path_recursive "Env Var BEFORE - depth=%depth%" + %print_debug% :set_path_recursive "Found Subdirectory - '%%~fi'" + call :set_path_recursive "%%~fi" %depth% %max_depth% %position% + %print_debug% :set_path_recursive "Env Var AFTER- depth=%depth%" ) exit /b diff --git a/vendor/psmodules/Cmder.ps1 b/vendor/psmodules/Cmder.ps1 index 6de808e4b..2500e9c0e 100644 --- a/vendor/psmodules/Cmder.ps1 +++ b/vendor/psmodules/Cmder.ps1 @@ -249,3 +249,30 @@ function Get-GitStatusSetting { return $true } + +function yOrn( $question ) { + Do { + $Answer = Read-Host -Prompt "`n${question}? (y/n) " + } + Until ($Answer -eq 'y' -or $Answer -eq 'n' -or $Answer -eq 'yes' -or $Answer -eq 'no') + + return $Answer +} + +function TemplateExpand($template_filename, $outfile) { + $template = Get-Content "$template_filename" -Raw -Encoding UTF8 + + $expanded = Invoke-Expression "@`"`r`n$template`r`n`"@" + + $overwrite = 'y' + if ((test-path "$outfile")) { + $overwrite = yOrn "'$outfile' already exists do you want to overwrite it" + } + + if ($overwrite -match 'y') { + $utf8NoBom = New-Object System.Text.UTF8Encoding($false) + [System.IO.File]::WriteAllText($outfile, $expanded, $utf8NoBom) + } else { + write-host "Skipping Cmder '$shell' config generation at user request!" + } +} diff --git a/vendor/start_git_bash.cmd b/vendor/start_git_bash.cmd new file mode 100644 index 000000000..679c5af9e --- /dev/null +++ b/vendor/start_git_bash.cmd @@ -0,0 +1,51 @@ +@echo off + +if not defined CMDER_ROOT ( + if defined ConEmuDir ( + for /f "delims=" %%i in ("%ConEmuDir%\..\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) else ( + for /f "delims=" %%i in ("%~dp0\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) +) + +if defined ConEmuDir ( + set "gitCommand=--command=%ConEmuBaseDirShort%\conemu-msys2-64.exe" +) + +if exist "%CMDER_ROOT%\vendor\git-for-windows" ( + set "PATH=%CMDER_ROOT%\vendor\git-for-windows\usr\bin;%PATH%" + set "gitCmd=%CMDER_ROOT%\vendor\git-for-windows\git-cmd.exe" + set "bashCmd=%CMDER_ROOT%\vendor\git-for-windows\usr\bin\bash.exe" +) else if exist "%ProgramFiles%\git" ( + set "PATH=%ProgramFiles%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles%\git\git-cmd.exe" + set "bashCmd=%ProgramFiles%\git\usr\bin\bash.exe" + if not exist "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) else if exist "%ProgramFiles(x86)%\git" ( + set "PATH=%ProgramFiles(x86)%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles(x86)%\git\git-cmd.exe" + set "bashCmd=%ProgramFiles(x86)%\git\usr\bin\bash.exe" + if not exist "%ProgramFiles(x86)%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) + +if defined ConEmuDir ( + "%gitCmd%" --no-cd %gitCommand% "%bashCmd%" --login -i +) else ( + "%bashCmd%" --login -i +) diff --git a/vendor/start_git_mintty.cmd b/vendor/start_git_mintty.cmd new file mode 100644 index 000000000..ea4f09a9f --- /dev/null +++ b/vendor/start_git_mintty.cmd @@ -0,0 +1,40 @@ +@echo off + +if not defined CMDER_ROOT ( + if defined ConEmuDir ( + for /f "delims=" %%i in ("%ConEmuDir%\..\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) else ( + for /f "delims=" %%i in ("%~dp0\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) +) + +if exist "%CMDER_ROOT%\vendor\git-for-windows" ( + set "PATH=%CMDER_ROOT%\vendor\git-for-windows\usr\bin;%PATH%" + set "gitCmd=%CMDER_ROOT%\vendor\git-for-windows\usr\bin\mintty.exe" +) else if exist "%ProgramFiles%\git" ( + set "PATH=%ProgramFiles%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles%\git\usr\bin\mintty.exe" + if not exist "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) else if exist "%ProgramFiles(x86)%\git" ( + set "PATH=%ProgramFiles(x86)%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles(x86)%\git\usr\bin\mintty.exe" + if not exist "%ProgramFiles(x86)%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) + +"%gitCmd%" /bin/bash -l diff --git a/vendor/user_init.cmd.template b/vendor/user_init.cmd.template new file mode 100644 index 000000000..caf3a61b1 --- /dev/null +++ b/vendor/user_init.cmd.template @@ -0,0 +1,162 @@ +@echo off + +:: This file was autogenerated by Cmder init.cmd +:: +:: It is yours to edit and will not be touched again by Cmder. +:: +:: If you wish to recreate this file simply rename it and Cmder will re-create it the next time it is run +:: or run the following command from a Cmder shell: +:: +:: powershell -f %cmder_root%\vendor\bin\create-cmdercfg.ps1 -shell cmd [-outfile "[filename]"] +:: + +if "%CMDER_CONFIGURED%" == "1" ( + goto CMDER_CONFIGURED +) + +if "%CMDER_CLINK%" == "1" ( + goto :INJECT_CLINK +) else if "%CMDER_CLINK%" == "2" if defined WT_PROFILE_ID ( + goto :INJECT_CLINK +) else if "%CMDER_CLINK%" == "2" ( + goto :CLINK_FINISH +) + +goto :SKIP_CLINK + +:INJECT_CLINK + %print_verbose% "Injecting Clink!" + + :: Check if Clink is not present + if not exist "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" ( + :: This allows the user to install Clink globally and remove it from Cmder if they wish. + :: The user may also want to remove parts of the SKIP_CLINK section. + goto :SKIP_CLINK + ) + + :: Run Clink + "%CMDER_ROOT%\vendor\clink\clink_%clink_architecture%.exe" inject --quiet --profile "%CMDER_CONFIG_DIR%" --scripts "%CMDER_ROOT%\vendor" + + if errorlevel 2 ( + %print_error% "Clink initialization has failed with error code: %errorlevel%" + goto :SKIP_CLINK + ) + + set CMDER_CLINK=2 + goto :CLINK_FINISH + +:SKIP_CLINK + %print_warning% "Skipping Clink Injection!" + + for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x + chcp 65001>nul + + :: 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 + +:CLINK_FINISH + if not defined GIT_INSTALL_ROOT set "GIT_INSTALL_ROOT=$env:GIT_INSTALL_ROOT" + if not defined SVN_SSH set "SVN_SSH=$env:SVN_SSH" + if not defined git_locale set "git_locale=$env:git_locale" + if not defined LANG set "LANG=$env:LANG" + if not defined user_aliases set "user_aliases=$env:user_aliases" + if not defined aliases set "aliases=%user_aliases%" + if not defined HOME set "HOME=%USERPROFILE%" + + set "PLINK_PROTOCOL=$env:PLINK_PROTOCOL" + + if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" ( + set "path=%GIT_INSTALL_ROOT%\cmd;%path%" + ) + + :: Add the unix commands at the end to not shadow windows commands like `more` and `find` + set path_position_nix_tools=append + if %nix_tools% equ 2 ( + set "path_position_nix_tools=prepend" + ) + + :: TODO: Support for ARM + set "git_mingw_bin=" + if "%PROCESSOR_ARCHITECTURE%" == "x86" if exist "%GIT_INSTALL_ROOT%\mingw32" ( + set "git_mingw_bin=%GIT_INSTALL_ROOT%\mingw32\bin" + ) else if "%PROCESSOR_ARCHITECTURE%" == "AMD64" if exist "%GIT_INSTALL_ROOT%\mingw64" ( + set "git_mingw_bin=%GIT_INSTALL_ROOT%\mingw64\bin" + ) + + %lib_path% add_path_with_position "%git_mingw_bin%" "%path_position_nix_tools%" + %lib_path% add_path_with_position "%GIT_INSTALL_ROOT%\usr\bin" "%path_position_nix_tools%" + + set "path=%CMDER_ROOT%\vendor\bin;%path%" + +:USER_CONFIG_START + if %max_depth% gtr 1 ( + %lib_path% enhance_path_recursive "%CMDER_ROOT%\bin" 0 %max_depth% + ) else ( + set "path=%CMDER_ROOT%\bin;%path%" + ) + + :: The CMDER_USER_BIN variable is set in the launcher. + if defined CMDER_USER_BIN ( + if %max_depth% gtr 1 ( + %lib_path% enhance_path_recursive "%CMDER_USER_BIN%" 0 %max_depth% + ) else ( + set "path=%CMDER_USER_BIN%;%path%" + ) + ) + + set "path=%path%;%CMDER_ROOT%" + + call "%user_aliases%" + + :: Drop *.bat and *.cmd files into "%CMDER_ROOT%\config\profile.d" + :: to run them at startup. + %lib_profile% run_profile_d "%CMDER_ROOT%\config\profile.d" + if defined CMDER_USER_CONFIG ( + %lib_profile% run_profile_d "%CMDER_USER_CONFIG%\profile.d" + ) + + call "%CMDER_ROOT%\config\user_profile.cmd" + if defined CMDER_USER_CONFIG ( + if exist "%CMDER_USER_CONFIG%\user_profile.cmd" ( + call "%CMDER_USER_CONFIG%\user_profile.cmd" + ) + ) + + set "path=%path:;;=;%" + +:CMDER_CONFIGURED + if not defined CMDER_CONFIGURED set CMDER_CONFIGURED=1 + + set CMDER_INIT_END=%time% + + if "%time_init%" == "1" if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( + call "%cmder_root%\vendor\bin\timer.cmd" "%CMDER_INIT_START%" "%CMDER_INIT_END%" + ) + +:CLEANUP + set architecture_bits= + set CMDER_ALIASES= + set CMDER_INIT_END= + set CMDER_INIT_START= + set CMDER_USER_FLAGS= + set debug_output= + set fast_init= + set git_mingw_bin= + set max_depth= + set nix_tools= + set path_position= + set print_debug= + set print_error= + set print_verbose= + set print_warning= + set time_init= + set verbose_output= + set user_aliases= + set "PATH=%PATH:;;=;%" + +exit /b diff --git a/vendor/user_profile.cmd.default b/vendor/user_profile.cmd.default index 00c7fb515..239a3c69c 100644 --- a/vendor/user_profile.cmd.default +++ b/vendor/user_profile.cmd.default @@ -11,7 +11,7 @@ :: you can add your plugins to the cmder path like so :: set "PATH=%CMDER_ROOT%\vendor\whatever;%PATH%" -:: arguments in this batch are passed from init.bat, you can quickly parse them like so: +:: arguments in this batch are passed from init.cmd, you can quickly parse them like so: :: more usage can be seen by typing "cexec /?" :: %ccall% "/customOption" "command/program" diff --git a/vendor/windows_terminal_default_settings.json b/vendor/windows_terminal_default_settings.json new file mode 100644 index 000000000..d44c9d9f4 --- /dev/null +++ b/vendor/windows_terminal_default_settings.json @@ -0,0 +1,390 @@ +{ + "$help": "https://aka.ms/terminal-documentation", + "$schema": "https://aka.ms/terminal-profiles-schema", + "actions": [ + { + "command": { + "action": "copy", + "singleLine": false + }, + "keys": "ctrl+shift+c" + }, + { + "command": "unbound", + "keys": "ctrl+v" + }, + { + "command": "unbound", + "keys": "ctrl+c" + }, + { + "command": "paste" + }, + { + "command": "find", + "keys": "ctrl+shift+f" + }, + { + "command": { + "action": "splitPane", + "split": "auto", + "splitMode": "duplicate" + }, + "keys": "alt+shift+d" + } + ], + "copyFormatting": "none", + "copyOnSelect": true, + "defaultProfile": "{48946353-ebe8-4571-a591-7d609f31327a}", + "newTabMenu": [ + { + "type": "remainingProfiles" + } + ], + "profiles": { + "defaults": { + "colorScheme": "One Half Dark", + "font": { + "face": "Cascadia Code" + } + }, + "list": [ + { + "colorScheme": "One Half Dark", + "commandline": "cmd /k \"%WT_SETTINGS_DIR%\\..\\..\\init.cmd\"", + "guid": "{48946353-ebe8-4571-a591-7d609f31327a}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder.ico", + "name": "Cmder", + "startingDirectory": null, + "tabTitle": "Cmder", + "useAtlasEngine": false + }, + { + "colorScheme": "One Half Dark", + "commandline": "%SystemRoot%\\System32\\cmd.exe /k \"%WT_SETTINGS_DIR%\\..\\..\\init.cmd\"", + "elevate": true, + "guid": "{bdd957d0-c15a-49e6-9816-14b02351a071}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder_red.ico", + "name": "Cmder as Admin", + "startingDirectory": null, + "tabTitle": "Cmder as Admin" + }, + { + "colorScheme": "One Half Dark", + "commandline": "PowerShell -ExecutionPolicy Bypass -NoLogo -NoProfile -NoExit -Command \"Invoke-Expression 'Import-Module ''%WT_SETTINGS_DIR%\\..\\..\\profile.ps1'''\"", + "guid": "{eb1f6578-ce9d-47a9-a8c7-9b3fdd22302d}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder_orange.ico", + "name": "Cmder - PowerShell", + "startingDirectory": null, + "tabTitle": "Cmder", + "useAtlasEngine": false + }, + { + "colorScheme": "One Half Dark", + "commandline": "PowerShell -ExecutionPolicy Bypass -NoLogo -NoProfile -NoExit -Command \"Invoke-Expression 'Import-Module ''%WT_SETTINGS_DIR%\\..\\..\\profile.ps1'''\"", + "elevate": true, + "guid": "{c5225c3e-8619-4145-8182-2800814eeb17}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder_purple.ico", + "name": "Cmder - PowerShell as Admin", + "startingDirectory": null, + "tabTitle": "Cmder - PowerShell as Admin", + "useAtlasEngine": false + }, + { + "colorScheme": "One Half Dark", + "commandline": "%WT_SETTINGS_DIR%\\..\\..\\start_git_bash.cmd", + "guid": "{c5c298e9-010e-4b8c-bc55-e3df81846b4c}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder_blue.ico", + "name": "Cmder - Bash", + "startingDirectory": null, + "tabTitle": "Cmder - Bash" + }, + { + "colorScheme": "One Half Dark", + "commandline": "%WT_SETTINGS_DIR%\\..\\..\\start_git_bash.cmd", + "elevate": true, + "guid": "{545eb9ed-4c1c-49b3-8cc6-7eb41bd280ff}", + "hidden": false, + "icon": "%WT_SETTINGS_DIR%\\..\\..\\..\\icons\\cmder_yellow.ico", + "name": "Cmder - Bash as Admin", + "startingDirectory": null, + "tabTitle": "Cmder - Bash as Admin" + }, + { + "commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", + "hidden": false, + "name": "Windows PowerShell" + }, + { + "commandline": "%SystemRoot%\\System32\\cmd.exe", + "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", + "hidden": false, + "name": "Command Prompt" + } + ] + }, + "schemes": [ + { + "background": "#0C0C0C", + "black": "#0C0C0C", + "blue": "#0037DA", + "brightBlack": "#767676", + "brightBlue": "#3B78FF", + "brightCyan": "#61D6D6", + "brightGreen": "#16C60C", + "brightPurple": "#B4009E", + "brightRed": "#E74856", + "brightWhite": "#F2F2F2", + "brightYellow": "#F9F1A5", + "cursorColor": "#FFFFFF", + "cyan": "#3A96DD", + "foreground": "#CCCCCC", + "green": "#13A10E", + "name": "Campbell", + "purple": "#881798", + "red": "#C50F1F", + "selectionBackground": "#FFFFFF", + "white": "#CCCCCC", + "yellow": "#C19C00" + }, + { + "background": "#012456", + "black": "#0C0C0C", + "blue": "#0037DA", + "brightBlack": "#767676", + "brightBlue": "#3B78FF", + "brightCyan": "#61D6D6", + "brightGreen": "#16C60C", + "brightPurple": "#B4009E", + "brightRed": "#E74856", + "brightWhite": "#F2F2F2", + "brightYellow": "#F9F1A5", + "cursorColor": "#FFFFFF", + "cyan": "#3A96DD", + "foreground": "#CCCCCC", + "green": "#13A10E", + "name": "Campbell Powershell", + "purple": "#881798", + "red": "#C50F1F", + "selectionBackground": "#FFFFFF", + "white": "#CCCCCC", + "yellow": "#C19C00" + }, + { + "background": "#282828", + "black": "#282828", + "blue": "#458588", + "brightBlack": "#928374", + "brightBlue": "#83A598", + "brightCyan": "#8EC07C", + "brightGreen": "#B8BB26", + "brightPurple": "#D3869B", + "brightRed": "#FB4934", + "brightWhite": "#EBDBB2", + "brightYellow": "#FABD2F", + "cursorColor": "#FFFFFF", + "cyan": "#689D6A", + "foreground": "#EBDBB2", + "green": "#98971A", + "name": "Gruvbox Dark", + "purple": "#B16286", + "red": "#CC241D", + "selectionBackground": "#FFFFFF", + "white": "#A89984", + "yellow": "#D79921" + }, + { + "background": "#272822", + "black": "#3E3D32", + "blue": "#03395C", + "brightBlack": "#272822", + "brightBlue": "#66D9EF", + "brightCyan": "#66D9EF", + "brightGreen": "#A6E22E", + "brightPurple": "#AE81FF", + "brightRed": "#F92672", + "brightWhite": "#F8F8F2", + "brightYellow": "#FD971F", + "cursorColor": "#FFFFFF", + "cyan": "#66D9EF", + "foreground": "#F8F8F2", + "green": "#A6E22E", + "name": "Monokai", + "purple": "#AE81FF", + "red": "#F92672", + "selectionBackground": "#FFFFFF", + "white": "#F8F8F2", + "yellow": "#FFE792" + }, + { + "background": "#282C34", + "black": "#282C34", + "blue": "#61AFEF", + "brightBlack": "#5A6374", + "brightBlue": "#61AFEF", + "brightCyan": "#56B6C2", + "brightGreen": "#98C379", + "brightPurple": "#C678DD", + "brightRed": "#E06C75", + "brightWhite": "#DCDFE4", + "brightYellow": "#E5C07B", + "cursorColor": "#FFFFFF", + "cyan": "#56B6C2", + "foreground": "#DCDFE4", + "green": "#98C379", + "name": "One Half Dark", + "purple": "#C678DD", + "red": "#E06C75", + "selectionBackground": "#FFFFFF", + "white": "#DCDFE4", + "yellow": "#E5C07B" + }, + { + "background": "#FAFAFA", + "black": "#383A42", + "blue": "#0184BC", + "brightBlack": "#4F525D", + "brightBlue": "#61AFEF", + "brightCyan": "#56B5C1", + "brightGreen": "#98C379", + "brightPurple": "#C577DD", + "brightRed": "#DF6C75", + "brightWhite": "#FFFFFF", + "brightYellow": "#E4C07A", + "cursorColor": "#4F525D", + "cyan": "#0997B3", + "foreground": "#383A42", + "green": "#50A14F", + "name": "One Half Light", + "purple": "#A626A4", + "red": "#E45649", + "selectionBackground": "#FFFFFF", + "white": "#FAFAFA", + "yellow": "#C18301" + }, + { + "background": "#002B36", + "black": "#002B36", + "blue": "#268BD2", + "brightBlack": "#073642", + "brightBlue": "#839496", + "brightCyan": "#93A1A1", + "brightGreen": "#586E75", + "brightPurple": "#6C71C4", + "brightRed": "#CB4B16", + "brightWhite": "#FDF6E3", + "brightYellow": "#657B83", + "cursorColor": "#FFFFFF", + "cyan": "#2AA198", + "foreground": "#839496", + "green": "#859900", + "name": "Solarized Dark", + "purple": "#D33682", + "red": "#DC322F", + "selectionBackground": "#FFFFFF", + "white": "#EEE8D5", + "yellow": "#B58900" + }, + { + "background": "#FDF6E3", + "black": "#002B36", + "blue": "#268BD2", + "brightBlack": "#073642", + "brightBlue": "#839496", + "brightCyan": "#93A1A1", + "brightGreen": "#586E75", + "brightPurple": "#6C71C4", + "brightRed": "#CB4B16", + "brightWhite": "#FDF6E3", + "brightYellow": "#657B83", + "cursorColor": "#002B36", + "cyan": "#2AA198", + "foreground": "#657B83", + "green": "#859900", + "name": "Solarized Light", + "purple": "#D33682", + "red": "#DC322F", + "selectionBackground": "#FFFFFF", + "white": "#EEE8D5", + "yellow": "#B58900" + }, + { + "background": "#000000", + "black": "#000000", + "blue": "#3465A4", + "brightBlack": "#555753", + "brightBlue": "#729FCF", + "brightCyan": "#34E2E2", + "brightGreen": "#8AE234", + "brightPurple": "#AD7FA8", + "brightRed": "#EF2929", + "brightWhite": "#EEEEEC", + "brightYellow": "#FCE94F", + "cursorColor": "#FFFFFF", + "cyan": "#06989A", + "foreground": "#D3D7CF", + "green": "#4E9A06", + "name": "Tango Dark", + "purple": "#75507B", + "red": "#CC0000", + "selectionBackground": "#FFFFFF", + "white": "#D3D7CF", + "yellow": "#C4A000" + }, + { + "background": "#FFFFFF", + "black": "#000000", + "blue": "#3465A4", + "brightBlack": "#555753", + "brightBlue": "#729FCF", + "brightCyan": "#34E2E2", + "brightGreen": "#8AE234", + "brightPurple": "#AD7FA8", + "brightRed": "#EF2929", + "brightWhite": "#EEEEEC", + "brightYellow": "#FCE94F", + "cursorColor": "#000000", + "cyan": "#06989A", + "foreground": "#555753", + "green": "#4E9A06", + "name": "Tango Light", + "purple": "#75507B", + "red": "#CC0000", + "selectionBackground": "#FFFFFF", + "white": "#D3D7CF", + "yellow": "#C4A000" + }, + { + "background": "#000000", + "black": "#000000", + "blue": "#000080", + "brightBlack": "#808080", + "brightBlue": "#0000FF", + "brightCyan": "#00FFFF", + "brightGreen": "#00FF00", + "brightPurple": "#FF00FF", + "brightRed": "#FF0000", + "brightWhite": "#FFFFFF", + "brightYellow": "#FFFF00", + "cursorColor": "#FFFFFF", + "cyan": "#008080", + "foreground": "#C0C0C0", + "green": "#008000", + "name": "Vintage", + "purple": "#800080", + "red": "#800000", + "selectionBackground": "#FFFFFF", + "white": "#C0C0C0", + "yellow": "#808000" + } + ], + "themes": [], + "useAcrylicInTabRow": true, + "wordDelimiters": " ()\"',;<>!@#$%^&*|+=[]{}~?\u2502" +}