clip.exeで日本語をコピーすると文字化けするようになった
状況
今日(2023-03-12)terminalを使ったら、clip.exeでコピーした日本語が文字化けするようになってしまった
WSL2のneovimでclipboardを使う設定をしている
https://gyazo.com/2b5bf23b089b2146c450feb88d4ec9ac
たちが悪いのが、neovimでUTF-8のファイルに文字化けしたテキストを貼り付けて保存するとShift JISになること
正常だった他の日本語コメントも巻き込んでしまう
原因 (根本ではない)
clip.exeにUTF-8を渡すと文字化けする
Shift JISしか受け付けないため
ならなぜ今まで文字化けしなかったのか……takker.icon
| clip.exeでファイルの中身をコピーしても、少しも文字化けしなかった
今確認したら、文字化けするようになってしまっていた
takker.iconのシステムが、昨日から突然echoもneovimもShift JISではなくUTF-8を使うようになったとか?
そんなことある?
しかもそれだと今までShift JISメインでシステムが動いていたということになるが、ますますあり得ない
[Console]::Out.Write()がShift JISで文字を出力していた
neovimがこれをUTF-8と認識してしまうため、文字化けを起こしていた
解決策
以下の方法でtakker99/dotfilesにPR作ってmergeした
vim-jpでの助言を受けて、さらに簡略化した
方針
標準入力をShift JISに変換してから渡す
[Console]::Out.Write()の出力文字コードをUTF-8に変える
文字コード変換にはnkfを使った
iconvでもよかったかも。install不要なので
WSL2のneovimでclipboardを使うのclip.vimを以下で差し替える
#22ではコピーコマンドを別のファイルにwrapして呼び出していた
sh -cで直接コマンドを書きたかったが、なぜかclipboard: error: -sc: 1: Syntax error: Unterminated quoted stringが出てしまうため断念した
これの原因が空白区切りだとわかったので、手動で空白の区切り方を設定できるリスト渡しに変更した
code:clip-fix.vim
if system('uname -a | grep microsoft') != ''
let g:clipboard = {
\ 'name': 'WslClipboard',
\ 'copy': {
\ '+': 'sh','-c','nkf -sc | clip.exe',
\ '*': 'sh','-c','nkf -sc | clip.exe',
\ },
\ 'paste': {
\ '+': 'powershell.exe -c Console::OutputEncoding = Text.Encoding::UTF8;Console::Out.Write($(Get-Clipboard -Raw).tostring().replace("\`r", "")',
\ '*': 'powershell.exe -c Console::OutputEncoding = Text.Encoding::UTF8;Console::Out.Write($(Get-Clipboard -Raw).tostring().replace("\`r", "")',
\ },
\ 'cache_enabled': 0,
\ }
endif
懸念
Shift JISのファイルを編集しようとしたとき、逆の問題が起こりそうだ
貼り付け時にUTF-8をShift JISと解釈してしまう
わかっていないこと
突然文字コード変換が必要になった理由
根本原因がわからないのが怖いtakker.icon
2023-09-14 07:59:44 WSL2のupdateが原因のようだ
WSLでclip.exeに渡した文字列が"文字化け"した際の対処法
状況整理
↓が文字化けする
$ echo "日本語" | clip.exe
https://gyazo.com/54235ae9c143d8f4303c9807e2e807bd
対処
✅SJISに変換してから渡す
nkfをつかった
https://gyazo.com/e31641f6a2e81bc0f63819ff03d5e960
これを出力したときには気づいていなかったが、コピーした文字列はShift JISになっている
❌powershell側で$OutputEncodingをShift JISにする
$ $OutputEncoding = Text.Encoding::Default
from
PowerShell/日本語/コマンドプロンプトなコマンドの入出力が文字化けする - yanor.net/wiki
Powershell上で、パイプで渡すと文字化けする。 - Qiita
$OutputEncoding = [Console]::OutputEncodingclip.exeで日本語をコピーすると文字化けするようになった#640d25eb1280f00000ae1971 でもいいのか?
単一sessionでしか有効にならないみたい
PowerShell環境では直るが、WSL2環境には影響を与えないようだ
https://gyazo.com/9ebbd7064e164086ec85ad8e7bd65220
powershell.exe -c "$OutputEncoding = [Text.Encoding]::Default;Read-Host | clip.exe"ならどうだろう?
意味なかった
https://gyazo.com/848681c69039e019efef2095ad49c45f
echo "日本語" | powershell.exe -c "[Console]::InputEncoding = [Text.Encoding]::UTF8;\$OutputEncoding = [Text.Encoding]::Default;Read-Host | clip.exe"でなんとかなるか試してみたが、微妙に壊れた文字になってしまう
https://gyazo.com/d10539f173f751e33ad733c02fe07eef
Read-Hostではsystem()内で標準入力を受け取れない
2023-03-13 10:51:33 今調べたら、Read-Host | Set-Clipboardではまったくコピペできていなかった
昨日はたまたまclipboardに似たような文字列が入ってたせいで、実行できたと勘違いしていただけだった
copy
paste
powershell.exe -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("\`r", ""))を実行すると、Shift JISで出力されてしまう
neovimだとこれが解釈できずに文字化けを起こす
fish shell上だと自動で文字コードを判別してくれるせいか、文字化けせず表示される
多分この親切な挙動のせいで、文字コードが変わっているかどうかわからず混乱した面が少なからずあったと思うtakker.icon
nkf -gで確認すると、Shift JISだとわかる
この機能はmanで初めて知った
先にmanを読むべきだったかな
powershell.exe -c "Get-Clipboard" | nkf -gもShift JISと判定された
コピー方法はclip.exeでもwindows上でのコピーでもSet-Clipboardでも同じ
[Console]が出力する文字コードの問題かも?
neovim内で'+': 'sh copy.sh'にしてコピーした日本語まじりのテキストをスクボやメモ帳に貼り付けたら、文字化けしてなかった
shell scriptで標準入力を受け取る
つまりコピーではなく、貼り付け処理の問題だということ
[Console]::OutputEncodingを指定したらUTF-8になった
$ powershell.exe -c Console::OutputEncoding = Text.Encoding::UTF8;Console::Out.Write($(Get-Clipboard -Raw).tostring().replace("\`r", "")
from PowerShell/日本語/コマンドプロンプトなコマンドの入出力が文字化けする - yanor.net/wiki
これで解決
解決策
sh copy.shでコピー
powershell.exe -c [Console]::OutputEncoding = [Text.Encoding]::UTF8;[Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("\`r", "")で貼り付ける
確認事項
neovim内での日本語まじりの(複数)行のコピペ
yとdとpを使った
いくつかの異なる文字列で試した
windowsのメモ帳とneovim間でコピペ
以下、調査時の混乱を含むメモ
調査
WSL2経由でclip.exeをつかっているのが原因だろうか?
とりあえず、clip.exeの文字化けが原因なのはわかった
15:20:37 外部から貼り付けしたときも文字化けしてた。原因はこれだけじゃない
$OutputEncodingはUS-ASCIIになってた
clip.exeで日本語をコピーすると文字化けするようになった#640d25eb1280f00000ae1971とおんなじ状態
code:log
$OutputEncoding
IsSingleByte : True
BodyName : us-ascii
EncodingName : US-ASCII
HeaderName : us-ascii
WebName : us-ascii
WindowsCodePage : 1252
IsBrowserDisplay : False
IsBrowserSave : False
IsMailNewsDisplay : True
IsMailNewsSave : True
EncoderFallback : System.Text.EncoderReplacementFallback
DecoderFallback : System.Text.DecoderReplacementFallback
IsReadOnly : True
CodePage : 20127
わからないこと
対策
powershellの設定を変えても変化なし
どうすりゃええねんtakker.icon
clip.exe以外のコピーコマンドを使うしかないか?
この現象が起きた理由
なんにもしてないはずだが……takker.icon
sudo apt upgradeで何らかのアプリの設定が変わったとか?
対策
❌
iconv or nkf
コマンド上は変換に成功した
vimの設定でパイプを使う方法がわからない
これだとclipboard: error: |: No such file or directoryが発生する
code:vim
if system('uname -a | grep microsoft') != ''
let g:clipboard = {
\ 'name': 'WslClipboard',
\ 'copy': {
\ '+': 'nkf -sc | clip.exe',
\ '*': 'nkf -sc | clip.exe',
\ },
\ 'paste': {
\ '+': 'powershell.exe -c Console::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ '*': 'powershell.exe -c Console::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',
\ },
\ 'cache_enabled': 0,
\ }
endif
g:clipboardの設定方法を調べようtakker.icon
配列を指定すればいいだけっぽい?
いや、そもそもpipe symbolをサポートしていないようだhttps://github.com/neovim/neovim/issues/12092#issue-596283907
PowerShellでwrapper scriptを書くしかなさそう
Powershellでテキストをクリップボードにコピーする
教えてもらった情報から、次の変更を施したらコピーできるようになった
code:diff
- \ '+': 'clip.exe',
- \ '*': 'clip.exe',
+ \ '+': 'powershell.exe -c Read-Host | Set-Clipboard',
+ \ '*': 'powershell.exe -c Read-Host | Set-Clipboard',
欠点
漢字が文字化けする
まだ文字コードがおかしいみたい
https://gyazo.com/d535f6c853c719e98191ebafb680b7de
遅い
これはPowerShellをいちいち立ち上げているせいなのでしかたなし
改行がコピーされない
$ powershell.exe -c "Set-Clipboard(\"てすと`n てsつp\");Console::Out.Write(\$(Get-Clipboard -Raw).tostring())"
https://gyazo.com/86d792501865445d78f8c69afec86985
shellの実行結果から見ると、Set-Clipboardは問題ではなさそう
neovimがRead-Hostに書き込む時、改行情報が消えてしまっている?
cmd.exeのほうが高速というアドバイスを受けたので、DOS commandで書いてみる
$ cmd.exe /C "set /p inputText= && echo %inputText% | clip"
vimscriptでは''内でエスケープ処理が不要なので、これをそのまま'+'と'*'の値として渡せば良い
結果
警告で止まってしまい、コピーできない
shell上ではコピーはできている
https://gyazo.com/94f2884a2cfe178e632f872d800dbf70
警告の中身
code:err
'\\wsl.localhost\Ubuntu\home\takker\git\dotfiles\nvim\userautoload\init'
上記の現在のディレクトリで CMD.EXE を開始しました。
UNC パスはサポートされません。Windows ディレクトリを既定で使用します。
対策を考える
警告を抑制する
https://teratail.com/questions/csp8gwl2in2yaw
微妙に関係なさそう
消し方は不明
警告の原因を消す
UNCパスはサポートされません。Windowsディレクトリを既定で使用します。#640d5d311280f00000725613を読む限り、原因を消しても警告は消えないっぽいな
terminalのせいかもしれないので、念のためhyperで試してみたがだめだった
https://gyazo.com/0f2750aa52c0bb0868f418b9e159bff6
登場する文字コードはUTF-8とShift_JISとUTF-16
UTF-16はPowerShellの記事にちらっと出てきた
関係ないかも
WSLの文字コード周りがあやしいかも
WSLにShift_JISを渡す方法:PowerShellの意外な使い方 - Qiita
ASCII.jp:Windows Subsystem for LinuxとWindows内の文字コード (1/2)
cmdからWSLを使って日本語文字列をパイプで扱うとcmdのコードページが壊れる - 記憶は人なり
pipe symbolの問題?
一番関係ありそう
g:clipboardは内部でsystem()を呼び出している
https://code2svg.vercel.app/svg/L37-49/https://raw.githubusercontent.com/neovim/neovim/v0.8.3/runtime/autoload/provider/clipboard.vim#.svg https://github.com/neovim/neovim/blob/v0.8.3/runtime/autoload/provider/clipboard.vim#L37-L49
https://knowledge.sakura.ad.jp/23436/#i-4
system()にpipe symbolを渡せないのはなぜ?
https://vim-jp.org/vimdoc-ja/builtin.html#system()
渡せない理由は書かれていない
MSYSで標準出力をクリップボードにコピー - プログラムdeタマゴ
References
Powershell で文字コードを変更する(clip.exe へのリダイレクトもね)
vim-jpの#questionスレッド
お世話になりすぎて頭が上がらないtakker.icon*3
/nishio/nishio.iconさん
頭を冷やすよう促された(雑解釈)
ありがとうございますtakker.icon
referencesではないけどまあいいや
各種処理の入出力文字コード設定方法 - Lazy Diary @ Hatena Blog
#2023-03-13 09:27:01
#2023-03-12 09:45:17