質問・報告の内容
C ドライブ直下での finddir() による上方検索の結果が、想定した動作と異なります。
" 前提条件、:pwd で見えるカレントディレクトリに .git フォルダがあって、
" C ドライブ直下には .git フォルダがない状態。
:echo finddir('.git', 'C:\')
" 何も表示されない
:echo finddir('.git', 'C:\;')
.git
上 2 つの結果は同じになると思ったのですが、実際には下のケースではカレント
ディレクトリに対する検索結果が返ってきているように見えます。調べてみたところ、
vim_findfile_stopdir() という関数の中で "\;" がエスケープシーケンスとして処理
されてしまい、"C:" という path で検索しようとした結果、相対 path であると判断さ
れカレントディレクトリの結果が返されたようです。Windows の ドライブ直下のみで
ヒットすると思われます。以下の方法では想定通り空文字列が返ってきます。
:echo finddir('.git', 'C:\\;')
:echo finddir('.git', 'C:/;')
関連 help:
:h finddir()
:h file-searching
C ドライブ直下での上方検索に特に意図はなく、あるファイルが git 配下にあるかどう
かを調べるために以下のようにしていたら、単に C ドライブ直下にあるファイルで期待
しない結果が返ってきたことに気が付いた、という経緯です。
let l:result = finddir('.git', expand('%:p:h') . ';')
スクリプト側でお手当してあげれば特に問題はないのですが、特に help にも記述がな
く一人で割と嵌ったので、報告をあげたほうがいいのかなと思い issue を立てました。
Vimのバージョン
8.1.0155
OSの種類/ディストリ/バージョン
- Windows 10 Home 64bit, Ver. 1803, Build: 17134.112
使用している or 関係していそうなプラグイン
プラグインは特に関係なさそうに思います。
その他
以下、Slack 上の vim-jp で、@koron さんとやり取りさせていただいた経緯を貼っておきます。
7月2日 (月)
すみません、自分ではバグかどうか判断がつかなかったので意見をお聞かせいただけないでしょうか。
:echo finddir('.git', 'C:\')
のように実行すると期待通り 'C:\' に対して検索がかかるのですが、
:echo finddir('.git', 'C:\;')
のように上方検索すると、カレントディレクトに対する検索結果が返ってくるように見えます。
調べてみたところ、vim_findfile_stopdir() の中で '\;' がエスケープシーケンスとして扱われてしまったため、相対 path と見なされカレントディレクトリを検索しているようです。
:echo finddir('.git', 'C:\\;')
だと期待通り動作するようです。いまいち、感覚と違う動きをしていたのでどうかなと思いまして。
raa0121 [21:35]
確かに、 `\;` がエスケープシーケンスとして扱われるなら (編集済み)
さらに `\` で動くのは正しい扱いのような気もしますね
:help \;
mnishz [21:39]
やっぱりそうなりますかね。'C:\Users\;' のようなケースでは期待通り動くので、ちょっと気持ちが悪いといいますか。。
Windows でドライブ直下で検索する場合はスクリプト側にお手当が必要ということですね。
KoRoN [21:50]
軽くソース読んでみたけど複雑でダメだ。もうちょっとちゃんとみないとどう扱ってるかわかんない。
yoshitia [21:50]
Windowsだけに窓から放り投げるかLinuxインストールバトルで解決
KoRoN [21:51]
あ~
`C:` と から文字列 になってるんかねぇ (編集済み)
stop directoryが空ってことだよなぁ。
mnishz [21:53]
どうもありがとうございます。そうですね、'C:' で検索されているので、どこかのmch_isFullName() で、絶対 path でないと判断されているようです。
KoRoN [21:54]
いやどうもエスケープ関係ないんじゃないかな、と思い始めてる。
`'` だから `\;` はエスケープにならない。
:help file-search
vimhelp アプリ [21:55]
```11. ファイル検索 *file-searching*
{Vimが |+path_extra| 機能付きでコンパイルされたときのみ有効}
現在の所、オプション 'path', 'cdpath', 'tags' と|finddir()|, |findfile()| で、
本節で説明する「ファイル検索」にしたがってワイルドカードの展開が行われる。
それ以外のコマンドでは |wildcards| という少し異なるルールにしたがう。
ファイル検索には以下の3種類がある:```
mnishz [21:57]
あれ、そうですか。。
最初 ' だとエスケープされないはずだよなと思ったんですが、デバッグコードを仕込んでみてどうも vim_findfile_stopdir() でそのように扱われているように見えたのですが。。
KoRoN [22:01]
えっとそもそも `C:\;` で stopdir を空にしたい理由、狙いってなんなんです?
mnishz [22:03]
不思議なことをやっているのは重々承知なんですが、特に狙いがあったわけではなくて、
あるファイルがgit repository配下にあるかどうかを調べるスクリプトを書いていて、
KoRoN [22:04]
偶然やったら、その挙動に ??? ってなったって感じ?
mnishz [22:05]
finddir('.git', path . ";") のようにしていたのですが、たまたまC直下のファイルでやってみたら期待した動作と違ったので。
はい、そうなります。
KoRoN [22:09]
なるほどなるほど
仮に書式が `{start_dir};{stop_dir}` で、空の時はカレントディレクトリを使うとすると、なんか納得行く気がしますね。
いやだめか。
`vim_findfile_stopdir()` が stopdir を見つけられてない?
そうっすね。
`{start_dir}` の部分に `;` を含めるのを許容するために `\;` をここだけのエスケープ処理としてんのか。 (編集済み)
mnishz [22:16]
すみません、今再度 build 中です。ですが、r_ptr++ で飛んでしまい見つからずNULLで返っていたと思います。
KoRoN [22:17]
https://github.com/vim/vim/blob/ade55787978e15fe57c5cedf38c9f85bfe1d983c/src/misc2.c#L4501-L4507
GitHub
vim/vim
vim - The official Vim repository
で、セパレーターの `;` が見つからなかったから、そもそも `stop_dir` 無しという解釈になってるっぽいですなぁ。
おーけーおーけー
`C:\;` は start_dir = `C:;` と解釈されてますね。で、これは Win 的には `mch_isFullName() = FALSE` になってる。 (編集済み)
stop_dir は空。
mnishz [22:24]
はい、その通りです。(確認の結果そうでした。) (編集済み)
KoRoN [22:27]
これ、結局の所 `vim_findfile_stopdir()` が適当な自前のエスケープ処理してることで、エッジケースをサポートできなくなってるっていう感じですね。ただ `C:/;` にすれば回避はできる。 (編集済み)
とはいえフルにエスケープ対応しちゃうと、UNIXとかで `\` を含むディレクトリがエスケープなしで扱えていたのが、扱えなくなっちゃう。変な非互換性がでてくると。
「バグかどうかはわからないけれど、Windowsでこういうケースで使いたい時に困るんだよね。」って言えれば、修正は入れてもらえると思いますよ。
mnishz [22:32]
どうもありがとうございます。まさにWindowsのドライブ直下でしか hit しない感じですね。
おぉ
KoRoN [22:33]
ただ `C:\;` っていう指定は、本来ありえないんですよね。なので「こういうケースで使いたい時に~」とはいえない。
UNIX的な `/;` という指定には意味があるのかしら?
これがあれば、それに対応するWindowsの `C:\;` が使えない、ってのは根拠になるかと思います。
mnishz [22:36]
あぁ、なるほど。Root directoryでの上方検索が動くべきかどうかとうことですね。
個人的には「どうしてもこのケースが動かないと困る!」というよりは、おかしな動作(に感じた)ので報告してみたほうがいいのかなと思いまして。 (編集済み)
KoRoN [22:38]
一応、vim-jp/issues に↑の経緯をまとめて登録しておくのが良いかと思います。
mnishz [22:39]
分かりました!ありがとうございます。いろいろとコメントいただけて嬉しいです。
KoRoN [22:40]
「このケースが動かないと困る」がないならば「Vim scriptで雑にfinddir()の上方検索したい時に、ルートディレクトリかどうか判定して path の合成方法を変えなきゃいけないのは、無用な苦労を生んでるよね」みたいな言い方は通るかもしれません。
mnishz [22:47]
そうですね、というか「みんなあまりこんなことやらないのかな」という気がだんだんしてきました。
後ほどissuesに上げてみようと思います。
質問・報告の内容
C ドライブ直下での finddir() による上方検索の結果が、想定した動作と異なります。
上 2 つの結果は同じになると思ったのですが、実際には下のケースではカレント
ディレクトリに対する検索結果が返ってきているように見えます。調べてみたところ、
vim_findfile_stopdir() という関数の中で "\;" がエスケープシーケンスとして処理
されてしまい、"C:" という path で検索しようとした結果、相対 path であると判断さ
れカレントディレクトリの結果が返されたようです。Windows の ドライブ直下のみで
ヒットすると思われます。以下の方法では想定通り空文字列が返ってきます。
関連 help:
:h finddir()
:h file-searching
C ドライブ直下での上方検索に特に意図はなく、あるファイルが git 配下にあるかどう
かを調べるために以下のようにしていたら、単に C ドライブ直下にあるファイルで期待
しない結果が返ってきたことに気が付いた、という経緯です。
スクリプト側でお手当してあげれば特に問題はないのですが、特に help にも記述がな
く一人で割と嵌ったので、報告をあげたほうがいいのかなと思い issue を立てました。
Vimのバージョン
8.1.0155
OSの種類/ディストリ/バージョン
使用している or 関係していそうなプラグイン
プラグインは特に関係なさそうに思います。
その他
以下、Slack 上の vim-jp で、@koron さんとやり取りさせていただいた経緯を貼っておきます。