From 0ea5246c1b73c18c4256b82f44debb6854855702 Mon Sep 17 00:00:00 2001 From: Dion Munk Date: Tue, 6 Oct 2026 22:38:16 -0600 Subject: [PATCH] fix(notes): resolve a relative location against a portable VS Code's folder A portable VS Code keeps everything in its own folder, and #38 wanted the notes there too, with a relative location like `data\Notes`. Such a path was resolved against the extension host's working folder, so notes were listed but didn't open, and since #86 it resolved against the workspace folder instead, which can't find them at all. In a portable VS Code, a relative notes.notesLocation is now resolved against the folder holding it. VS Code sets VSCODE_PORTABLE to its portable data folder (`data` in the program folder on Windows and Linux, `code-portable-data` next to the application on macOS), so the extension uses its parent rather than repeating VS Code's own detection. Outside portable mode nothing changes, and workspace notes stay relative to the workspace folder. --- CHANGELOG.md | 1 + README.md | 2 +- package.json | 2 +- src/extension.ts | 7 ++++--- src/location.ts | 8 ++++++++ src/test/suite/location.test.ts | 15 ++++++++++++++- 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf34dce..9cf63b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * the Notes view is refreshed after a note has been deleted, instead of before * deleting a folder relied on a package that was only installed as a development dependency * New Note and New Folder failed when a note was selected, they now create next to the note (#67, #76) +* in a portable VS Code, a relative storage location is relative to the folder holding VS Code, so notes can be kept with it and opened from there (#38) ## [2.0.0] - 2025-03-26 diff --git a/README.md b/README.md index 154b44c..79a848b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ A multi-root workspace uses the first folder for relative locations. This extension contributes the following settings: -* `Notes.notesLocation`: location of the notes in the Notes section, set in your user settings and not synced between machines +* `Notes.notesLocation`: location of the notes in the Notes section, set in your user settings and not synced between machines. In a [portable](https://code.visualstudio.com/docs/editor/portable) VS Code, a relative path is relative to the folder holding VS Code, so the notes can travel with it (for example `data/Notes` on Windows and Linux) * `Notes.workspaceNotesLocation`: location of the notes in the Workspace Notes section, relative to the workspace folder or a full path * `Notes.notesDefaultNotesExtension`: extension used for new notes * `Notes.notesExtensions`: list of extensions recognized as notes or '*' for all extensions diff --git a/package.json b/package.json index 063b2f5..6f54407 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "type": "string", "default": "", "scope": "machine-overridable", - "description": "Storage location for the Notes view, set in your user settings. A path starting with `~` is in your home folder. Not synced between machines. A value in a workspace's settings is used as that workspace's notes, use `notes.workspaceNotesLocation` for that instead." + "description": "Storage location for the Notes view, set in your user settings. A path starting with `~` is in your home folder. In a portable VS Code, a relative path is relative to the folder holding it, so the notes can travel with it. Not synced between machines. A value in a workspace's settings is used as that workspace's notes, use `notes.workspaceNotesLocation` for that instead." }, "notes.workspaceNotesLocation": { "type": "string", diff --git a/src/extension.ts b/src/extension.ts index 9e2a367..8016028 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { Note } from './note'; import { NotesViewProvider } from './notesViewProvider'; import { NotesWatcher } from './notesWatcher'; -import { getLocationState, resolveNotesLocation, toWorkspaceSetting } from './location'; +import { getLocationState, getPortableFolder, resolveNotesLocation, toWorkspaceSetting } from './location'; let extId = 'vscode-notes'; let extPub = 'dionmunk'; @@ -231,11 +231,12 @@ export class Notes { return vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; } - // get notes storage location, with ~ and a path relative to the workspace folder resolved + // get notes storage location, with ~ and a relative path resolved: against the folder holding a portable + // VS Code, so the notes travel with it, otherwise against the workspace folder // only the user settings count: a notesLocation in workspace settings is that workspace's notes static getNotesLocation(): string { const notesLocation = vscode.workspace.getConfiguration('notes').inspect('notesLocation')?.globalValue; - return resolveNotesLocation(notesLocation, os.homedir(), Notes.getWorkspaceFolder()); + return resolveNotesLocation(notesLocation, os.homedir(), getPortableFolder() ?? Notes.getWorkspaceFolder()); } // get the workspace notes location, '' without a workspace folder or a location diff --git a/src/location.ts b/src/location.ts index 199dfe2..5f63fe3 100644 --- a/src/location.ts +++ b/src/location.ts @@ -61,3 +61,11 @@ export function toWorkspaceSetting(folder: string, workspaceDir: string): string // forward slashes work on every platform, and the setting may be shared through the repository return relative.split(path.sep).join('/'); } + +// the folder holding a portable VS Code, which a relative notes location is resolved against so the notes +// travel with it: VS Code sets VSCODE_PORTABLE to its portable data folder, the `data` folder in the +// program folder on Windows and Linux, or `code-portable-data` next to the application on macOS +export function getPortableFolder(env: NodeJS.ProcessEnv = process.env): string | undefined { + const portableData = env.VSCODE_PORTABLE; + return portableData ? path.dirname(portableData) : undefined; +} diff --git a/src/test/suite/location.test.ts b/src/test/suite/location.test.ts index bb5f21c..0f4d727 100644 --- a/src/test/suite/location.test.ts +++ b/src/test/suite/location.test.ts @@ -2,7 +2,7 @@ import * as assert from 'assert'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { getLocationState, resolveNotesLocation, toWorkspaceSetting } from '../../location'; +import { getLocationState, getPortableFolder, resolveNotesLocation, toWorkspaceSetting } from '../../location'; suite('Notes Location', () => { const home = path.join(path.sep, 'home', 'someone'); @@ -77,4 +77,17 @@ suite('Notes Location', () => { const picked = path.join(workspace, 'docs', 'notes'); assert.strictEqual(resolveNotesLocation(toWorkspaceSetting(picked, workspace), home, workspace), picked); }); + + test('a portable VS Code is the folder holding its portable data folder', () => { + const install = path.join(path.sep, 'usb', 'VSCode'); + assert.strictEqual(getPortableFolder({ VSCODE_PORTABLE: path.join(install, 'data') }), install); + assert.strictEqual(getPortableFolder({}), undefined); + assert.strictEqual(getPortableFolder({ VSCODE_PORTABLE: '' }), undefined); + }); + + test('a relative location in a portable VS Code is inside its folder (#38)', () => { + const install = path.join(path.sep, 'usb', 'VSCode'); + const portable = getPortableFolder({ VSCODE_PORTABLE: path.join(install, 'data') }); + assert.strictEqual(resolveNotesLocation('data/Notes', home, portable), path.join(install, 'data', 'Notes')); + }); });