Skip to content

Commit 3eeffd5

Browse files
author
Your Name
committed
v0.1.2: fix theme download stdout leak, fix chocolatey+winget release
- Fix PowerShell Invoke-WebRequest progress output leaking to TUI (root cause of black tab bar) - Add $ProgressPreference = 'SilentlyContinue' to all PowerShell download commands - Add Stdio::piped() to all subprocess calls to prevent stdout/stderr leaks - Fix Chocolatey nuspec schema namespace (chocolatey.org -> microsoft.com/2010/07) - Use WriteAllText for nuspec to ensure clean UTF-8 without BOM - Fix winget: use wingetcreate new+submit for first-time package, update for subsequent - Change winget PackageIdentifier to marlocarlo.OmpManager (proper casing) - Bump version to 0.1.2
1 parent c922e14 commit 3eeffd5

7 files changed

Lines changed: 116 additions & 48 deletions

File tree

.github/workflows/release.yml

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ jobs:
142142
143143
New-Item -ItemType Directory -Force -Path choco/tools
144144
145-
@"
145+
$nuspec = @"
146146
<?xml version="1.0" encoding="utf-8"?>
147-
<package xmlns="http://schemas.chocolatey.org/packaging/2015/06/nuspec.xsd">
147+
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
148148
<metadata>
149149
<id>omp-manager</id>
150150
<version>$version</version>
@@ -154,13 +154,17 @@ jobs:
154154
<projectUrl>https://github.com/marlocarlo/omp-manager</projectUrl>
155155
<licenseUrl>https://github.com/marlocarlo/omp-manager/blob/master/LICENSE</licenseUrl>
156156
<requireLicenseAcceptance>false</requireLicenseAcceptance>
157-
<description>A TUI manager for Oh My Posh - browse themes, install fonts, and configure shells with zero effort.</description>
158-
<tags>oh-my-posh prompt theme tui terminal</tags>
157+
<description>A TUI manager for Oh My Posh — browse themes, install fonts, and configure shells with zero effort.</description>
158+
<summary>TUI manager for Oh My Posh prompt theming</summary>
159+
<tags>oh-my-posh prompt theme tui terminal cli</tags>
160+
<packageSourceUrl>https://github.com/marlocarlo/omp-manager</packageSourceUrl>
161+
<bugTrackerUrl>https://github.com/marlocarlo/omp-manager/issues</bugTrackerUrl>
159162
</metadata>
160163
</package>
161-
"@ | Out-File -Encoding utf8 choco/omp-manager.nuspec
164+
"@
165+
[System.IO.File]::WriteAllText("$PWD/choco/omp-manager.nuspec", $nuspec.Trim())
162166
163-
@"
167+
$install = @"
164168
`$ErrorActionPreference = 'Stop'
165169
`$toolsDir = Split-Path -Parent `$MyInvocation.MyCommand.Definition
166170
`$url = '$url'
@@ -171,7 +175,8 @@ jobs:
171175
-UnzipLocation `$toolsDir ``
172176
-Checksum64 `$checksum ``
173177
-ChecksumType64 'sha256'
174-
"@ | Out-File -Encoding utf8 choco/tools/chocolateyinstall.ps1
178+
"@
179+
[System.IO.File]::WriteAllText("$PWD/choco/tools/chocolateyinstall.ps1", $install.Trim())
175180
176181
choco pack choco/omp-manager.nuspec --output-directory choco
177182
@@ -210,11 +215,90 @@ jobs:
210215
- name: Install wingetcreate
211216
shell: pwsh
212217
run: |
218+
$ProgressPreference = 'SilentlyContinue'
213219
Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
214220
215221
- name: Submit to winget-pkgs
216222
shell: pwsh
217223
run: |
218224
$version = "${{ steps.version.outputs.VERSION }}"
225+
$sha256 = "${{ steps.checksum.outputs.SHA256 }}"
219226
$url = "https://github.com/marlocarlo/omp-manager/releases/download/${{ github.ref_name }}/omp-manager-x86_64-pc-windows-msvc.zip"
220-
./wingetcreate.exe update marlocarlo.omp-manager --version $version --urls $url --token ${{ secrets.WINGET_GH_PAT }} --submit
227+
228+
# Try update first (works when the package already exists in winget-pkgs)
229+
./wingetcreate.exe update marlocarlo.OmpManager `
230+
--version $version --urls $url `
231+
--token ${{ secrets.WINGET_GH_PAT }} --submit 2>&1 | Tee-Object -Variable updateOutput
232+
233+
if ($LASTEXITCODE -ne 0) {
234+
Write-Host "Package not yet in winget-pkgs — creating initial manifest..."
235+
236+
$manifestDir = "manifests/m/marlocarlo/OmpManager/$version"
237+
New-Item -ItemType Directory -Force -Path $manifestDir
238+
239+
# Version manifest
240+
@"
241+
# Created using GitHub Actions automated release pipeline
242+
# yaml-language-server: `$schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json
243+
PackageIdentifier: marlocarlo.OmpManager
244+
PackageVersion: $version
245+
DefaultLocale: en-US
246+
ManifestType: version
247+
ManifestVersion: 1.6.0
248+
"@ | ForEach-Object { $_.Trim() } | Set-Content -Path "$manifestDir/marlocarlo.OmpManager.yaml" -Encoding utf8NoBOM
249+
250+
# Installer manifest
251+
@"
252+
# yaml-language-server: `$schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json
253+
PackageIdentifier: marlocarlo.OmpManager
254+
PackageVersion: $version
255+
InstallerType: zip
256+
NestedInstallerType: portable
257+
NestedInstallerFiles:
258+
- RelativeFilePath: omp-manager.exe
259+
PortableCommandAlias: omp-manager
260+
Installers:
261+
- Architecture: x64
262+
InstallerUrl: $url
263+
InstallerSha256: $sha256
264+
ManifestType: installer
265+
ManifestVersion: 1.6.0
266+
"@ | ForEach-Object { $_.Trim() } | Set-Content -Path "$manifestDir/marlocarlo.OmpManager.installer.yaml" -Encoding utf8NoBOM
267+
268+
# Locale manifest
269+
@"
270+
# yaml-language-server: `$schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json
271+
PackageIdentifier: marlocarlo.OmpManager
272+
PackageVersion: $version
273+
PackageLocale: en-US
274+
Publisher: marlocarlo
275+
PublisherUrl: https://github.com/marlocarlo
276+
PackageName: OMP Manager
277+
PackageUrl: https://github.com/marlocarlo/omp-manager
278+
License: MIT
279+
LicenseUrl: https://github.com/marlocarlo/omp-manager/blob/master/LICENSE
280+
ShortDescription: A TUI manager for Oh My Posh — browse themes, install fonts, and configure shells
281+
Description: A terminal user interface to browse themes, install Nerd Fonts, and configure shell profiles for Oh My Posh with zero effort.
282+
Tags:
283+
- cli
284+
- oh-my-posh
285+
- prompt
286+
- terminal
287+
- tui
288+
ManifestType: defaultLocale
289+
ManifestVersion: 1.6.0
290+
"@ | ForEach-Object { $_.Trim() } | Set-Content -Path "$manifestDir/marlocarlo.OmpManager.locale.en-US.yaml" -Encoding utf8NoBOM
291+
292+
Write-Host "Generated manifests in $manifestDir"
293+
Get-ChildItem -Recurse $manifestDir | ForEach-Object { Write-Host $_.FullName }
294+
295+
# Validate and submit
296+
./wingetcreate.exe submit $manifestDir `
297+
--prtitle "New package: marlocarlo.OmpManager version $version" `
298+
--token ${{ secrets.WINGET_GH_PAT }}
299+
300+
if ($LASTEXITCODE -ne 0) {
301+
Write-Error "wingetcreate submit failed"
302+
exit 1
303+
}
304+
}

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "omp-manager"
3-
version = "0.1.0"
3+
version = "0.1.2"
44
edition = "2021"
55
description = "A TUI manager for Oh My Posh - browse themes, install fonts, and configure shells with zero effort"
66
license = "MIT"

src/detect.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ fn list_nerd_fonts() -> Vec<String> {
162162
Select-Object -ExpandProperty Name
163163
"#;
164164
Command::new("powershell")
165-
.args(["-NoProfile", "-Command", script])
165+
.args(["-NoProfile", "-Command", &format!("$ProgressPreference = 'SilentlyContinue'; {}", script)])
166+
.stdout(std::process::Stdio::piped())
167+
.stderr(std::process::Stdio::piped())
166168
.output()
167169
.ok()
168170
.and_then(|o| String::from_utf8(o.stdout).ok())

src/install.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ fn install_omp_windows() -> OpResult {
4444
let result2 = Command::new("powershell")
4545
.args([
4646
"-NoProfile", "-ExecutionPolicy", "Bypass", "-Command",
47-
"Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://ohmyposh.dev/install.ps1'))"
47+
"$ProgressPreference = 'SilentlyContinue'; Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://ohmyposh.dev/install.ps1'))"
4848
])
49+
.stdout(std::process::Stdio::piped())
50+
.stderr(std::process::Stdio::piped())
4951
.output();
5052
match result2 {
5153
Ok(o) if o.status.success() => OpResult {

src/main.rs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ mod theme;
1515
mod themes;
1616
mod ui;
1717

18-
use std::io::{self, BufWriter};
18+
use std::io;
1919
use std::time::Duration;
2020

2121
use crossterm::{
2222
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind},
23-
execute, queue,
24-
terminal::{disable_raw_mode, enable_raw_mode, BeginSynchronizedUpdate, EndSynchronizedUpdate, EnterAlternateScreen, LeaveAlternateScreen},
23+
execute,
24+
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
2525
};
2626
use ratatui::{backend::CrosstermBackend, Terminal};
2727

@@ -42,11 +42,7 @@ async fn main() -> anyhow::Result<()> {
4242
enable_raw_mode()?;
4343
let mut stdout = io::stdout();
4444
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
45-
// 1 MiB BufWriter ensures the entire frame (escape-sequences for every
46-
// changed cell) fits in a single buffer, so `flush()` emits one large
47-
// write() syscall instead of many 8 KiB partial writes that the
48-
// terminal would render individually, causing a visible flicker.
49-
let backend = CrosstermBackend::new(BufWriter::with_capacity(1_048_576, stdout));
45+
let backend = CrosstermBackend::new(stdout);
5046
let mut terminal = Terminal::new(backend)?;
5147

5248
// Run
@@ -63,22 +59,15 @@ async fn main() -> anyhow::Result<()> {
6359
// ── Event loop ───────────────────────────────────────────────────────────────
6460

6561
fn run_app(
66-
terminal: &mut Terminal<CrosstermBackend<BufWriter<io::Stdout>>>,
62+
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
6763
app: &mut App,
6864
) -> anyhow::Result<()> {
69-
let mut needs_redraw = true;
70-
7165
loop {
72-
// Draw only when state has changed (prevents flickering from constant redraws)
73-
if needs_redraw {
74-
// Synchronized update: tell the terminal to buffer all screen
75-
// writes until EndSynchronizedUpdate, then paint in one pass.
76-
// Combined with the 1 MiB BufWriter this guarantees flicker-free
77-
// atomic frame updates on Windows Terminal, ConPTY, etc.
78-
queue!(terminal.backend_mut(), BeginSynchronizedUpdate)?;
79-
terminal.draw(|f| ui::draw(f, app))?;
80-
execute!(terminal.backend_mut(), EndSynchronizedUpdate)?;
81-
needs_redraw = false;
66+
// Draw every frame (ratatui diffs internally – unchanged frames are cheap)
67+
terminal.draw(|f| ui::draw(f, app))?;
68+
69+
if !app.running {
70+
return Ok(());
8271
}
8372

8473
// Poll events (~20 fps)
@@ -97,14 +86,9 @@ fn run_app(
9786
} else {
9887
handle_normal_input(app, key.code, key.modifiers);
9988
}
100-
needs_redraw = true;
10189
}
10290
Event::Mouse(mouse) => {
10391
handle_mouse(app, mouse.kind, mouse.column, mouse.row);
104-
needs_redraw = true;
105-
}
106-
Event::Resize(_, _) => {
107-
needs_redraw = true;
10892
}
10993
_ => {}
11094
}
@@ -113,19 +97,10 @@ fn run_app(
11397
// Tick status message countdown
11498
if app.status.tick > 0 {
11599
app.tick_status();
116-
needs_redraw = true;
117100
}
118101

119102
// Apply any completed background theme downloads
120-
let prev_downloading = app.theme_downloading.len();
121103
app.poll_theme_downloads();
122-
if app.theme_downloading.len() != prev_downloading {
123-
needs_redraw = true;
124-
}
125-
126-
if !app.running {
127-
return Ok(());
128-
}
129104
}
130105
}
131106

src/themes.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,13 +296,16 @@ pub fn download_theme(name: &str, dest_dir: &Path) -> Result<PathBuf, String> {
296296
#[cfg(target_os = "windows")]
297297
{
298298
let ps_cmd = format!(
299-
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
299+
"$ProgressPreference = 'SilentlyContinue'; \
300+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
300301
Invoke-WebRequest -Uri '{}' -OutFile '{}' -UseBasicParsing",
301302
url,
302303
dest.to_string_lossy()
303304
);
304305
let output = std::process::Command::new("powershell")
305306
.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &ps_cmd])
307+
.stdout(std::process::Stdio::piped())
308+
.stderr(std::process::Stdio::piped())
306309
.output()
307310
.map_err(|e| format!("Failed to run PowerShell: {e}"))?;
308311
if !output.status.success() {
@@ -315,6 +318,8 @@ pub fn download_theme(name: &str, dest_dir: &Path) -> Result<PathBuf, String> {
315318
{
316319
let output = std::process::Command::new("curl")
317320
.args(["-fsSL", "-o", &dest.to_string_lossy(), &url])
321+
.stdout(std::process::Stdio::piped())
322+
.stderr(std::process::Stdio::piped())
318323
.output()
319324
.map_err(|e| format!("Failed to run curl: {e}"))?;
320325
if !output.status.success() {

0 commit comments

Comments
 (0)