■ Windows Subsystem for Linux の Emacs で利用できる設定
【お知らせ】
<2021/06/28 追記>
proxy サーバ配下の環境にある PC で Remote-WSL を使った場合、WSL に接続するまでに時間が掛かる問題が発生していました。次のページで紹介してある設定を行ったところ改善しましたので、紹介しておきます。
<2021/02/05 追記>
本ページの内容は WSL2 でも動作します。DrvFs や VolFs の記載がある場合には、Windows 側のファイルシステム、WSL2 側のファイルシステムと読み替えてください。
<2020/09/16 追記>
WSL2 の対策を行いました。(UNC パスのディレクトリで C-u を前置して実行した際、正常に動作するようになります。wslpath2 コマンドを使うように見直ししています。)
<2019/10/31 追記>
code を cmd.exe からコールする場合の引数のエスケープ処理を追加しました。
<2019/10/20 追記>
本設定と逆方向の操作をしたい場合には、次の設定を参考としてください。
<2019/09/10 追記>
本設定は次の情報に基づき、作成しています。
<2019/09/10 追記>
Remote Development に対応しました。
<2019/03/13 追記>
VSCode を Emacsキーバインドにするための新しい Extension、Awesome Emacs Keymap が出ているようです。
Command Palette 内での文字入力時に Emacsキーバインドが使えないのは変わっていないようです。
【本題】
Windows Subsystem for Linux で起動している Emacs から Visual Studio Code でファイルを開くための設定です。
1) Visual Studio Code の Windows版 をインストールする。
2) Remote-SSH を使う場合は、コマンドプロンプトから ssh コマンドが使えることを確認し、さらに Windows と WSL の ssh が同じホスト名で接続できるように設定を行う。(%USERPROFILE%/.ssh/config や ~/.ssh/config の設定を行うことで、ホスト名の略称が使える。)また、接続先と公開鍵認証で接続できるようにし、ssh-agent の設定をすることでパスフレースの入力を省略できるようにする。
※ ssh-agent-wsl を利用すると、Windows 側の ssh-agent に WSL から秘密鍵を登録でき、また Windows の ssh-agent を WSL からも利用できるようになります。
3) Remote-Containers を使う場合は、Docker の設定をし、コンテナを立ち上げておく。
4) 拡張機能 Remote Development をインストールする。
※ Remote-WSL、Remote-SSH、Remote-Containers の機能を最初に利用する際にサーバモジュールがインストールされます。Remote-WSL、Remote-SSH のサーバモジュールは sh -c で起動されるスクリプト内で wget によりインターネットから取得されるため、接続環境によっては .wgetrc にプロキシの設定を行う必要があるようです。
5) PC を一旦ログインしなおす。(VSCode の再起動だけで良いようにも思いますが、念の為)
6) 次のリポジトリの内容を WSL/WSL2 にインストールし、コマンドパスが通った状態で wslpath2 コマンドが動作するようにする。
7) Emacs を立ち上げ、以下の設定を有効にする。
(defun vscode-cmd-escape (arg)
(replace-regexp-in-string "[&|<>^\"%]" "^\\&" arg))
(defun vscode-open-command (filename &optional keep-position)
(interactive)
(let* ((filename (expand-file-name filename))
(default-directory "/mnt/c/")
authority
target
command
filepath)
(cond ((file-remote-p filename)
(setq command "cmd.exe /c code")
(if (file-directory-p filename)
(setq command (format "%s --folder-uri" command))
(setq command (format "%s --file-uri" command)))
(let* ((vec (tramp-dissect-file-name filename))
(method (tramp-file-name-method vec))
(host (tramp-file-name-host vec))
(user (tramp-file-name-user vec))
(localname (tramp-file-name-localname vec)))
(cond ((or (string= method "scp")
(string= method "ssh"))
(setq authority "ssh-remote")
(setq target (if user
(format "%s@%s" user host)
host))
(setq filepath (format "vscode-remote://%s+%s%s" authority target localname)))
((string= method "docker")
(setq authority "attached-container")
(setq dockerid (shell-command-to-string
(format "cmd.exe /c docker container ls --filter 'name=%s' --format '{{.ID}}'"
host)))
(when (not (string= dockerid ""))
(setq dockerid (substring dockerid 0 -1))
(setq target (mapconcat (lambda (x)
(format "%02x" (aref x 0)))
(split-string dockerid "" t) ""))
(setq filepath (format "vscode-remote://%s+%s%s" authority target localname))
(setq filepath (vscode-cmd-escape filepath))
(setq filepath (vscode-cmd-escape filepath)))))))
(t
(cond (current-prefix-arg
(setq command "cmd.exe /c code")
(let ((winpath (shell-command-to-string
(format "wslpath2 -w %s 2> /dev/null"
(shell-quote-argument (file-truename filename))))))
(when (not (string= winpath ""))
(setq filepath (substring winpath 0 -1))
(setq filepath (vscode-cmd-escape filepath))
(setq filepath (vscode-cmd-escape filepath)))))
(t
(setq command "code")
(setq filepath filename)))
(when keep-position
(setq command (format "%s -g" command))
(setq filepath (format "%s:%d:%d" filepath (line-number-at-pos) (+ (- (point)
(save-excursion
(beginning-of-line)
(point)))
1))))))
(if (null filepath)
(message "VSCodeで開くことができません")
(message (format "%s %s" command filepath))
(shell-command-to-string (format "%s %s" command (shell-quote-argument filepath))))))
;; dired で開いているディレクトリを開く
(define-key dired-mode-map (kbd "V")
(lambda ()
(interactive)
(save-some-buffers)
(vscode-open-command (dired-current-directory) nil)))
;; dired でカーソルがある位置のファイルを開く
(define-key dired-mode-map (kbd "C-c v")
(lambda ()
(interactive)
(save-some-buffers)
(vscode-open-command (dired-get-file-for-visit))))
;; 開いているファイルをカーソルの位置を維持して開く
(global-set-key (kbd "C-c v")
(lambda ()
(interactive)
(save-some-buffers)
(vscode-open-command buffer-file-name t)))
※ キーの設定は使いやすいように変更してご利用ください。
※ キーから呼ばれるコマンド内で「(save-some-buffers)」を呼んでいます。これは、Emacs で編集中のファイルが VSCode から二重に編集されないようにするための対策です。不要であれば削除してご利用ください。
※ Emacs 開いているファイルを VSCode で開く場合にカーソル位置を維持する機能をサポートしていますが、この機能は tramp での接続先のファイルを VSCode(の Remote-SSH、Remote-Containers)で開く際には機能しません。(ファイルの先頭にカーソルが位置します。)
8) Emacs から 7) で設定したキーを入力することにより、VSCode と連携する。
※ Remote-SSH、Remote-Containers で接続した VSCode を起動したい場合には、Emacs から接続先に tramp で接続し、その状態で設定したキーを入力してください。
※ tramp で Docker に接続するには、 docker-tramp.el が必要です。詳しくは、次のページの<2018/07/20 追記>の内容を参考としてください。
※ ローカルPC上では、数引数(C-u)を付けないで設定したキーを入力すると、Remote-WSL 機能を使って VSCode と連携します。(Windows 10 のバージョン関係なく、DrvFs、VolFs 上のどちらにあるファイルやディレクトリも開けます。)
※ ローカルPC上では、数引数(C-u)を付けて設定したキーを入力すると、Remote-WSL 機能を使わないで VSCode と連携します。(Windows 10 1809 までは、VolFs 上にあるファイルやディレクトリは開けません。)
※ Fakeymacs をインストールすると、Emacs から起動した VSCode との行き来を Alt+o のキーで行うことができるようになります。さらに Fakeymacs の vscode_key 拡張機能を有効にすると、VSCode を Emacs により近いキーバインドで利用できるようになります。
<変更履歴>
- 2018/11/26 このページを作成した。
- 2019/08/23 パスにシンボリックリンクが含まれる場合の対策を行った。
- 2019/08/23 wslpath 変換時のエラー対策を行った。
- 2019/08/27 Remote-WSL に対応した。
- 2019/09/10 Remote-SSH、Remote-Containers に対応した。
- 2019/10/31 code を cmd.exe からコールする場合の引数のエスケープ処理を追加した。
最終更新:2024年10月08日 22:20