cxxxr / cl-lsp

An implementation of the Language Server Protocol for Common Lisp
MIT License
216 stars 26 forks source link

windowsでリクエストメッセージにマルチバイト文字列が入っているとパースエラーになる場合がある #11

Closed cxxxr closed 1 year ago

cxxxr commented 4 years ago

環境 windows 10 vim 8.2 vim-lsp/vim-lsp-settings roswell 20.06.14.107(NO-GIT-REVISION) sbcl 2.0.0

例として以下のファイルを用意する

(defun f ()
  あ)

これをvimで開きvim-lspがcl-lsp stdion を起動したとき以下のリクエストが行われる(vim-lspのログ出力から抜粋)

2020/10/30 4:27:42:["--->",1,"cl-lsp",{"method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///C:/Users/user/tmp/test.lisp","version":1,"languageId":"lisp","text":"(defun f ()\n  あ)\n\n"}}}]

このときcl-lspはbodyをread-charで読み込み返ってきた文字をutf-8のバイト列分だけcontent-lengthから引いていき、0になるまでこれを繰り返す https://github.com/cxxxr/cl-lsp/blob/a14d5b93576d4fb820a1ffdd7497198e85eb37fb/jsonrpc-patch.lisp#L23

ここで"あ"はutf-8だと(227 129 130)の3要素のバイト列になるが、read-charの返り値が #\あ ではなく(227 129)と(130)に分割された返り値になることがある (227 129)を"縺"という文字列で扱ってしまい、babel:string-size-in-octetsで3バイト列として扱われる これが原因でread-charの回数とcontent-lengthの値が合わなくなる

mattn commented 4 years ago

Windows の sbcl だと read-char が cp932 を期待してるのではないでしょうか。

image

おそらく read-byte を使う必要があるかも。

mattn commented 4 years ago
(setf sb-impl::*default-external-format* :utf-8)
(setf sb-alien::*default-c-string-external-format* :utf-8)

をどこかに書いて試してみます。

snmsts commented 4 years ago

sbcl windowsは端末の言語設定にあわせてencodingをかえちゃうので、utf-8だけだと思っているとあしをすくわれがちですね。

https://github.com/cxxxr/lem/pull/527

mattnさんの試してみる方法(多分1行目)でちゃんと動くような気がしています。

cxxxr commented 4 years ago

sb-impl::*default-external-format* を変えても同じでした

cxxxr commented 4 years ago

逆にcp932ならそのままcp932として扱えば一応動くようにはなりました https://github.com/cxxxr/cl-lsp/pull/12

mattn commented 4 years ago

ありがとうございます。ちなみに read-byte を使わない理由って何かあるのでしょうか?

cxxxr commented 4 years ago

standard-inputはcharacter-streamなのでread-byteなどのバイト単位のオペレータは型エラーになるはずです

cxxxr commented 4 years ago

とりあえず #12 の修正で一応は直ったのでclose

mattn commented 4 years ago

なぜか分からないのですが僕の所ではまだ動かない様です。 didOpen の後に落ちてるぽいです。

cxxxr commented 4 years ago

https://github.com/cxxxr/cl-lsp/tree/issue-11-debug

このブランチで以下の内容のファイルを開いて閉じたときのログ出力結果は下に添付しているログファイルと比べて何か違いはありますか?

(defun f ()
  あ)

cl-lspのログ lsp.log vim-lspのログ lsp.log

mattn commented 4 years ago

特に違いは無いようです。そして

(defun f ()
  あ)

のコードは幾ら編集しても落ちません。

(defun f ()
  あ い う)

にしても落ちません。しかしダブルクオートを入れ出した途端、落ちてしまう様です。以下は

(defun f ()
  "あ" "い" "u")

に編集し、cl-lsp が終了した直後の lsp-log です。

lsp.log

image

cxxxr commented 4 years ago

ありがとうございます、とりあえず手元で再現はしました。

cxxxr commented 4 years ago

い"のところで32314, 1067の列として読み込まれ、それぞれ(231 184 186), (208, 171)になり合わせた列がい"を表すはずですが (babel:string-to-octets "い\")#(227 129 132 34)になるので違うんですね そもそもread-charの返り値をcp932とみなしてたのが間違えてるのかもしれません

read-charでutf-8の文字列を読み込めればいいんですが、default-external-formatを変えても結果は変わらず、文字コードやsbclの文字コードまわりの扱いについて精通していないので自力ではすぐには直せなさそうです