Skip to content

Commit 033549f

Browse files
committed
feat: add wslConvertWindowsPath option for WSL path conversion control
Add a new configuration option `wslConvertWindowsPath` to control whether WSL paths should be converted to Windows paths in WSL remote mode. - Default is true (convert to Windows path) for Windows applications - Set to false to keep WSL native path for WSL applications like evince - Fixes #74 (WSL applications) while maintaining compatibility with #16 (Windows applications) Changes: - Add wslConvertWindowsPath field to ExternalAppConfig interface - Update package.json schema and validation logic - Add i18n translations for 5 languages - Refactor path conversion to handle once at the beginning of open() - Add WSL usage documentation in README
1 parent ffbc322 commit 033549f

File tree

11 files changed

+139
-73
lines changed

11 files changed

+139
-73
lines changed

README.md

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,9 @@ Yes, you can use shellEnv to set additional environment variables:
177177
{
178178
"title": "run ts file",
179179
"shellCommand": "ts-node ${file}",
180-
"shellEnv":
181-
{
182-
"TOKEN": "tyekjjbqbptcxeycgmwqfepus"
183-
},
180+
"shellEnv": {
181+
"TOKEN": "tyekjjbqbptcxeycgmwqfepus"
182+
}
184183
}
185184
]
186185
}
@@ -200,41 +199,81 @@ Or you can set separate environment variables for Windows, Linux and macOS:
200199
{
201200
"title": "run ts file",
202201
"shellCommand": "ts-node ${file}",
203-
"shellEnv":
204-
{
205-
"windows":
206-
{
207-
"PLATFORM": "Windows"
208-
},
209-
"linux":
210-
{
211-
"PLATFORM": "GNU/Linux"
212-
},
213-
"osx":
214-
{
215-
"PLATFORM": "macOS"
216-
},
202+
"shellEnv": {
203+
"windows": {
204+
"PLATFORM": "Windows"
205+
},
206+
"linux": {
207+
"PLATFORM": "GNU/Linux"
217208
},
209+
"osx": {
210+
"PLATFORM": "macOS"
211+
}
212+
}
213+
}
214+
]
215+
}
216+
]
217+
}
218+
```
219+
220+
### How to use in WSL (Windows Subsystem for Linux)?
221+
222+
When using VSCode in WSL remote mode, file paths need to be converted between WSL and Windows formats depending on whether you're opening the file in a Windows application or a WSL application.
223+
224+
**By default, the extension converts WSL paths to Windows paths** (e.g., `/home/user/file.pdf``C:\Users\user\file.pdf`) to support opening files in Windows applications from WSL.
225+
226+
However, if you want to open files with **WSL applications** (like `evince`, `xdg-open`), you need to set `wslConvertWindowsPath: false` to keep the WSL native path:
227+
228+
```jsonc
229+
{
230+
"openInExternalApp.openMapper": [
231+
// ✅ Open with Windows application (default behavior)
232+
{
233+
"extensionName": "lyx",
234+
"apps": [
235+
{
236+
"title": "Lyx (Windows)",
237+
"shellCommand": "lyx.exe ${file}"
238+
// wslConvertWindowsPath defaults to true
239+
// ${file} will be: C:\Users\username\file.lyx
240+
}
241+
]
242+
},
243+
// ✅ Open with WSL application
244+
{
245+
"extensionName": "pdf",
246+
"apps": [
247+
{
248+
"title": "Evince (WSL)",
249+
"shellCommand": "evince ${file}",
250+
"wslConvertWindowsPath": false
251+
// ${file} will be: /home/username/file.pdf
218252
}
219253
]
220254
}
221255
]
222256
}
223257
```
224258

259+
**Related Issues:**
260+
261+
- [#16](https://github.com/tjx666/open-in-external-app/issues/16) - Opening files in Windows applications from WSL
262+
- [#74](https://github.com/tjx666/open-in-external-app/issues/74) - Opening files in WSL applications from WSL
263+
225264
### assign keyboard shortcut for specific config item
226265

227266
`keybindings.json`:
228267

229268
```jsonc
230269
{
231-
"key": "cmd+k cmd+o",
232-
"command": "openInExternalApp.open",
233-
"args": {
234-
// same with following id
235-
"configItemId": "xxx"
236-
}
237-
},
270+
"key": "cmd+k cmd+o",
271+
"command": "openInExternalApp.open",
272+
"args": {
273+
// same with following id
274+
"configItemId": "xxx"
275+
}
276+
}
238277
```
239278

240279
`settings.json`:

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@
243243
}
244244
}
245245
]
246+
},
247+
"wslConvertWindowsPath": {
248+
"type": "boolean",
249+
"description": "%cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath%",
250+
"default": true
246251
}
247252
}
248253
}

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.string": "Environment variable",
2323
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.windows": "Additional shellCommand environment variables for Windows",
2424
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.linux": "Additional shellCommand environment variables for Linux",
25-
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "Additional shellCommand environment variables for macOS"
25+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "Additional shellCommand environment variables for macOS",
26+
"cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath": "Whether to convert WSL path to Windows path when running in WSL remote mode. Default is true (convert to Windows path for Windows applications). Set to false to keep WSL native path for WSL applications like evince"
2627
}

package.nls.pt-br.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,11 @@
1616
"cfg.openInExternalApp.openMapper.item.apps.item.title": "Título que será exibido na lista suspensa, se houver vários aplicativos para abrir o arquivo.",
1717
"cfg.openInExternalApp.openMapper.item.apps.item.shellCommand": "Usar o shell de comando com um placeholder para lidar com arquivo.",
1818
"cfg.openInExternalApp.openMapper.item.apps.item.args": "Argumentos passados para 'openCommand'.",
19-
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "Defina como verdadeiro (true) quando o apicativo for baseado em Electron."
19+
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "Defina como verdadeiro (true) quando o apicativo for baseado em Electron.",
20+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv": "Additional shellCommand environment variables",
21+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.string": "Environment variable",
22+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.windows": "Additional shellCommand environment variables for Windows",
23+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.linux": "Additional shellCommand environment variables for Linux",
24+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "Additional shellCommand environment variables for macOS",
25+
"cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath": "Whether to convert WSL path to Windows path when running in WSL remote mode. Default is true (convert to Windows path for Windows applications). Set to false to keep WSL native path for WSL applications like evince"
2026
}

package.nls.ru.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.string": "Переменная окружения",
2323
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.windows": "Дополнительные переменные окружения для shellCommand, для Windows",
2424
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.linux": "Дополнительные переменные окружения для shellCommand, для Linux",
25-
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "Дополнительные переменные окружения для shellCommand, для macOS"
25+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "Дополнительные переменные окружения для shellCommand, для macOS",
26+
"cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath": "Whether to convert WSL path to Windows path when running in WSL remote mode. Default is true (convert to Windows path for Windows applications). Set to false to keep WSL native path for WSL applications like evince"
2627
}

package.nls.zh-cn.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,11 @@
1717
"cfg.openInExternalApp.openMapper.item.apps.item.title": "使用多个应用打开文件时弹出的的下拉列表中的标题",
1818
"cfg.openInExternalApp.openMapper.item.apps.item.shellCommand": "使用 shell 命令 和文件占位符去处理文件",
1919
"cfg.openInExternalApp.openMapper.item.apps.item.args": "传给打开命令的参数",
20-
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "当配置 electron 应用时请设置为 true"
20+
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "当配置 electron 应用时请设置为 true",
21+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv": "shellCommand 的额外环境变量",
22+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.string": "环境变量",
23+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.windows": "Windows 平台的 shellCommand 额外环境变量",
24+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.linux": "Linux 平台的 shellCommand 额外环境变量",
25+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "macOS 平台的 shellCommand 额外环境变量",
26+
"cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath": "在 WSL remote 模式下是否将 WSL 路径转换为 Windows 路径。默认为 true(转换为 Windows 路径,用于 Windows 应用)。设置为 false 可保持 WSL 原生路径,用于 WSL 应用(如 evince)"
2127
}

package.nls.zh-tw.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,11 @@
1717
"cfg.openInExternalApp.openMapper.item.apps.item.title": "使用多個應用程式開啟檔案時跳出的下拉式選單中的標題",
1818
"cfg.openInExternalApp.openMapper.item.apps.item.shellCommand": "使用 shell 命令和檔案修飾符號以處理檔案",
1919
"cfg.openInExternalApp.openMapper.item.apps.item.args": "輸入給開啟命令的參數",
20-
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "當選擇 electron 應用程式時請設定為 true"
20+
"cfg.openInExternalApp.openMapper.item.apps.item.isElectronApp": "當選擇 electron 應用程式時請設定為 true",
21+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv": "shellCommand 的額外環境變數",
22+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.string": "環境變數",
23+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.windows": "Windows 平台的 shellCommand 額外環境變數",
24+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.linux": "Linux 平台的 shellCommand 額外環境變數",
25+
"cfg.openInExternalApp.openMapper.item.apps.item.shellEnv.osx": "macOS 平台的 shellCommand 額外環境變數",
26+
"cfg.openInExternalApp.openMapper.item.apps.item.wslConvertWindowsPath": "在 WSL remote 模式下是否將 WSL 路徑轉換為 Windows 路徑。預設為 true(轉換為 Windows 路徑,用於 Windows 應用程式)。設定為 false 可保持 WSL 原生路徑,用於 WSL 應用程式(如 evince)"
2127
}

src/config.ts

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,21 @@ export function validateConfiguration(configuration: ExtensionConfigItem[]): joi
2121
args: joi.array().items(joi.string().required()),
2222
isElectronApp: joi.boolean(),
2323
shellCommand: joi.string(),
24-
shellEnv: joi
25-
.alternatives()
26-
.try(
27-
joi.object()
28-
.pattern(
29-
joi.string(),
30-
joi.string().required()
31-
),
32-
joi.object({
33-
windows: joi.object()
34-
.pattern(
35-
joi.string(),
36-
joi.string().required()
37-
),
38-
osx: joi.object()
39-
.pattern(
40-
joi.string(),
41-
joi.string().required()
42-
),
43-
linux: joi.object()
44-
.pattern(
45-
joi.string(),
46-
joi.string().required()
47-
)
48-
})
49-
)
24+
shellEnv: joi.alternatives().try(
25+
joi.object().pattern(joi.string(), joi.string().required()),
26+
joi.object({
27+
windows: joi
28+
.object()
29+
.pattern(joi.string(), joi.string().required()),
30+
osx: joi
31+
.object()
32+
.pattern(joi.string(), joi.string().required()),
33+
linux: joi
34+
.object()
35+
.pattern(joi.string(), joi.string().required()),
36+
}),
37+
),
38+
wslConvertWindowsPath: joi.boolean(),
5039
}),
5140
),
5241
)

src/openInExternalApp.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { extname } from 'node:path';
33
import type { Uri } from 'vscode';
44
import vscode from 'vscode';
55
import { localize } from 'vscode-nls-i18n';
6-
import { wslToWindows } from 'wsl-path';
76

87
import getExtensionConfig from './config';
98
import { logger } from './utils/logger';
@@ -103,13 +102,7 @@ export default async function openInExternalApp(
103102
uri ??= vscode.window.activeTextEditor?.document.uri ?? (await getActiveFileUri());
104103
if (!uri) return;
105104

106-
const { fsPath } = uri;
107-
const filePath =
108-
vscode.env.remoteName === 'wsl'
109-
? await wslToWindows(fsPath, {
110-
wslCommand: 'wsl.exe',
111-
})
112-
: fsPath;
105+
const { fsPath: filePath } = uri;
113106

114107
// when there is configuration map to it's extension, use [open](https://github.com/sindresorhus/open)
115108
// except for configured appConfig.isElectronApp option

src/typings/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ interface ExternalAppConfig {
1818
isElectronApp?: boolean;
1919
shellCommand?: string;
2020
shellEnv?: NodeJS.ProcessEnv | PlatformVariables;
21+
/**
22+
* Whether to convert WSL path to Windows path when running in WSL remote mode.
23+
* Only applies when vscode.env.remoteName === 'wsl'.
24+
* @default true - Convert to Windows path (e.g., /home/user/file -> C:\Users\user\file)
25+
* @example false - Keep WSL native path for WSL applications like evince
26+
*/
27+
wslConvertWindowsPath?: boolean;
2128
}
2229

2330
interface ExtensionConfigItem {

0 commit comments

Comments
 (0)