Repository: JanDeDobbeleer/oh-my-posh
Pull request #5954 (2024-11-28 09:28:15)

feat: single release workflow
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md].
- [x] The commit message follows the [conventional commits][cc] guidelines.
- [x] Tests for the changes have been added (for bug fixes / features).
- [x] Docs have been added/updated (for bug fixes / features).

<!---

Tips:

If you're not comfortable with working with Git,
we're working a guide (https://ohmyposh.dev/docs/contributing/git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7bc4dd9a..c5dace6f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2878,6 +2878,16 @@
         "design",
         "doc"
       ]
+    },
+    {
+      "login": "dusktreader",
+      "name": "Tucker Beck",
+      "avatar_url": "https://avatars.githubusercontent.com/u/713676?v=4",
+      "profile": "https://github.com/dusktreader",
+      "contributions": [
+        "code",
+        "doc"
+      ]
     }
   ],
   "contributorsPerLine": 7,
diff --git a/.github/workflows/microsoft_store.yml b/.github/workflows/microsoft_store.yml
index 3b14c519..2b1f7216 100644
--- a/.github/workflows/microsoft_store.yml
+++ b/.github/workflows/microsoft_store.yml
@@ -1,10 +1,7 @@
 name: Windows Store
 on:
-  workflow_dispatch:
-    inputs:
-      version:
-        description: 'The latest version'
-        required: true
+  release:
+    types: [published]
 
 jobs:
   microsoft_store:
@@ -27,29 +24,29 @@ jobs:
         with:
           command: update
           product-update: '{
-              "packages":[
-                  {
-                    "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v${{ github.event.inputs.version }}/install-x64.msi",
-                    "languages":["en"],
-                    "architectures":["X64"],
-                    "installerParameters":"/quiet INSTALLER=ws",
-                    "isSilentInstall":false
-                  },
-                  {
-                    "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v${{ github.event.inputs.version }}/install-arm64.msi",
-                    "languages":["en"],
-                    "architectures":["Arm64"],
-                    "installerParameters":"/quiet INSTALLER=ws",
-                    "isSilentInstall":false
-                  },
-                  {
-                    "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v${{ github.event.inputs.version }}/install-x86.msi",
-                    "languages":["en"],
-                    "architectures":["X86"],
-                    "installerParameters":"/quiet INSTALLER=ws",
-                    "isSilentInstall":false
-                  }
-              ]
+            "packages":[
+            {
+            "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/${{ github.event.release.tag_name }}/install-x64.msi",
+            "languages":["en"],
+            "architectures":["X64"],
+            "installerParameters":"/quiet INSTALLER=ws",
+            "isSilentInstall":false
+            },
+            {
+            "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/${{ github.event.release.tag_name }}/install-arm64.msi",
+            "languages":["en"],
+            "architectures":["Arm64"],
+            "installerParameters":"/quiet INSTALLER=ws",
+            "isSilentInstall":false
+            },
+            {
+            "packageUrl":"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/${{ github.event.release.tag_name }}/install-x86.msi",
+            "languages":["en"],
+            "architectures":["X86"],
+            "installerParameters":"/quiet INSTALLER=ws",
+            "isSilentInstall":false
+            }
+            ]
             }'
       - name: Publish Submission
         uses: jandedobbeleer/store-submission@submission-status
diff --git a/.github/workflows/msi.yml b/.github/workflows/msi.yml
deleted file mode 100644
index 86bde2a9..00000000
--- a/.github/workflows/msi.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-name: MSI
-on:
-  release:
-    types: [published]
-
-jobs:
-  package:
-    runs-on: windows-latest
-    strategy:
-      matrix:
-        arch: [x64, arm64, x86]
-    defaults:
-      run:
-        shell: pwsh
-        working-directory: ${{ github.workspace }}/packages/msi
-    steps:
-      - name: Checkout code 👋
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
-      - name: Install Wix Toolset 🛠
-        run: dotnet tool install --global wix
-      - name: Build installer 📦
-        id: build
-        env:
-          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
-          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
-          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
-        run: |
-          $version = $env:GITHUB_REF.TrimStart("refs/tags/v")
-          ./build.ps1 -Architecture ${{ matrix.arch }}  -Version $version -Download -Sign
-      - name: Upload artifacts 🆙
-        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
-        with:
-          github-token: ${{secrets.GITHUB_TOKEN}}
-          script: |
-            console.log('environment', process.versions);
-
-            const fs = require('fs').promises;
-
-            const { repo: { owner, repo }, sha } = context;
-            console.log({ owner, repo, sha });
-
-            for (let file of await fs.readdir('./packages/msi/out')) {
-              if (file.indexOf(".msi") < 0) {
-                continue;
-              }
-
-              console.log('uploading', file);
-
-              await github.rest.repos.uploadReleaseAsset({
-                owner, repo,
-                release_id: ${{ github.event.release.id }},
-                name: file,
-                data: await fs.readFile(`./packages/msi/out/${file}`)
-              });
-            }
-  notify:
-    runs-on: ubuntu-latest
-    needs: package
-    strategy:
-      matrix:
-        workflow: [winget, microsoft_store]
-    steps:
-      - name: Notify 🙋🏾‍♀️
-        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
-        with:
-          github-token: ${{ secrets.GH_PAT }}
-          script: |
-            await github.request('POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches', {
-              owner: 'jandedobbeleer',
-              repo: '${{ github.event.repository.name }}',
-              workflow_id: '${{ matrix.workflow }}.yml',
-              ref: 'main',
-              inputs: {"version": process.env.GITHUB_REF.replace('refs/tags/v', '')}
-            })
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 127c219f..67257f1b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -5,13 +5,13 @@ on:
     branches:
       - main
     paths:
-      - 'src/**'
-      - 'packages/**'
-      - '.github/workflows/**'
+      - "src/**"
+      - "packages/**"
+      - ".github/workflows/**"
 
 jobs:
   changelog:
-    runs-on: macos-latest
+    runs-on: ubuntu-latest
     outputs:
       version: ${{ steps.changelog.outputs.version }}
       body: ${{ steps.changelog.outputs.clean_changelog }}
@@ -29,6 +29,8 @@ jobs:
           output-file: "false"
           skip-commit: "true"
           skip-on-empty: "true"
+          skip-tag: "true"
+
   artifacts:
     needs: changelog
     if: ${{ needs.changelog.outputs.skipped == 'false' }}
@@ -36,38 +38,17 @@ jobs:
     defaults:
       run:
         shell: pwsh
-        working-directory: ${{ github.workspace }}/src
+        working-directory: ${{ github.workspace }}/build
     steps:
       - name: Checkout code 👋
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
       - name: Install Go 🗳
         uses: ./.github/workflows/composite/bootstrap-go
-      - name: Tag HEAD 😸
-        run: |
-          git config --global user.name "GitHub Actions"
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git tag ${{ needs.changelog.outputs.tag }}
-      - name: Prerequisites 🔐
-        run: |
-          $PSDefaultParameterValues['Out-File:Encoding']='UTF8'
-
-          $shaSigningKeyLocation = Join-Path -Path $env:RUNNER_TEMP -ChildPath sha_signing_key.pem
-          $env:SIGNING_KEY > $shaSigningKeyLocation
-          Write-Output "SHA_SIGNING_KEY_LOCATION=$shaSigningKeyLocation" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
-
-          # install code signing dlib
-          nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.60 -ExcludeVersion -OutputDirectory $env:RUNNER_TEMP
-          Write-Output "SIGNTOOLDLIB=$env:RUNNER_TEMP/Microsoft.Trusted.Signing.Client/bin/x64/Azure.CodeSigning.Dlib.dll" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
-
-          # requires Windows Dev Kit 10.0.22621.0
-          $signtool = 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe'
-          Write-Output "SIGNTOOL=$signtool" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
-
-          # openssl
-          $openssl = 'C:/Program Files/Git/usr/bin/openssl.exe'
-          Write-Output "OPENSSL=$openssl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+      - name: Pre Build 😸
         env:
           SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
+        run: |
+          ./pre.ps1 -Version ${{ needs.changelog.outputs.version }}
       - name: Run GoReleaser 🚀
         uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf
         with:
@@ -79,21 +60,85 @@ jobs:
           AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
           AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
           AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
-      - name: Zip theme files 🤐
+      - name: Post Build 🤐
+        run: |
+          ./post.ps1
+      - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
+        with:
+          name: build-artifacts
+          path: |
+            src/dist/posh-*
+            src/dist/themes.*
+            src/dist/checksums.*
+  msi:
+    needs:
+      - changelog
+      - artifacts
+    runs-on: windows-latest
+    strategy:
+      matrix:
+        arch: [x64, arm64, x86]
+    defaults:
+      run:
+        shell: pwsh
+        working-directory: ${{ github.workspace }}/packages/msi
+    steps:
+      - name: Checkout code 👋
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+      - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
+        with:
+          name: build-artifacts
+          path: dist
+      - name: Install Wix Toolset 🛠
+        run: dotnet tool install --global wix
+      - name: Build installer 📦
+        id: build
+        env:
+          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+        run: |
+          $version = '${{ needs.changelog.outputs.version }}'.TrimStart("v")
+          ./build.ps1 -Architecture ${{ matrix.arch }}  -Version $version -Copy -Sign
+      - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
+        with:
+          name: msi-artifact-${{ matrix.arch }}
+          path: |
+            packages/msi/out/install-${{ matrix.arch }}.msi
+            packages/msi/out/install-${{ matrix.arch }}.msi.sha256
+  cdn:
+    runs-on: ubuntu-latest
+    needs:
+      - changelog
+      - msi
+    strategy:
+      matrix:
+        arch: [x64, arm64, x86]
+    steps:
+      - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
+        with:
+          name: msi-artifact-${{ matrix.arch }}
+      - name: Upload MSI to CDN
+        env:
+          CDN_CONNECTIONSTRING: ${{ secrets.CDN_CONNECTIONSTRING }}
         run: |
-          $compress = @{
-            Path = "../themes/*.omp.*"
-            CompressionLevel = "Fastest"
-            DestinationPath = "./dist/themes.zip"
-          }
-          Compress-Archive @compress
-      - name: Add hashes 🤫
+          az storage blob upload --container-name v${{ needs.changelog.outputs.version }} --file install-${{ matrix.arch }}.msi --connection-string $CDN_CONNECTIONSTRING
+          az storage blob upload --container-name latest --file install-${{ matrix.arch }}.msi --overwrite true --connection-string $CDN_CONNECTIONSTRING
+  release:
+    runs-on: ubuntu-latest
+    needs:
+      - changelog
+      - cdn
+    steps:
+      - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
+        with:
+          merge-multiple: true
+      - name: Upload version file
+        env:
+          CDN_CONNECTIONSTRING: ${{ secrets.CDN_CONNECTIONSTRING }}
         run: |
-          Get-ChildItem ./dist -Exclude *.yaml,*.sig | Get-Unique |
-          Foreach-Object {
-            $zipHash = Get-FileHash $_.FullName -Algorithm SHA256
-            $zipHash.Hash | Out-File -Encoding 'UTF8' "./dist/$($_.Name).sha256"
-          }
+          echo v${{ needs.changelog.outputs.version }} > version.txt
+          az storage blob upload --container-name latest --file version.txt --overwrite true --connection-string $CDN_CONNECTIONSTRING
       - name: Release 🎓
         uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974
         with:
@@ -102,6 +147,4 @@ jobs:
           fail_on_unmatched_files: true
           token: ${{ secrets.GH_PAT }}
           files: |
-            src/dist/posh-*
-            src/dist/themes.*
-            src/dist/checksums.*
+            *
diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml
index e800ff55..3069acb2 100644
--- a/.github/workflows/winget.yml
+++ b/.github/workflows/winget.yml
@@ -1,10 +1,7 @@
 name: Winget
 on:
-  workflow_dispatch:
-    inputs:
-      version:
-        description: 'The latest version'
-        required: true
+  release:
+    types: [published]
 
 jobs:
   publish:
@@ -20,4 +17,4 @@ jobs:
       uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
     - name: Create manifest and submit PR 📦
       run: |
-        ./build.ps1 -Version "${{ github.event.inputs.version }}" -Token $env:WINGETCREATE_TOKEN
+        ./build.ps1 -Version "${{ github.event.release.tag_name }}" -Token $env:WINGETCREATE_TOKEN
diff --git a/build/post.ps1 b/build/post.ps1
new file mode 100644
index 00000000..226ee7cb
--- /dev/null
+++ b/build/post.ps1
@@ -0,0 +1,16 @@
+# Description: Post build script to compress the themes and generate SHA256 hashes for all files in the dist folder
+
+# Compress all themes
+$compress = @{
+    Path             = "../themes/*.omp.*"
+    CompressionLevel = "Fastest"
+    DestinationPath  = "../src/dist/themes.zip"
+}
+Compress-Archive @compress
+
+# Generate SHA256 hashes for all files in the dist folder
+Get-ChildItem ./dist -Exclude *.yaml, *.sig | Get-Unique |
+Foreach-Object {
+    $zipHash = Get-FileHash $_.FullName -Algorithm SHA256
+    $zipHash.Hash | Out-File -Encoding 'UTF8' "../src/dist/$($_.Name).sha256"
+}
diff --git a/build/pre.ps1 b/build/pre.ps1
new file mode 100644
index 00000000..5929c10f
--- /dev/null
+++ b/build/pre.ps1
@@ -0,0 +1,30 @@
+Param
+(
+    [string]
+    $Version,
+    [parameter(Mandatory = $false)]
+    [string]
+    $SDKVersion = "10.0.22621.0"
+)
+
+git config --global user.name "GitHub Actions"
+git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
+git tag $Version --force
+
+$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'
+
+$shaSigningKeyLocation = Join-Path -Path $env:RUNNER_TEMP -ChildPath sha_signing_key.pem
+$env:SIGNING_KEY > $shaSigningKeyLocation
+Write-Output "SHA_SIGNING_KEY_LOCATION=$shaSigningKeyLocation" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+# install code signing dlib
+nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.60 -ExcludeVersion -OutputDirectory $env:RUNNER_TEMP
+Write-Output "SIGNTOOLDLIB=$env:RUNNER_TEMP/Microsoft.Trusted.Signing.Client/bin/x64/Azure.CodeSigning.Dlib.dll" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+# requires Windows Dev Kit 10.0.22621.0
+$signtool = "C:/Program Files (x86)/Windows Kits/10/bin/$SDKVersion/x64/signtool.exe"
+Write-Output "SIGNTOOL=$signtool" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+# openssl
+$openssl = 'C:/Program Files/Git/usr/bin/openssl.exe'
+Write-Output "OPENSSL=$openssl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
diff --git a/packages/msi/build.ps1 b/packages/msi/build.ps1
index f0bee419..7a62731b 100644
--- a/packages/msi/build.ps1
+++ b/packages/msi/build.ps1
@@ -9,8 +9,8 @@ Param
     [parameter(Mandatory = $false)]
     [string]
     $SDKVersion = "10.0.22621.0",
-    [switch]$Download,
-    [switch]$Sign
+    [switch]$Sign,
+    [switch]$Copy
 )
 
 $PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'
@@ -18,24 +18,23 @@ $PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'
 New-Item -Path "." -Name "dist" -ItemType Directory -ErrorAction SilentlyContinue
 New-Item -Path "." -Name "out" -ItemType Directory -ErrorAction SilentlyContinue
 
-if ($Download) {
-    # download the executable
+if ($Copy) {
     switch ($Architecture) {
         'x86' { $file = "posh-windows-386.exe" }
         'x64' { $file = "posh-windows-amd64.exe" }
         Default { $file = "posh-windows-$Architecture.exe" }
     }
 
-    $name = "oh-my-posh.exe"
-    $url = "https://github.com/jandedobbeleer/oh-my-posh/releases/download/v$Version/$file"
-    Invoke-WebRequest $url -Out "./dist/$($name)"
+    # copy the correct architecture to ./dist
+    Copy-Item -Path "../../dist/$file" -Destination "./dist/oh-my-posh.exe"
 }
 
 # variables
 $env:VERSION = $Version
 
 # create MSI
-$installer = "./out/install-$Architecture.msi"
+$fileName = "install-$Architecture.msi"
+$installer = "./out/$fileName"
 wix build -arch $Architecture -out $installer .\oh-my-posh.wxs
 
 if ($Sign) {
diff --git a/packages/winget/JanDeDobbeleer.OhMyPosh.installer.yaml b/packages/winget/JanDeDobbeleer.OhMyPosh.installer.yaml
index 53f542bf..00fd4047 100644
--- a/packages/winget/JanDeDobbeleer.OhMyPosh.installer.yaml
+++ b/packages/winget/JanDeDobbeleer.OhMyPosh.installer.yaml
@@ -11,42 +11,42 @@ InstallModes:
 - silentWithProgress
 Installers:
 - Architecture: x64
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-x64.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-x64.msi
   InstallerSha256: <HASH-AMD64>
   Scope: machine
   UpgradeBehavior: install
   InstallerSwitches:
      Custom: INSTALLER=winget ALLUSERS=1
 - Architecture: x64
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-x64.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-x64.msi
   InstallerSha256: <HASH-AMD64>
   Scope: user
   UpgradeBehavior: install
   InstallerSwitches:
      Custom: INSTALLER=winget
 - Architecture: x86
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-x86.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-x86.msi
   InstallerSha256: <HASH-386>
   Scope: machine
   UpgradeBehavior: install
   InstallerSwitches:
      Custom: INSTALLER=winget ALLUSERS=1
 - Architecture: x86
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-x86.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-x86.msi
   InstallerSha256: <HASH-386>
   Scope: user
   UpgradeBehavior: install
   InstallerSwitches:
      Custom: INSTALLER=winget
 - Architecture: arm64
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-arm64.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-arm64.msi
   InstallerSha256: <HASH-ARM64>
   Scope: machine
   UpgradeBehavior: install
   InstallerSwitches:
      Custom: INSTALLER=winget ALLUSERS=1
 - Architecture: arm64
-  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v<VERSION>/install-arm64.msi
+  InstallerUrl: https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/<VERSION>/install-arm64.msi
   InstallerSha256: <HASH-ARM64>
   Scope: user
   UpgradeBehavior: install
diff --git a/src/prompt/engine.go b/src/prompt/engine.go
index 72829bc4..2ed895ab 100644
--- a/src/prompt/engine.go
+++ b/src/prompt/engine.go
@@ -20,9 +20,11 @@ type Engine struct {
 	activeSegment         *config.Segment
 	previousActiveSegment *config.Segment
 	rprompt               string
+	Overflow              config.Overflow
 	prompt                strings.Builder
 	currentLineLength     int
 	rpromptLength         int
+	Padding               int
 	Plain                 bool
 }
 
@@ -157,7 +159,13 @@ func (e *Engine) shouldFill(filler string, padLength int) (string, bool) {
 		return "", false
 	}
 
-	if padLength <= 0 {
+	tmpl := &template.Text{
+		Template: filler,
+		Context:  e,
+	}
+
+	var err error
+	if filler, err = tmpl.Render(); err != nil {
 		return "", false
 	}
 
@@ -218,6 +226,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
 
 		// we can't print the right block as there's not enough room available
 		if !OK {
+			e.Overflow = block.Overflow
 			switch block.Overflow {
 			case config.Break:
 				e.writeNewline()
@@ -234,6 +243,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
 
 		defer func() {
 			e.currentLineLength = 0
+			e.Overflow = ""
 		}()
 
 		// validate if we have a filler and fill if needed
diff --git a/website/docs/configuration/block.mdx b/website/docs/configuration/block.mdx
index 41968474..59338a3d 100644
--- a/website/docs/configuration/block.mdx
+++ b/website/docs/configuration/block.mdx
@@ -71,6 +71,27 @@ to be repeated to this property. Add this property to the _right_ aligned block.
   }}
 />
 
+Filler allows you to specify a template to tweak the text used as filler. This template behaves the same as
+Segment templates, however, fewer properties are available.
+
+| Name        | Type   | Description                                                           |
+| ----------- | ------ | --------------------------------------------------------------------- |
+| `.Overflow` | `text` | if no overflow was needed, this is empty. Otherwise `hide` or `break` |
+| `.Padding`  | `int`  | the computed length of the padding between left and right blocks      |
+
+This can be very useful if you wish to use a filler text when there is no overflow and use
+empty space when the right block is hidden or drawn on a newline due to overflow.
+
+<Config
+  data={{
+    block: {
+      alignment: "right",
+      overflow: "hide",
+      filler: "{{ if .Overflow }} {{ else }}-{{ end }}",
+    },
+  }}
+/>
+
 ### Overflow
 
 - `break`
diff --git a/website/docs/contributors.md b/website/docs/contributors.md
index ec5b336b..7c0d0955 100644
--- a/website/docs/contributors.md
+++ b/website/docs/contributors.md
@@ -404,6 +404,7 @@ Thanks goes to these wonderful people ([emoji key][acek]):
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/vshulcz"><img src="https://avatars.githubusercontent.com/u/99616188?v=4?s=100" width="100px;" alt="Vlad Shulcz"/><br /><sub><b>Vlad Shulcz</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=vshulcz" title="Code">💻</a></td>
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/Silzinc"><img src="https://avatars.githubusercontent.com/u/128738169?v=4?s=100" width="100px;" alt="Silzinc"/><br /><sub><b>Silzinc</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Silzinc" title="Code">💻</a> <a href="#design-Silzinc" title="Design">🎨</a> <a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Silzinc" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="14.28%"><a href="https://github.com/Hampter"><img src="https://avatars.githubusercontent.com/u/23213489?v=4?s=100" width="100px;" alt="Noah Springer"/><br /><sub><b>Noah Springer</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Hampter" title="Code">💻</a> <a href="#design-Hampter" title="Design">🎨</a> <a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Hampter" title="Documentation">📖</a></td>
+      <td align="center" valign="top" width="14.28%"><a href="https://github.com/dusktreader"><img src="https://avatars.githubusercontent.com/u/713676?v=4?s=100" width="100px;" alt="Tucker Beck"/><br /><sub><b>Tucker Beck</b></sub></a><br /><a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dusktreader" title="Code">💻</a> <a href="https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dusktreader" title="Documentation">📖</a></td>
     </tr>
   </tbody>
 </table>


Test patch:
diff --git a/src/prompt/engine_test.go b/src/prompt/engine_test.go
index 4cf42b30..a16e41f8 100644
--- a/src/prompt/engine_test.go
+++ b/src/prompt/engine_test.go
@@ -2,9 +2,11 @@ package prompt
 
 import (
 	"errors"
+	"strings"
 	"testing"
 
 	"github.com/jandedobbeleer/oh-my-posh/src/cache"
+	"github.com/jandedobbeleer/oh-my-posh/src/color"
 	"github.com/jandedobbeleer/oh-my-posh/src/config"
 	"github.com/jandedobbeleer/oh-my-posh/src/maps"
 	"github.com/jandedobbeleer/oh-my-posh/src/runtime"
@@ -276,3 +278,112 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
 		assert.Equal(t, tc.Expected, got)
 	}
 }
+
+func TestShouldFill(t *testing.T) {
+	cases := []struct {
+		Case           string
+		Overflow       config.Overflow
+		ExpectedFiller string
+		Block          config.Block
+		Padding        int
+		ExpectedBool   bool
+	}{
+		{
+			Case:           "Plain single character with no padding",
+			Padding:        0,
+			ExpectedFiller: "",
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "-",
+			},
+		},
+		{
+			Case:           "Plain single character with 1 padding",
+			Padding:        1,
+			ExpectedFiller: "-",
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "-",
+			},
+		},
+		{
+			Case:           "Plain single character with lots of padding",
+			Padding:        200,
+			ExpectedFiller: strings.Repeat("-", 200),
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "-",
+			},
+		},
+		{
+			Case:           "Plain multi-character with some padding",
+			Padding:        20,
+			ExpectedFiller: strings.Repeat("-^-", 6) + "  ",
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "-^-",
+			},
+		},
+		{
+			Case:           "Template conditional on overflow with no overflow",
+			Padding:        3,
+			ExpectedFiller: strings.Repeat("X", 3),
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "{{ if .Overflow -}} O {{- else -}} X {{- end }}",
+			},
+		},
+		{
+			Case:           "Template conditional on overflow with an overflow",
+			Overflow:       config.Break,
+			Padding:        3,
+			ExpectedFiller: strings.Repeat("O", 3),
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Hide,
+				Filler:   "{{ if .Overflow -}} O {{- else -}} X {{- end }}",
+			},
+		},
+		{
+			Case:           "Template conditional on overflow break",
+			Overflow:       config.Break,
+			Padding:        3,
+			ExpectedFiller: strings.Repeat("O", 3),
+			ExpectedBool:   true,
+			Block: config.Block{
+				Overflow: config.Break,
+				Filler:   `{{ if eq .Overflow "break" -}} O {{- else -}} X {{- end }}`,
+			},
+		},
+	}
+
+	for _, tc := range cases {
+		env := new(mock.Environment)
+		env.On("Shell").Return(shell.GENERIC)
+
+		engine := &Engine{
+			Env:      env,
+			Overflow: tc.Overflow,
+		}
+
+		template.Cache = &cache.Template{
+			Shell:    shell.GENERIC,
+			Segments: maps.NewConcurrent(),
+		}
+		template.Init(env, nil)
+
+		terminal.Init(shell.GENERIC)
+		terminal.Plain = true
+		terminal.Colors = &color.Defaults{}
+
+		gotFiller, gotBool := engine.shouldFill(tc.Block.Filler, tc.Padding)
+
+		assert.Equal(t, tc.ExpectedFiller, gotFiller, tc.Case)
+		assert.Equal(t, tc.ExpectedBool, gotBool, tc.Case)
+	}
+}