あらすじ
- WSLのEmacsと、Windowsのアプリでのテキストのコピペがうまくいかない問題に不定期に悩まされている
- elisp、Perl、バッチファイルを組み合わせたダサいソリューションを作った
- 以下の手順でコピペ出来るようになります
- WSL-Emacsでコピー、Windowsアプリにペースト
- Emacsでテキストを選択
- C-c cを押下(キーバインドはお好みで)
- Windows側でペースト用ショートカットアイコンをクリック
- WindowsアプリでCtrl+Vを押下
- Windowsアプリでコピー、WSL-Emacsにペースト
- Windowsアプリでテキストを選択、Ctrl+Cを押下
- Windows側でコピー用ショートカットアイコンをクリック
- EmacsでC-c vを押下(これもカスタマイズ可能)
- WSL-Emacsでコピー、Windowsアプリにペースト
問題
普通、Emacsでテキストをコピペするには以下のように操作する。
- コピー元の開始位置でC-SPCを押下し、終了位置でM-wを押下してコピー
- ペースト先位置でC-yを押下してペースト
WSL+UbuntuでXのEmacsを使っているが、WSL-EmacsのテキストをWindowsアプリにコピペするのも、以下のように自然に出来ていた。
- Emacsのコピー元の開始位置でC-SPCを押下し、終了位置でM-wを押下してコピー
- Windowsアプリのペースト先位置でCtrl+Vを押下してペースト
逆に、WindowsアプリのテキストをWSL-Emacsにコピペするのも、以下のように自然に出来ていた。
- Windowsアプリでコピー元テキストを選択し、Ctrl+Cを押下してコピー
- Emacsのペースト先位置でC-yを押下してペースト
ところが、毎日使っているEmacsが「ある日突然」「なぜか」Windowsアプリとコピペ出来ないことが何回かあった。
今回、過去に役立っていたソリューションがすべて使えなくなってしまったので、超バッドハックであるが自分でなんとなく解決した。
過去使えていたソリューション
先人のブログを検索しまくって、以下のようなソリューションを導入してしのげていた。
- .emacs.d/init.elに
(setq x-select-enable-primary t)
を追加する
- PowerShellのGet-Clipboardを使う
- clip.exeというコマンドを使う
- win32yank.exeというツールを使う
基本、一番上の(setq x-select-enable-primary t)
さえ設定すれば、Emacsのデフォルト通りM-w、C-yで出来ていたのだが、昨日(2022-10-26)突如使えなくなり、この4つのソリューションすべて試したがダメだった。
ショーック!
自作のバッドハック
そこそこ忙しい日だったので、ひどいけど自作のバッドハックで凌ぐことにした。
概略は以下の通り。
- Emacs=>Windows
- elispのshell-command-to-regionでWSL側のPerlスクリプトを呼び出し、Windowsから見えるところにjunk.txtなどというファイルに書き出し
- Windows側のPerlスクリプトでjunk.txtを読み取ってクリップボードに入れる
- Windows=>Emacs
- Windows側のPerlスクリプトでクリップボードの内容をjunk.txtに書き出し
- elispのshell-command-to-stringでWSL側のPerlスクリプトを呼び出し、junk.txtの内容のカーソル位置に書き出す
ポイントとしてはWindows側のPerlスクリプトでClipboardモジュールを使うとWindowsクリップボードが読み書き出来るところ。
Emacs=>Windows
elispのshell-command-to-regionでWSL側のPerlスクリプトを呼び出し、Windowsから見えるところにjunk.txtなどというファイルに書き出し、Windows側のPerlスクリプトでjunk.txtの中身でクリップボードを置き換える。
elispでshell-command-on-region
emacs.d/init.elに以下のように書くことで、Emacsで範囲選択してC-c c(カスタマイズ可)を押下すると、copyToWindowsJunk.plというスクリプトを、リージョン(選択範囲)を標準入力に実行出来る。
(defun wsl-copy (start end)
(interactive "r")
(shell-command-on-region start end "copyToWindowsJunk.pl"))
(global-set-key (kbd "C-c c") 'wsl-copy)
WSLのPerlでWindowsに書き出し
WSLのパスが通ったところにcopyToWindowsJunk.plというスクリプトを用意した。
#! /usr/bin/perl
open JUNK, '>', "/mnt/c/Users/ユーザー名/Desktop/junk.txt" or die "$!";
select JUNK;
while(<>) {
print;
}
まさにジャンクなスクリプトなので説明なしで。
WindowsのPerlでクリップボードを書き換え
デスクトップのjunk.txtというファイルの中身をクリップボードに書き込む。
#! perl
use Clipboard;
use Encode qw /encode/;
open JUNK, "<:utf8", 'C:\\Users\\ユーザー名\Desktop\\junk.txt' or die $!;
local $/ = undef;
$junk = <JUNK>;
Clipboard->copy(encode('cp932', $junk));
Clipboardモジュールの使い方は以下を参考にした。
https://takepierrot.hatenablog.jp/entry/20120307/1331047847
encodeでcp932を指定しないといけないのが今どきどうなんだろう。
WindowsのPerlをバッチファイルで呼び出す
ショートカットにするためにバッチファイルを書いた。
perl \bin\copyFromWSL.pl
以下のページを参考にバッチファイルのショートカットのアイコンを変え、タスクバーに置いた。
アイコンはWSLから持ってくるという思いを込めて↓っぽいアイコンにした。
使い方
以上でWSLのEmacsのテキストをコピーしてWindowsのアプリにペースト出来るようになった。
- WSLのEmacsでコピーしたいテキストを選択する
- C-c cを押下
- Windowsのタスクバーアイコン↓をクリック
- WindowsアプリでCtrl+Vを押下
Windows=>Emacs
Windows側のPerlスクリプトでクリップボードの中身をjunk.txtに書き出し、elispのshell-command-to-stringでjunk.txtの中身をEmacsバッファに挿入する。
WindowsのPerlでクリップボードを読み取り
クリップボードの中身をデスクトップのjunk.txtに書き出す。
#! perl
use Clipboard;
use Encode qw /decode/;
use open IO => qw/:utf8 :std/;
open JUNK, ">", 'C:\\Users\\ユーザー名\Desktop\\junk.txt' or die $!;
print JUNK decode('cp932', Clipboard->paste());
バッチファイルを作り、アイコンを変え、タスクバーにピン止め
詳細は省略。↑みたいなアイコンにした。
elispでshell-command-to-string
(defun wsl-paste ()
(interactive)
(insert (shell-command-to-string "pasteFromWindowsJunk.pl")))
(global-set-key (kbd "C-c v") 'wsl-paste)
junk.txtを読み取って標準出力に書き出し
#! /usr/bin/perl
open JUNK, '<', "/mnt/c/Users/ユーザー名/Desktop/junk.txt" or die "$!";
while(<JUNK>) {
s/\r\r$//;
print;
}
改行が\r\r\aみたいになる。
I-Oレイヤーを使うのが本道だろうが、\r\rを削除するというバッドハック。
使い方
以上でWindowsのアプリのテキストをコピーしてWSLのEmacsにペースト出来るようになった。
- Windowsアプリでテキストを選択、Ctrl+Cを押下
- Windowsのタスクバーアイコン↑をクリック
- WSLのEmacsで挿入位置にカーソルを置く
- C-c vを押下
改善点
やはりアイコンを押すのがダサ過ぎるので、keyHack?とかを使ってスクリプトを操作したい。
Windowsの空きキーにバインドしたいんだけど、どこがいいんだろう?
もう疲れたので明日以降。
(この項終わり)