Edited at

Windows上のVSCodeからWSL上のPythonを使って補完や「定義へ移動」を効かせる


WSL+VSCodeでIntelliSenseとLinterを使いたい

Windows上にVSCodeをインストールするとWSLのpythonを見に行けない。

だけどWSLにVSCodeをインストールするのも不安定であまりやりたくない。

VSCodeでWSL上のコマンドにアクセスするには以下の方法があります。

Rust: WSLGit

Python: WSLenv

Pythonの方は試していません。(pyinstallerが遅い印象があるので…)

Rustで書かれたWSLGitを使います。


WSLGit

WSLGitはWindowsからWSLのGitを使うためのツールです。

https://github.com/andy-5/wslgit/releasesから最新のバイナリをダウンロードして好きなところに置きます。

VSCodeのsetting.jsonにwslgit.exeのパスを書きます。


setting.json

{

"git.path": "C:\\CHANGE\\TO\\PATH\\TO\\wslgit.exe"
}

これで、cmdからwslgit.exeを叩くとWSLを開いてgitを起動してくれます。


Pylintを使う

同じ方法で他のツールにも対応できます。

WSLGitのソースのString::from("git")の部分をString::from("python3")などの使いたいコマンドに変えてコンパイルすればいいです。

Rustのインストール

$ curl https://sh.rustup.rs -sSf | sh

WSLGitをgit cloneして好みの仕様にする

$ git clone https://github.com/rust-lang/rls.git

WSL上のRustでWindows用の実行ファイルをビルドします。

参考:Rustでクロスコンパイルしてみた | 思案試行

MinGWをインストール

$ sudo apt install mingw-w64

x86_64-pc-windows-gnuコンポーネントをインストール

$ rustup target add x86_64-pc-windows-gnu

~/.cargo/configに以下を追記


~/.cargo/config

[target.x86_64-pc-windows-gnu]

linker = "/usr/bin/x86_64-w64-mingw32-gcc"

[target.i686-pc-windows-gnu]
linker = "/usr/bin/i686-w64-mingw32-gcc"
rustflags = "-C panic=abort"


コンパイルする

$ cargo build --target x86_64-pc-windows-gnu --release

target/x86_64-pc-windows-gnu/release/に.exeファイルが生成されます。

好きな場所に配置してVSCodeのsetting.jsonでパスを設定します。


setting.json

{

"python.pythonPath": "C:\\CHANGE\\TO\\PATH\\TO\\python3.exe",
"python.linting.pylintPath": "C:\\CHANGE\\TO\\PATH\\TO\\pylint.exe",
"python.formatting.autopep8Path": "C:\\CHANGE\\TO\\PATH\\TO\\autopep8.exe"
}

各パッケージのインストール

$ sudo apt install python3

$ sudo apt install pylint
$ sudo apt install autopep8

これで、VSCodeでpylintやautopep8が使えるようになります。


「定義へ移動」を使いたい

このままだとVSCodeの「定義へ移動」などはWSLのパスを参照してしまって使えません。





調べたら対応している人がいました:plusls' blog – Windows的vscode使用wsl中的python

以下、この記事に従って作業します。

C:\Users\<User>\.vscode\extensions\ms-python.python-2019.3.6215\pythonFiles\completion.pyが関数を検索してパスを返しているため、これを以下のように書き換えます。

wsl_to_win_path関数を追加してwsl_root_pathにWSLのホームディレクトリを書き、watch関数で見るパスをwsl_to_win_pathでWindowsのパスに置き換えています。


completion.py

wsl_root_path = 'C:\\Users\\<User>\\<Your WSL home>'

windows_disk = {}
def wsl_to_win_path(path):
ret = path
if path.startswith('/mnt/'):
ret = path[5:6] + ':' + path[6:]
ret = ret.replace('/', '\\')
if ret[:3] in windows_disk:
if windows_disk[ret[:3]] is True:
return ret
else:
if os.system('powershell.exe /c \'test-path {}| Out-Null\''.format(ret[:3])) == 0:
return ret
else:
pass
if path.startswith('/'):
ret = wsl_root_path + path.replace('/', '\\')
return ret
return ret

...

class JediCompletion(object):

...

def watch(self):
while True:
try:
rq = self._input.readline()
if len(rq) == 0:
# Reached EOF - indication our parent process is gone.
sys.stderr.write('Received EOF from the standard input,exiting' + '\n')
sys.stderr.flush()
return
with RedirectStdout():
response = self._process_request(rq)
# wsl path to win path
if self.drive_mount == '/mnt/':
response_data = json.loads(response)
for i in range(len(response_data['results'])):
if 'fileName' in response_data['results'][i]:
response_data['results'][i]['fileName'] = wsl_to_win_path(response_data['results'][i]['fileName'])
response = json.dumps(response_data)
self._write_response(response)

except Exception:
sys.stderr.write(traceback.format_exc() + '\n')
sys.stderr.flush()


これで、「定義へ移動」などが正しく動作します。


Rustの補完も使う

VSCodeでRustの補完を使う方法についても書いておきます。

RLSを使います。

rustupをアップデート

$ rustup update

RLSをインストール

$ rustup component add rls rust-analysis rust-src

VSCodeで拡張機能 Rust (rls) をインストールしてsetting.jsonに"rust.useWSL": trueを追加


setting.json

{

"rust.useWSL": true
}

nightlyを使ってる場合は"rust-client.channel": "nightly"も追加


setting.json

{

"rust-client.channel": "nightly"
}