Skip to content

Instantly share code, notes, and snippets.

@youz
Last active October 20, 2020 00:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save youz/99f43f13c3fd79dc4724c087e3d5134a to your computer and use it in GitHub Desktop.
Save youz/99f43f13c3fd79dc4724c087e3d5134a to your computer and use it in GitHub Desktop.
wsl utility for xyzzy
;;; -*- mode: lisp; package: wsl -*-
(defpackage :wsl
(:use :lisp :editor))
(in-package :wsl)
(export '(run-wsl
run-wsl-in-buffer
convert-wslpath-to-win
convert-winpath-to-wsl
*wslexe-path*
*wsl-output-buffer-name*
*wsl-output-mode-keymap*
))
(defvar *wslexe-path* "C:/Windows/Sysnative/wsl.exe")
(defvar *wsl-output-buffer-name* "*wsl*")
(defvar *wsl-output-mode-keymap* nil)
(defun %run-wsl-sync (args enc)
(let ((tmpbuf (create-new-buffer " *wsltmp*"))
(cmd (format nil "~A ~A" *wslexe-path* args)))
(unwind-protect
(let ((proc (make-process cmd :output tmpbuf :outcode *encoding-binary*)))
(while (eq (process-status proc) :run)
(sleep-for 0.1))
(let ((ec (process-exit-code proc)))
(save-excursion
(set-buffer tmpbuf)
(let ((output (buffer-substring 0 (point-max))))
(unless (eq enc *encoding-binary*)
(setq output (convert-encoding-to-internal enc output)))
(values output ec)))))
(progn
(let ((proc (buffer-process tmpbuf)))
(when (and proc (eq (process-status proc) :run))
(kill-process proc))
(while (eq (process-status proc) :run)
(sleep-for 0.1)))
(delete-buffer tmpbuf)))))
(defun run-wsl (cmd &key (encoding *encoding-utf8*) run-on-shell)
"wsl.exeを実行し、終了するまで待つ。出力結果(文字列)とプロセス終了コードを多値で返す"
(let ((args (format nil "--~A ~A" (if run-on-shell "" "exec") cmd)))
(%run-wsl-sync args encoding)))
(defun run-wsl-in-buffer (cmd &key (buffer *wsl-output-buffer-name*)
(encoding *encoding-utf8*)
clear
run-on-shell)
"wsl.exeを実行し、バッファ上に出力結果を表示する"
(let ((buf (get-buffer-create buffer)))
(save-excursion
(set-buffer buf)
(when clear
(erase-buffer buf))
(wsl-output-mode)
(with-output-to-buffer (buf (point-max))
(format t "~&<start WSL: ~A>~%" cmd)))
(make-process (format nil "~A --~A ~A" *wslexe-path*
(if run-on-shell "" "exec")
cmd)
:output buf
:incode encoding
:outcode encoding
:show :hide)
(pop-to-buffer buf t t)
buf))
(defun wsl-output-mode ()
(when (keymapp *wsl-output-mode-keymap*)
(use-keymap *wsl-output-mode-keymap*))
(setq need-not-save t
buffer-mode 'wsl-output
mode-name "WSL output"))
(defun convert-winpath-to-wsl (winpath)
(multiple-value-bind (output ec)
(run-wsl (concat "wslpath -a -u " (map-backslash-to-slash winpath)))
(unless (= ec 0)
(error output))
(string-right-trim "\r\n" output)))
(defun convert-wslpath-to-win (wslpath)
(multiple-value-bind (output ec)
(run-wsl (concat "wslpath -a -w " wslpath) :run-on-shell t)
(unless (= ec 0)
(error output))
(string-right-trim "\r\n" output)))
(provide "wsl")

wsl.exe実行

run-wsl

wsl:run-wslはwsl.exeを使って指定コマンドを実行し、終了するまで待って出力結果とプロセス終了コードを多値で返す。

キーワード引数 :run-on-shell にtを指定した場合、デフォルトシェル上で実行する。 (wsl.exe -- <args> とするのと同じ)

:run-on-shell引数を省略(or nilを指定)した場合は直接実行する。(wsl.exe --exec <args> とするのと同じ)

> (wsl:run-wsl "ls ~" :run-on-shell t)
"bin
code
opt
"
0

> (wsl:run-wsl "ruby --version")
"ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
"
0

終了しないコマンド(bashとかirbとか)を実行してしまった場合は永遠に待ち続けてしまうので C-g で抜ける。(wsl.exeのプロセスはkill-processされる)

run-wsl-in-buffer

wsl:run-wsl-in-bufferは引数をwsl.exeに渡し、出力結果をバッファ上に表示にする。

出力先バッファはキーワード引数:bufferで指定する。省略時は*wsl-output-buffer-name*で指定されているバッファに出力する。

実行中のコマンドを強制終了したい場合は、出力バッファ上でC-c C-k

%run-wsl-sync

非公開の関数%run-wsl-syncを使うとコマンド実行以外の機能(--listとか--helpとか)を呼び出せるが、出力が何故かUTF-16になる & 謎のNUL文字が混じる。 (未対策)

> (wsl::%run-wsl-sync "--list" *encoding-utf16le-bom*)
"Linux 用 Windows サブシステム ディストリビューション:^@
Ubuntu-20.04 (既定)^@
"
0

> (wsl::%run-wsl-sync "--list -v" *encoding-utf16le-bom*)
"  NAME            STATE           VERSION\Xd60a\Xd700\Xd62a\Xd700\X0d86\X647c戀\Xc7b3\X6b3a\X6ccb\Xc7b3\Xd62d\Xd700\X1a00 \Xd62e\Xd700 \Xd634\Xd700\X0d86\X0d86\X0d86\X0d86匀\X6ccb\Xc9c7\X6bb9\X6bb9攀\X4090\X0d86\X0d86\X0d86\X0d86\X0d86\X0d86\X0d86\X0d86\X0d86\Xd631\Xd700
"
0

wsl.exe --list -vの結果は\0の入る場所がマズいらしくまともにデコード出来ない。

パスの変換

WSL上でwslpathを呼び出して変換する

> (wsl:convert-wslpath-to-win "~/code")
"\\\\wsl$\\Ubuntu-20.04\\home\\yu\\code"

> (wsl:convert-winpath-to-wsl "D:/project")
"/mnt/d/project"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment