param(
[ValidateSet("auto", "vscode", "vscodium")]
[string]$Editor = "auto"
)
$ErrorActionPreference = "Stop"
Write-Host "Islands Dark Theme Installer for Windows" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
Write-Host ""
if ($env:ISLANDS_DARK_EDITOR -and $Editor -eq "auto") {
$Editor = $env:ISLANDS_DARK_EDITOR
}
$Editor = $Editor.ToLowerInvariant()
if ($Editor -eq "codium") {
$Editor = "vscodium"
} elseif ($Editor -eq "code") {
$Editor = "vscode"
}
if ($Editor -eq "auto") {
if (Get-Command "code" -ErrorAction SilentlyContinue) {
$Editor = "vscode"
} elseif (Get-Command "codium" -ErrorAction SilentlyContinue) {
$Editor = "vscodium"
} else {
$Editor = "vscode"
}
}
if ($Editor -eq "vscodium") {
$editorName = "VSCodium"
$cliName = "codium"
$extRoot = "$env:USERPROFILE\.vscode-oss\extensions"
$settingsDir = "$env:APPDATA\VSCodium\User"
$processName = "VSCodium"
$possiblePaths = @(
"$env:LOCALAPPDATA\Programs\VSCodium\bin\codium.cmd",
"$env:ProgramFiles\VSCodium\bin\codium.cmd",
"${env:ProgramFiles(x86)}\VSCodium\bin\codium.cmd"
)
} else {
$editorName = "VS Code"
$cliName = "code"
$extRoot = "$env:USERPROFILE\.vscode\extensions"
$settingsDir = "$env:APPDATA\Code\User"
$processName = "Code"
$possiblePaths = @(
"$env:LOCALAPPDATA\Programs\Microsoft VS Code\bin\code.cmd",
"$env:ProgramFiles\Microsoft VS Code\bin\code.cmd",
"${env:ProgramFiles(x86)}\Microsoft VS Code\bin\code.cmd"
)
}
$codePath = Get-Command $cliName -ErrorAction SilentlyContinue
if (-not $codePath) {
$found = $false
foreach ($path in $possiblePaths) {
if (Test-Path $path) {
$env:Path += ";$(Split-Path $path)"
$found = $true
break
}
}
if (-not $found) {
Write-Host "Error: $editorName CLI ($cliName) not found!" -ForegroundColor Red
Write-Host "Please install $editorName and make sure '$cliName' command is in your PATH."
Write-Host "You can do this by:"
Write-Host " 1. Open $editorName"
Write-Host " 2. Press Ctrl+Shift+P"
Write-Host " 3. Type 'Shell Command: Install $cliName command in PATH'"
exit 1
}
}
Write-Host "$editorName CLI found" -ForegroundColor Green
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Write-Host ""
Write-Host "Step 1: Installing Islands Dark theme extension..."
$extDir = Join-Path $extRoot "bwya77.islands-dark-1.0.0"
if (Test-Path $extDir) {
Remove-Item -Recurse -Force $extDir
}
New-Item -ItemType Directory -Path $extDir -Force | Out-Null
Copy-Item "$scriptDir\package.json" "$extDir\" -Force
Copy-Item "$scriptDir\themes" "$extDir\themes" -Recurse -Force
if (Test-Path "$extDir\themes") {
Write-Host "Theme extension installed to $extDir" -ForegroundColor Green
} else {
Write-Host "Failed to install theme extension" -ForegroundColor Red
exit 1
}
$extJson = Join-Path $extRoot "extensions.json"
if (Test-Path $extJson) {
$extJsonBackup = "$extJson.pre-islands-dark.$(Get-Date -Format 'yyyyMMddHHmmss')"
Copy-Item $extJson $extJsonBackup -Force
Remove-Item $extJson -Force
Write-Host "Backed up extensions.json and cleared it ($editorName will rebuild it)" -ForegroundColor Green
Write-Host " Backup: $extJsonBackup" -ForegroundColor DarkGray
}
Write-Host ""
Write-Host "Step 2: Installing Custom UI Style extension..."
try {
$output = & $cliName --install-extension subframe7536.custom-ui-style --force 2>&1
Write-Host "Custom UI Style extension installed" -ForegroundColor Green
} catch {
Write-Host "Could not install Custom UI Style extension automatically" -ForegroundColor Yellow
Write-Host " Please install it manually from the Extensions marketplace"
}
Write-Host ""
Write-Host "Step 3: Installing Bear Sans UI fonts..."
$fontDir = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts"
if (-not (Test-Path $fontDir)) {
New-Item -ItemType Directory -Path $fontDir -Force | Out-Null
}
$fontPreExistence = @{}
$fontFiles = Get-ChildItem "$scriptDir\fonts\*.otf" -ErrorAction SilentlyContinue
foreach ($f in $fontFiles) {
$destPath = Join-Path $fontDir $f.Name
$fontPreExistence[$f.Name] = @{
wasPresentBeforeInstall = (Test-Path $destPath)
installedPath = $destPath
}
}
try {
$fonts = Get-ChildItem "$scriptDir\fonts\*.otf"
foreach ($font in $fonts) {
try {
Copy-Item $font.FullName $fontDir -Force -ErrorAction SilentlyContinue
} catch {
}
}
Write-Host "Fonts installed" -ForegroundColor Green
Write-Host " Note: You may need to restart applications to use the new fonts" -ForegroundColor DarkGray
} catch {
Write-Host "Could not install fonts automatically" -ForegroundColor Yellow
Write-Host " Please manually install the fonts from the 'fonts/' folder"
Write-Host " Select all .otf files and right-click > Install"
}
Write-Host ""
Write-Host "Step 4: Applying $editorName settings..."
if (-not (Test-Path $settingsDir)) {
New-Item -ItemType Directory -Path $settingsDir -Force | Out-Null
}
$settingsFile = Join-Path $settingsDir "settings.json"
function Strip-Jsonc {
param([string]$Text)
$result = [System.Text.StringBuilder]::new($Text.Length)
$inString = $false
$escaped = $false
$i = 0
while ($i -lt $Text.Length) {
$c = $Text[$i]
if ($escaped) {
[void]$result.Append($c)
$escaped = $false
$i++
continue
}
if ($c -eq '\' -and $inString) {
[void]$result.Append($c)
$escaped = $true
$i++
continue
}
if ($c -eq '"') {
$inString = -not $inString
[void]$result.Append($c)
$i++
continue
}
if (-not $inString) {
if ($c -eq '/' -and ($i + 1) -lt $Text.Length -and $Text[$i + 1] -eq '/') {
while ($i -lt $Text.Length -and $Text[$i] -ne "`n") { $i++ }
continue
}
if ($c -eq '/' -and ($i + 1) -lt $Text.Length -and $Text[$i + 1] -eq '*') {
$i += 2
while ($i -lt $Text.Length) {
if ($Text[$i] -eq '*' -and ($i + 1) -lt $Text.Length -and $Text[$i + 1] -eq '/') {
$i += 2
break
}
$i++
}
continue
}
}
[void]$result.Append($c)
$i++
}
$resultStr = $result.ToString()
$resultStr = $resultStr -replace ',\s*([}\]])', '$1'
return $resultStr
}
$newSettings = Get-Content "$scriptDir\settings.json" -Raw | ConvertFrom-Json
if (Test-Path $settingsFile) {
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$backupFile = "$settingsFile.pre-islands-dark.$timestamp"
Copy-Item $settingsFile $backupFile -Force
Write-Host "Existing settings.json backed up to:" -ForegroundColor Yellow
Write-Host " $backupFile"
Write-Host " You can restore your old settings from this file if needed."
try {
$existingRaw = Get-Content $settingsFile -Raw
try {
$existingSettings = $existingRaw | ConvertFrom-Json
} catch {
$existingSettings = (Strip-Jsonc $existingRaw) | ConvertFrom-Json
}
$mergedSettings = [ordered]@{}
$existingSettings.PSObject.Properties | ForEach-Object {
$mergedSettings[$_.Name] = $_.Value
}
$newSettings.PSObject.Properties | ForEach-Object {
$mergedSettings[$_.Name] = $_.Value
}
$stylesheetKey = 'custom-ui-style.stylesheet'
if ($existingSettings.$stylesheetKey -and $newSettings.$stylesheetKey) {
$mergedStylesheet = [ordered]@{}
$existingSettings.$stylesheetKey.PSObject.Properties | ForEach-Object {
$mergedStylesheet[$_.Name] = $_.Value
}
$newSettings.$stylesheetKey.PSObject.Properties | ForEach-Object {
$mergedStylesheet[$_.Name] = $_.Value
}
$mergedSettings[$stylesheetKey] = [PSCustomObject]$mergedStylesheet
}
[PSCustomObject]$mergedSettings | ConvertTo-Json -Depth 100 | Set-Content $settingsFile
Write-Host "Settings merged (your non-theme settings preserved, theme settings updated)" -ForegroundColor Green
} catch {
Write-Host "Could not parse existing settings.json - leaving it untouched" -ForegroundColor Yellow
Write-Host " Your backup is at: $backupFile" -ForegroundColor DarkGray
Write-Host " To apply Islands Dark settings, manually merge from: $scriptDir\settings.json" -ForegroundColor DarkGray
Write-Host " Error: $($_.Exception.Message)" -ForegroundColor DarkGray
}
} else {
Copy-Item "$scriptDir\settings.json" $settingsFile -Force
Write-Host "Islands Dark settings applied" -ForegroundColor Green
}
$stateFile = Join-Path $settingsDir ".islands-dark-state.json"
if (-not (Test-Path $stateFile)) {
$state = [ordered]@{
previousColorTheme = "Default Dark+"
previousIconTheme = ""
customUiStyleWasInstalled = $false
settingsBackupPath = ""
extensionsJsonBackupPath = ""
fonts = @{}
installedAt = (Get-Date -Format "o")
}
if ($backupFile -and (Test-Path $backupFile)) {
try {
$backupRaw = Get-Content $backupFile -Raw
try { $backupSettings = $backupRaw | ConvertFrom-Json }
catch { $backupSettings = (Strip-Jsonc $backupRaw) | ConvertFrom-Json }
if ($backupSettings.'workbench.colorTheme') {
$state.previousColorTheme = $backupSettings.'workbench.colorTheme'
}
if ($backupSettings.'workbench.iconTheme') {
$state.previousIconTheme = $backupSettings.'workbench.iconTheme'
}
} catch {}
$state.settingsBackupPath = $backupFile
}
if ($extJsonBackup -and (Test-Path $extJsonBackup)) {
$state.extensionsJsonBackupPath = $extJsonBackup
}
$cuiExtDirs = Get-ChildItem "$extRoot\subframe7536.custom-ui-style-*" -Directory -ErrorAction SilentlyContinue
if ($cuiExtDirs) {
$state.customUiStyleWasInstalled = $true
}
$fontState = [ordered]@{}
foreach ($key in $fontPreExistence.Keys) {
$fontState[$key] = [ordered]@{
wasPresentBeforeInstall = $fontPreExistence[$key].wasPresentBeforeInstall
installedPath = $fontPreExistence[$key].installedPath
}
}
$state.fonts = [PSCustomObject]$fontState
[PSCustomObject]$state | ConvertTo-Json -Depth 10 | Set-Content $stateFile
Write-Host "Pre-install state saved for clean uninstall" -ForegroundColor DarkGray
}
Write-Host ""
Write-Host "Step 5: Enabling Custom UI Style..."
$firstRunFile = Join-Path $scriptDir ".islands_dark_first_run"
if (-not (Test-Path $firstRunFile)) {
New-Item -ItemType File -Path $firstRunFile | Out-Null
Write-Host ""
Write-Host "Important Notes:" -ForegroundColor Yellow
Write-Host " - IBM Plex Mono and FiraCode Nerd Font Mono need to be installed separately"
Write-Host " - After $editorName reloads, you may see a 'corrupt installation' warning"
Write-Host " - This is expected - click the gear icon and select 'Don't Show Again'"
Write-Host ""
Read-Host "Press Enter to continue and reload $editorName"
}
Write-Host " Applying CSS customizations..."
Write-Host ""
Write-Host "Islands Dark theme has been installed!" -ForegroundColor Green
Write-Host ""
Write-Host " Closing $editorName..." -ForegroundColor Cyan
Stop-Process -Name $processName -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
Write-Host " Relaunching $editorName..." -ForegroundColor Cyan
Start-Process $cliName -ErrorAction SilentlyContinue
Write-Host ""
Write-Host "=========================================" -ForegroundColor Cyan
Write-Host " IMPORTANT: One more step required!" -ForegroundColor Cyan
Write-Host "=========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "To activate the custom UI styling:" -ForegroundColor Yellow
Write-Host " 1. Wait for $editorName to finish loading"
Write-Host " 2. Press Ctrl+Shift+P to open the Command Palette"
Write-Host " 3. Type: Custom UI Style: Reload" -ForegroundColor White
Write-Host " 4. Press Enter and $editorName will reload with the new styling"
Write-Host ""
Write-Host "You only need to do this once (or after $editorName updates)." -ForegroundColor DarkGray
Write-Host ""
Start-Sleep -Seconds 3