Skip to content

Commit 8f0c18a

Browse files
author
88871
committed
fix: normalize path separators in WSL remote sessions
When the extension runs on a non-Windows host (WSL remote, SSH remote) but the configured journal base path is a Windows-style drive path such as C:\Users\...\journal, the path components were concatenated with a mix of backslashes and forward slashes. The result was a malformed path like /C:\Users\...\journal/2026/05/20.md that VS Code could not resolve, causing an empty buffer to be shown instead of the journal entry (#228). Two-layer fix: 1. conf.ts – normalizeBasePathForRuntime: besides the existing /mnt/<drive>/... conversion for explicit Windows drive paths, now also replaces stray backslashes in non-drive POSIX paths so that any Windows-style separator that slipped in via ${workspaceFolder} or similar variables is cleaned up before the path is returned from getBasePath(). 2. template-service.ts – getResolvedEntryPath / getResolvedNotesPath / getResolvedWeeklyNotesPath / getWeekPathPattern: after all template variables are substituted, replace any remaining backslashes with forward slashes on non-Windows hosts before Path.normalize() runs. This acts as a belt-and-suspenders guard so that a Windows-style base path that somehow passes through getBasePath() unchanged cannot corrupt the final resolved path string.
1 parent 9a4d1a1 commit 8f0c18a

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/vscode/conf.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,14 @@ export class Configuration implements IRawConfigProvider {
9595
/**
9696
* Converts Windows-style absolute paths to a runtime-compatible path when
9797
* the extension is running on a non-Windows host (e.g. WSL remote).
98+
*
99+
* Detection uses both `process.platform` and `vscode.env.remoteName` so that
100+
* the normalization fires whenever the extension host is Linux-based — whether
101+
* that is a native Linux installation, an SSH remote, or a WSL remote session
102+
* where the user stored their journal base path as a Windows drive path.
98103
*/
99104
private normalizeBasePathForRuntime(basePath: string): string {
105+
// Running natively on Windows: separators are already correct.
100106
if (process.platform === 'win32') {
101107
return basePath;
102108
}
@@ -106,11 +112,15 @@ export class Configuration implements IRawConfigProvider {
106112
const trimmed = basePath.replace(/^\/+/, '');
107113
const isWindowsAbsPath = /^[a-zA-Z]:[\\/]/.test(trimmed);
108114
if (!isWindowsAbsPath) {
109-
return basePath;
115+
// Not a Windows-style absolute path — nothing to convert.
116+
// Still replace any stray backslashes so mixed-separator strings
117+
// (e.g. from a ${workspaceFolder} expansion) become valid POSIX paths.
118+
return basePath.replace(/\\/g, '/');
110119
}
111120

112121
// Non-Windows remotes (WSL/SSH/containers): map Windows drive path to
113-
// Linux mount style to avoid invalid paths such as /c:\Users\...
122+
// the Linux /mnt/<drive>/... convention used by WSL, avoiding invalid
123+
// mixed paths such as /C:\Users\...\journal/2026/05/20.md.
114124
const drive = trimmed.charAt(0).toLowerCase();
115125
const rest = trimmed.substring(2).replace(/\\/g, '/').replace(/^\/+/, '');
116126
return `/mnt/${drive}/${rest}`;

src/vscode/template-service.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ export class TemplateService {
4040
scopedTemplate.value = replaceVariableValue("homeDir", os.homedir(), scopedTemplate.value);
4141
scopedTemplate.value = replaceVariableValue("base", this.raw.getBasePath(scopeId), scopedTemplate.value);
4242
scopedTemplate.value = resolveDate(scopedTemplate.value, date, this.raw.getLocale());
43+
// On non-Windows hosts, eliminate any residual backslashes so that the
44+
// fully-resolved path is a valid POSIX path (covers WSL remote sessions).
45+
if (process.platform !== 'win32') {
46+
scopedTemplate.value = scopedTemplate.value.replace(/\\/g, '/');
47+
}
4348
return scopedTemplate;
4449
}
4550

@@ -65,6 +70,9 @@ export class TemplateService {
6570
scopedTemplate.value = replaceVariableValue("base", this.raw.getBasePath(scopeId), scopedTemplate.value);
6671
scopedTemplate.value = replaceVariableValue("year", String(year), scopedTemplate.value);
6772
scopedTemplate.value = replaceVariableValue("week", String(week), scopedTemplate.value);
73+
if (process.platform !== 'win32') {
74+
scopedTemplate.value = scopedTemplate.value.replace(/\\/g, '/');
75+
}
6876
return scopedTemplate;
6977
}
7078

@@ -116,6 +124,9 @@ export class TemplateService {
116124
scopedTemplate.value = replaceVariableValue("base", this.raw.getBasePath(scopeId), scopedTemplate.value);
117125
scopedTemplate.value = replaceVariableValue("week", week + "", scopedTemplate.value);
118126
scopedTemplate.value = resolveDate(scopedTemplate.value, new Date(), this.raw.getLocale());
127+
if (process.platform !== 'win32') {
128+
scopedTemplate.value = scopedTemplate.value.replace(/\\/g, '/');
129+
}
119130
scopedTemplate.value = Path.normalize(scopedTemplate.value);
120131
return scopedTemplate;
121132
}
@@ -127,6 +138,13 @@ export class TemplateService {
127138
};
128139
scopedTemplate.value = replaceVariableValue("base", this.raw.getBasePath(scopeId), scopedTemplate.template);
129140
scopedTemplate.value = resolveDate(scopedTemplate.value, date, this.raw.getLocale());
141+
// On non-Windows hosts, convert any residual backslashes to forward slashes
142+
// before normalization so that Windows-style base paths configured for WSL
143+
// remote sessions (e.g. C:\Users\...) do not produce mixed-separator paths
144+
// like /C:\Users\...\journal/2026/05 (see issue #228).
145+
if (process.platform !== 'win32') {
146+
scopedTemplate.value = scopedTemplate.value.replace(/\\/g, '/');
147+
}
130148
scopedTemplate.value = Path.normalize(scopedTemplate.value);
131149
return scopedTemplate;
132150
}

0 commit comments

Comments
 (0)