diff --git a/README.md b/README.md index 749934a..6679eb6 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ So settings live in [`User/`](User/) as ordinary files, and less magic than Settings Sync and more legible: a diff shows what changed. It **copies rather than symlinks** on purpose. A symlink at -`%APPDATA%\Code\User\settings.json` is fragile — an editor that saves atomically (write +`Code/User/settings.json` is fragile — an editor that saves atomically (write a temp file, rename it over the target) replaces the link with a regular file, and the sync stops without anything looking broken. @@ -75,7 +75,7 @@ Never in this repo. `publish.ps1` and `install.ps1` read, in order: 1. `-Token ` 2. `$env:GITEA_TOKEN` -3. `%USERPROFILE%\.gitea-token` +3. `~/.gitea-token` (`%USERPROFILE%\.gitea-token` on Windows) Create one at `/user/settings/applications` with **`write:repository`** scope. `install.ps1` only reads, so a `read:repository` token is enough there — and if the @@ -176,5 +176,8 @@ once installed. Both were checked by hand. - **`dev-link.ps1` and `install.ps1` conflict.** A junctioned source and an installed `.vsix` are two copies of the same extension id; VS Code loads one arbitrarily. `dev-link.ps1 -Unlink` before installing. -- **Windows-only paths.** The scripts assume `%APPDATA%\Code\User` and - `%USERPROFILE%\.vscode\extensions`. `ci-release.sh` is the portable half. +- **Linux and macOS need pwsh.** The scripts run under PowerShell 7 (`pwsh`) there and + find VS Code's user folder at `~/.config/Code/User` (`~/Library/Application Support/Code/User` + on macOS) and the CLI in the usual apt, snap, flatpak and Homebrew locations. Set + `VSCODE_USER_DIR` for Insiders or a portable install. `dev-link.ps1` makes a symlink + instead of a junction. `ci-release.sh` needs only bash. diff --git a/scripts/common.ps1 b/scripts/common.ps1 index df0b6c4..71143c3 100644 --- a/scripts/common.ps1 +++ b/scripts/common.ps1 @@ -71,7 +71,7 @@ function Get-GiteaToken { if ($Token) { return $Token } if ($env:GITEA_TOKEN) { return $env:GITEA_TOKEN } - $file = Join-Path $env:USERPROFILE '.gitea-token' + $file = Join-Path (Get-HomeDir) '.gitea-token' if (Test-Path $file) { $value = (Get-Content $file -Raw).Trim() if ($value) { return $value } @@ -283,16 +283,59 @@ function Get-VsceCommand { $entry } +function Test-IsWindows { + <# + Windows PowerShell 5.1 has no $IsWindows (it only ever runs on Windows); pwsh 6+ + defines it on every platform. So: undefined means Windows. + #> + if (Test-Path variable:IsWindows) { return [bool] $IsWindows } + return $true +} + +function Get-HomeDir { + <# $HOME is set by both editions on every platform; USERPROFILE only exists on Windows. #> + if ($HOME) { return $HOME } + if ($env:USERPROFILE) { return $env:USERPROFILE } + throw 'Neither $HOME nor USERPROFILE is set.' +} + +function Get-CodeUserDir { + <# + VS Code's user folder, where settings.json and keybindings.json live. Set + VSCODE_USER_DIR to override, e.g. for Insiders or a portable install. + #> + if ($env:VSCODE_USER_DIR) { return $env:VSCODE_USER_DIR } + if (Test-IsWindows) { return Join-Path $env:APPDATA 'Code\User' } + if ((Test-Path variable:IsMacOS) -and $IsMacOS) { + return Join-Path (Get-HomeDir) 'Library/Application Support/Code/User' + } + $configHome = if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { Join-Path (Get-HomeDir) '.config' } + return Join-Path $configHome 'Code/User' +} + function Get-CodeCommand { <# The VS Code CLI. Not always on PATH, so fall back to the usual install locations. #> $onPath = Get-Command code -ErrorAction SilentlyContinue if ($onPath) { return $onPath.Source } - $candidates = @( - (Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code\bin\code.cmd'), - 'C:\Program Files\Microsoft VS Code\bin\code.cmd', - (Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code Insiders\bin\code-insiders.cmd') - ) + $candidates = if (Test-IsWindows) { + @( + (Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code\bin\code.cmd'), + 'C:\Program Files\Microsoft VS Code\bin\code.cmd', + (Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code Insiders\bin\code-insiders.cmd') + ) + } else { + @( + '/usr/bin/code', + '/usr/share/code/bin/code', + '/snap/bin/code', + '/var/lib/flatpak/exports/bin/com.visualstudio.code', + (Join-Path (Get-HomeDir) '.local/bin/code'), + '/usr/local/bin/code', + '/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code', + '/usr/bin/code-insiders' + ) + } foreach ($candidate in $candidates) { if (Test-Path $candidate) { return $candidate } } diff --git a/scripts/dev-link.ps1 b/scripts/dev-link.ps1 index c42a436..34f2fdb 100644 --- a/scripts/dev-link.ps1 +++ b/scripts/dev-link.ps1 @@ -38,7 +38,7 @@ $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'common.ps1') $config = Get-SetupConfig -$extensionsDir = Join-Path $env:USERPROFILE '.vscode\extensions' +$extensionsDir = Join-Path (Get-HomeDir) '.vscode/extensions' if (-not (Test-Path $extensionsDir)) { New-Item -ItemType Directory -Path $extensionsDir -Force | Out-Null } @@ -103,7 +103,9 @@ foreach ($extension in $extensions) { "(it may be a real installed copy).") } - New-Item -ItemType Junction -Path $link -Target $source | Out-Null + # A junction needs no privilege on Windows; elsewhere a plain symlink does the same job. + $linkType = if (Test-IsWindows) { 'Junction' } else { 'SymbolicLink' } + New-Item -ItemType $linkType -Path $link -Target $source | Out-Null Write-Host "linked $linkName -> $source" -ForegroundColor Green } diff --git a/scripts/settings.ps1 b/scripts/settings.ps1 index eee0ad8..64a1cc0 100644 --- a/scripts/settings.ps1 +++ b/scripts/settings.ps1 @@ -35,11 +35,11 @@ $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'common.ps1') $repoUser = Join-Path (Get-RepoRoot) 'User' -$codeUser = Join-Path $env:APPDATA 'Code\User' +$codeUser = Get-CodeUserDir if (-not (Test-Path $codeUser)) { throw ("VS Code's user folder was not found at $codeUser. If you use Insiders or a " + - "portable install, point APPDATA at it or copy by hand.") + "portable install, set VSCODE_USER_DIR to it or copy by hand.") } # Only the things worth version-controlling. Everything else in User/ is state: