vim-jp / issues

有志で既知のバグや要望を検討・管理し、オフィシャルへの還元をしていきます。
https://vim-jp.org/
341 stars 11 forks source link

タブ文字と breakindentopt=list:-1 組み合わせ時のインデント量 #1398

Open iranoan opened 2 years ago

iranoan commented 2 years ago

質問の内容

set breakindentopt=list:-1

とした時、折返し行のインデント量は、タブ文字が常に1として計算されます

これは意図してこの様になっているのでしょうか?

再現動画

breakindentoption 上動画は GVim を使っていますが、下記設定ファイルのコメントに有るように端末でも再現します また set expandtab を使っていませんが、使った場合の自動整形は tabstop に応じた個数だけスペースが入力されるので、strwidth() ではなく strdisplaywidth() 相当でインデントされたほうが対応を考えると自然な気がします

\~/.vim/vimrc

filetype plugin on
set autoindent
set formatoptions+=n
set breakindent
set breakindentopt+=list:-1
set textwidth=40
" 下記は幅指定目的で GVim を使い、動画で違いをわかりやすくする指定で再現自体には関係しない
set background=dark
colorscheme desert
set guioptions+=M
set guioptions-=T
set guioptions-=m
set list listchars=tab:\I-,space:␣,eol:$
set number
set columns=40 lines=8
augroup GUIVIM
    autocmd!
    autocmd VimEnter,GUIEnter * ++nested set columns=40 lines=8
augroup END

Vimのバージョン

$ vim --version VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Sep 13 2022 09:35:02) 適用済パッチ: 1-3995, 4563, 4646, 4774, 4895, 4899, 4901, 4919 Modified by team+vim@tracker.debian.org Compiled by team+vim@tracker.debian.org Huge 版 with GTK3 GUI. 機能の一覧 有効(+)/無効(-)

OSの種類/ディストリ/バージョン

$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.1 LTS Release: 22.04 Codename: jammy $ uname -a Linux xxxxxxx 5.15.0-50-generic #56-Ubuntu SMP Tue Sep 20 13:23:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

koron commented 2 years ago

9.0.0752 で再現

image

こんな感じの矛盾があるっぽい。なんでこうなってるのかは不明。


補足:

breakindent は warp された行の先頭に見た目上のインデントを追加する。

breakindentopt はその動作をカスタマイズするためのオプション。

breakindentoptlist:-1 という値は、インデント量の判定に formatlistpat でマッチした物理的な長さを使ってる。

一方で breakindent 自身は、先行する空白文字を別口でインデントとするらしい。 そしてその場合の長さは物理的なものではなく、見た目的なものとなっている。

この違いが不自然さを生じていると考えられる。

koron commented 2 years ago

先行する空白をインデントと認識している箇所。

https://github.com/vim/vim/blob/db4c94788ad70118fa1ccc5fbc821757350ac771/src/indent.c#L978-L979

コメントを見ると、見た目(cell)で取れることがわかる。

https://github.com/vim/vim/blob/db4c94788ad70118fa1ccc5fbc821757350ac771/src/indent.c#L430-L435

つまり prev_indent にインデント幅が見た目(cellサイズ)で入ることがわかる。

その後 formatlistpat が利用でき、かつマッチする際に prev_indent が上書きされる。 この時は見た目は考慮せず純粋にマッチした文字数に上書きされている。

https://github.com/vim/vim/blob/db4c94788ad70118fa1ccc5fbc821757350ac771/src/indent.c#L986-L1001

koron commented 2 years ago

prev_indent = (*regmatch.endp - *regmatch.startp); の箇所で linetabsize_str()*regmatch.endp[0] = NUL して regmatch.startup[0] (もしくは *regmatch.startup) を渡せばよいはず。

ただ漫然と endp[0] を書き替えて良いとも思えないので、 呼び出し前に退避して呼び出し後に復帰する もしくは save & free するみたいなことが要りそうね。

koron commented 2 years ago

やる気が切れたので僕はいったんここまで。

iranoan commented 2 years ago

色々調べていただきありがとうございました 環境依存でないことが分かっただけでも助かります