如何在 WSL 中,用 PhpStorm 指令開啟 WSL 系統中的專案

程式技術
sharkHead
如何在 WSL 中,用 PhpStorm 指令開啟 WSL 系統中的專案

我自己平常開發時常用的作業系統是 Mac 和 WSL (Windows Subsystem for Linux),而在編寫 PHP 時都是使用 PhpStorm 這款超級好用的 IDE。

在 Mac 作業系統上,PhpStorm 提供了一個方便的功能,可以在終端機中使用 phpstorm 命令來打開專案。

$ cd /path/to/project
$ phpstorm .

這個功能在 Windows 中也有提供。

# 使用 Toolbox 安裝 PhpStorm 的話,可以在 CMD 或是 PowerShell 中使用這個指令開啟專案
PhpStorm.cmd .

雖然 PhpStorm 支援開啟在 WSL 中的檔案,但並不支援使用指令開啟檔案,雖然這不影響開發,但能直接在 Terminal 中打開專案還是很方便。於是我上網查找是否有解決辦法。

這個問題有在 JetBrains 的論壇中有人提出來過,有人提供了一個解法,使用跨檔案系統工作功能,讓你在 WSL 中執行 Windows 程式。

# .bashrc or .zshrc

phpstorm() {
    cmd.exe "/mnt/c/Users/<username>/scripts/jetbrains/phpstorm.cmd" $(wslpath -w ${1:-$(pwd)})
}

我們可以在 WSL 中訪問 Winodws 系統中的資料夾,例如 C:\\ 在 WSL 中會以 /mnt/c 表示。而如果想要在 WSL 中 執行 Windows 系統的程式,可以使用 cmd.exe 來執行該程式。

wslpath 的功能類似 pwd,可以取得當前在 WSL 中的路徑,並可以選擇以 Linux 或是 Windows 的格式來呈現。

$ wslpath
wslpath: Invalid argument
Usage:
    -a    force result to absolute path format
    -u    translate from a Windows path to a WSL path (default)
    -w    translate from a WSL path to a Windows path
    -m    translate from a WSL path to a Windows path, with '/' instead of '\\'

EX: wslpath 'c:\\users'

所以如果我想取得 Winodws 格式的當前路徑,可以使用 wslpath -w .

${1:-$(pwd)} 這一段是什麼意思呢?

${1:-$(pwd)} 是一個 shell script 的語法,表示如果有傳入第一個參數就使用該參數,否則使用 pwd 指令執行的的輸出。

$() 中可以放入一個指令,這個指令會在整個指令執行前先執行並返回結果,如下所示。

cd /path/to/what/i/want 

# My current path is /path/to/what/i/want 
echo "My current path is $(pwd)"

假設我輸入 phpstorm . 那麼 ${1} 就會是 .,如果沒有輸入,就會使用 pwd 的執行輸出,也就是當前完整的目錄。

因為我是使用 Toolbox 安裝 PhpStorm,所以路徑需要稍微修改一下。

# .bashrc or .zshrc

phpstorm() {
    cmd.exe '/mnt/c/Users/<username>/AppData/Local/JetBrains/Toolbox/scripts/PhpStorm.cmd' $(wslpath -w ${1:-$(pwd)})
}

成功使用 PhpStorm 開啟專案!

2023_04_28_19_26_21_abcae79d4e3d.png

But

我發現了幾件事情,首先指令執行之後,會在 WSL 中開啟一個 Non-Daemon Process,你可以看到圖片中啟動 PhpStorm 後,我們就沒辦法與 Terminal 繼續互動了,直到把 PhpStorm 關閉為止。

你可以使用 kill <pid> 的方式結束這個 Process,PhpStorm 並不會因此關閉。

如果不想看到執行後顯示的訊息,並且讓 Process 以 Daemon 的方式在背景執行的話,可以在指令後面加上 > /dev/null 2>&1 &

再來是 WSL 的根目錄路徑其實有變更,新版本的路徑如下。

# 新版本的根目錄路徑
\\wsl.localhost\Ubuntu\

但 PhpStorm 仍舊是使用舊版本的路徑。

# 舊版本的根目錄路徑
\\wsl$\Ubuntu\

可以用 PhpStorm 的 File → Open 查看開啟的路徑

2023_04_28_19_27_03_e2a390cab6a7.png

有關於系統路徑的變更,可以查看微軟的這篇文章。目前新與舊版本的系統路徑都能夠使用,但我想未來 PhpStorm 更新預設也會使用新的路徑。

2023_04_28_19_27_21_8f2ca674487e.png

如果想用舊的路徑,該怎麼辦?

可以嘗試修改下面這段。

$(wslpath -w ${1:-$(pwd)})

我第一個想法是使用串接字串,因為舊路徑前半段的 \\\\wsl$\\Ubuntu 是固定的,後半段我們只要補上 pwd 的輸出結果就好,但是 pwd 的結果是使用斜線 /,與 Windows 的反斜線 \\ 不同。

$ pwd

/home/allen

所以串接起來就會不對。

$ echo '\\\\wsl$\\Ubuntu'$(pwd)

\\wsl$\Ubuntu/home/allen

嘗試問問 ChatGPT 有沒有什麼方法可以把字串中的斜線轉成反斜線,他很快速地給我了一個答案。

string="/home/allen"

new_string="${string//\//\\}"

echo "$new_string"

但輸出的結果是。

\homellen

\a 是響鈴符號,如果你輸入 echo "\a" 的話,並不會看到任何輸出,而是聽到喇叭發出 "噔" 的一聲。

看樣子 ChatGPT 也逃不了被跳脫字元坑到的命運🥲。

知道了 Shell Script 替換字元的方式之後,稍微修改一下 phpstorm() 的內容。

# .bashrc or .zshrc

phpstorm() {
    # 使用 realpath 取得完整的路徑
    # 沒有傳入參數就使用 pwd 取得當前的路徑
    string=$(realpath ${1:-$(pwd)})

    target='/'

    replace='\'

    cmd.exe 'windows/path/to/PhpStorm.cmd' '\\\\wsl$\\Ubuntu'${string//$target/$replace} 
}

同樣也能成功開啟資料夾,且路徑顯示舊有的路徑。

美中不足

稍微試用了一下,還是有一些問題,如果你因為安裝 (移除) 套件而重新啟動 PhpStorm 的話,重新開啟後就會將所有 Recent Projects 全部打開。

然後有機會 Crash

測試了一個解決辦法是,在啟動 PhpStorm 之後,就將 WSL 中的 Daemon Process 終止。

phpstorm() {
    cmd.exe 'windows/path/to/PhpStorm.cmd' $(wslpath -w ${1:-$(pwd)}) >/dev/null 2>&1 &
    # 取得 PID
    PID=$!
    # 等待 PhpStorm 啟動
    sleep 10
    # 終止 PhpStorm 在 WSL 中的 Daemon Process
    kill $PID
}

雖然重新啟動後還是會開啟所有的 Recent Projects,但並不會因此 Crash。

避免開啟所有 Recent Projects

可以在 Appearance & Behavior → System Settings 的頁面關閉 Reopen projects on startup 的功能。

2023_05_01_21_36_19_e2c4716a69fa.png

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言