Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

複数の'filetype'を扱いたい #1034

Open
keik8128 opened this issue Mar 4, 2017 · 19 comments
Open

複数の'filetype'を扱いたい #1034

keik8128 opened this issue Mar 4, 2017 · 19 comments

Comments

@keik8128
Copy link

keik8128 commented Mar 4, 2017

まだまだ仕様について検討が必要ですが、必要か否か、実装難度、仕様の不備などについてご意見をいただければ幸いです. なお、実装にはほとんど手を着けていません完了しました.

概要

現状でもsetl ft=foo.barは可能だが, 様々な問題が起こる(後述). これを何とかしたい

※以下の議論のほとんどは'filetype'だけでなく'syntax'にも当てはまる

動機

  • filetypeがvimのとき、特に.vimrcで
command! -nargs=*
    \ Autocmd
    \ autocmd vimrc <args>

のようにしているとき, Autocmdautocmdと同様にハイライトしたい(他のvimファイルでは必要ない)

  • 巨大なライブラリに対してハイライトがほしい(そのライブラリを使っていないときは必要ない). DSLを駆使するような言語ではほぼ構文と見なせるのでハイライトしてもいいはず.

現状

  • setl ft=foo.barすることで, fooとbarをfiletypeとして設定できる
  • fooのFilwType autocommandは走るが, barでは走らない
  • ftplugin/やindent/はfoo, bar共に走る

現状の問題点

  • ほとんどのプラグインが&filetype==#'foo'というようにしてファイルタイプを判定するので, この場合fooでもbarでもないファイルタイプとして扱われる
  • FileType autocommandが走らない

※なお, 'syntax'については==#で判定することが(たぶん)ほぼないので, それほど問題ではない

現状の対応策

  • 使わない
  • 新しいファイルタイプ, シンタックスを定義し, もとのftpluginやindent, syntaxをsourceする
    • after以下を勝手に読むわけにはいかないのでユーザー側の対応が必要
    • 新しいファイルタイプは&filetype==#'foo'の判定にかからない
    • 新しいファイルタイプは元のファイルタイプに仕掛けられていたFileType autocommandが走らない
  • 対応していないプラグインにPRを片っ端から投げる
  • Vim本体にfiletypeを取得, 判定する関数を入れる. getmainft(), getfts(), getminorfts(), ...
    • 一つ上の案をもう一歩進めた形
    • こちらもPRを投げまくる作業が必要. Vim本体で対応する分, 活発に開発されていれば開発者が対応してくれるだろう
    • 古いプラグインは壊れる(ft=foo.barはfooでもbarでもない)
  • autocmdで頑張る. autocmd {group} BufRead *.bar {let b:何らかの変数}
    • FileTypeが走らない(無理やりsourceする事はできるが、'runtimepath'をパースする事になる)
    • 変数名が問題になる(全員が同じ名前に統一しなければ無意味)
  • 現状での私の解決策
    1. ftdetect/vimrc.vimで、autocmd BufRead *vimrc* let b:ftplugin_vim_enable_vimrc = v:true
    2. after/{syntax,ftplugin}/vim_vimrc.vimで、↑の変数をチェック
    • 一つ上の方法と同じで、変数名の問題がある
    • filetypeごとの設定をするときにFileType autocommandは使わないようにしているので(すべてftplugin/やsyntax/で対応)、FileType autocommandが走らなくとも問題ない

求められる仕様

  1. 複合ファイルタイプを使わない選択肢をとることができる
  2. 単一ファイルタイプしか使っていない場合, 既存プラグインを壊してはならない
  3. 単一ファイルタイプしか使っていない場合に, 複合ファイルタイプを処理できるプラグインが壊れてはならない(複合が扱えるプラグインは単一も扱えなくてはならない)
  4. 単一ファイルタイプしか扱えないプラグインでも, 主要ファイルタイプは認識しなければならない
    • 現状のset ft=foo.barはこの点に大きな問題がある. foo.barはfooでもbarでもない
  5. ft=foo.bar型の複合ファイルタイプ(後述する運用2)も扱えなければならない
  6. 既存の'ft'の仕様は、互換性のためになるべく変えたくない

実現手段

新しいオプション

'minorfiletypes' 名前は暫定(候補: filetypes, subfiletypes, ...)

  • コンマ区切りのファイルタイプ(ピリオドの方がいい?)
  • バッファローカルで, ('ft'同様)グローバルな値がない
setlocal minorfiletype=bar,baz
  • set ft=foo.bar.bazと違い, FileType autocmdが走る
  • メインのファイルタイプ(ここではfoo)は含まれない
  • ftplugin/やindent/, それらのafter/以下も読まれる

新しい関数

  • 5番目の仕様を満たすために, 是非ほしい(shiftwidth()のような役割)
  • ftとmftを両方みて結果を返す
getmainft({bufnr})
" ft=foo.bar => foo

getfts({bufnr})
" ft=foo.bar, mft=baz => [foo,bar,baz]

...など

プラグイン側の対応とユーザーの設定

  1. 運用1: (best practice)
    ftは常に一つに保ち, mftに追加していく.
    この方法が優れているのは, 古いプラグインも少なくともftは認識する, という点. これが他の解決策と大きく違う. すなわち、mftを見ないプラグインにはPRを送らなくていい

  2. 運用2:
    ftにピリオド区切りで追加していく

  3. パターン1: プラグイン非対応でユーザーがmftを使用

    • mftは無視される
    • 運用1のとき, 少なくともftは認識する
      • ft=foo.barとの大きな違い
    • 運用2のとき, (従来通り)fooでもbarでもない謎のファイルタイプとなる
  4. パターン2: プラグイン非対応でユーザーがmftを不使用

    • なにも起こらない
  5. パターン3: プラグイン対応でユーザーがmftを使用

    • (運用方法によらず)すべてうまくいく
  6. パターン4: プラグイン対応でユーザーがmftを不使用

    • (運用方法によらず)すべてうまくいく

新しい関数は, このパターン3, 4において意味を持つ.
すなわち, 運用2が使われた場合でも, 従来とは違ってきちんと複合ファイルタイプを認識できる
(プラグインが直接オプションに触れずに関数からアクセスしていればの話)

使用例

" +=と^=のどちらが適切なのかは仕様をもう少し詰めなければいけない
autocmd BufRead *vimc* setlocal minorfiletypes+=vimrc
if exists('b:did_ftplugin_vimrc')
    " b:did_ftpluginはft=vimの時点でletされるので使えない
    finish
endif

...

let b:b:did_ftplugin_vimrc = 1

indent/やsyntax/も同様

その他考察

  • TODO commentstring, defineなどのファイルタイプに深く関わるオプションをどうするか. なにも考えずに実装すると後に指定したファイルタイプほど優先される(上書きされていく)と思う. 上書きした方がいいか残した方がいいかは場合によって変わりそうなので、もう少し考察する必要がある

  • TODO major filtypeとして呼ばれたのかminor filetypeとして呼ばれたのかは判別できた方がよさそう. 別のイベントを発行するわけにはいかないので, v:変数を使うことになる

  • TODO feature. 新しいfeatureにすべきか(filetypeやsyntaxに準じるべきではないか). また、'syntax'が使える条件と'filetype'が使える条件は異なる. 'syntax'が使えないのに+minorsyntaxされると困る. 現在feature同士の依存関係はあるのか? 要調査

  • TODO did_filetype()はどうなるべきか?

    • 新たにdid_minorfiletype()を作り, did_filetype()は'ft'のみ考える
    • 一つでもfiletype, minorfiletypeが設定されており, 一回でもFileTypeが走ったならばtrue
  • TODO filetypeは排他的にするべきか? 現在は排他的でない(ft=foo.barが可能)ので, 排他的にすると互換性が壊れる. :setfを使えば排他的になる

  • TODO ft=不明でmft=foo.barはあり得るか? ftがない状態でmftが設定されても予想外の事態は起きないか?

  • TODO b:did_ftpluginやb:undo_ftpluginの扱い

  • TODO 'ft'と'mft'はディレクトリを分けるべきか? mftplugin/, mindent/, msyntax/とか

以下の仮定をおくと上の問題のいくつかが(たぶん)解決する

仮定1: mftに対するftpluginやindentは新しく作られる
すなわち, 必ずmftに対応している

仮定2: mftはEmacsのように様々なファイルタイプに対する共通の設定ではなく, ftに付随するものである(is a関係が成立する)
e.g.) ruby <- rspec vim <- vimrc cpp <- cppheader

問題1は, commentstringやdefineが書き換わりようがない(XXX is a YYYが常に成立している)ため, 問題にならない
例えばft=vim, mft=vimrcだとすれば、vimrcでvimと矛盾するような設定はするはずがない(いきなりsetl iskeyword+=?なんてことはしない)

問題4,7は, 仮定1があるため, 新しい関数, 変数を用意することで解決する

  • もし仮定1がなければ, mft未対応のファイルタイプがmftとして読み込まれる可能性を排除できない
  • また、仮定2のおかげで、ft=python, mft=rubyなどの求められる挙動がよくわからない状態に陥ることを排除できる
@keik8128
Copy link
Author

keik8128 commented Mar 5, 2017

仮定1, 2に加えて仮定3を導入し、考察を進めました.
'ft'についてしか書いていませんが、'syn'にも適用されます

仮定3: mftに対するプラグインはftとして読み込まれることはなく、必ずmftとして読み込まれる

仕様

オプション

minorfiletypes 'mft' バッファロー狩る
コンマ区切りの文字列
セットされると、コンマで区切られたそれぞれのfiletypeに対して先頭から順番にFileType autocommandを発生させる
'filetype'未定ならエラー
'filetype'が変わるとリセットされる

ランタイムディレクトリ

mftdetect/
mftはftがセットされていないと無効なので、ftdetect/以下よりも後に読み込む必要がある
:runtimeで読み込みの順番を指定することはできないので、ftdetect/以下を読み込んだ後mftdetect/を読み込むような処理をfiletype.vimに入れる

v:変数

v:ft_isminor
FileType autocommandが呼ばれているとき有効.

関数

did_filetype()は従来通り'ft'に対する変更のみ考える. 'mft'が変更されても関知しない

did_minorfiltype()は今のところ必要性を感じていない

$VIMRUNTIM/syntax/syntax.vim

現状

augroup syntaxset
  au! FileType *    exe "set syntax=" . expand("<amatch>")
augroup END

これは、FileTypeがftかmftかで'syntax'を変更するか'minorsyntax'を変更するかを振り分けるように書き直す必要がある

minorfiletypesをセットする方法

  • &rtp/filetype.vimに、'filetype'をセットするautocmdより後に記述('ft'を先にセットさせるため)

  • &rtp/mftdetect/*.vimに記述

  • .vimrcに&rtp/filetype.vimのようなautocmdを書く. ただし、filetype onの後に書くこと. これは、'mft'を決めるautocommandを'ft'を決めるautocommandよりも後に実行させるためである

autocmd filetypedetect BufNewWin,BufRead *.foobar set minorfiletypes+=foobar

場合によってはset mft=foobarset mft^=foobarがよりふさわしいかもしれない

mftに対する設定

ftplugin/やindent/を使う派

In ftplugin/○○.vim
もちろんafter/以下でもかまわない

" このファイルの多重ロード防止
if exists('b:did_ftplugin_○○')
    " b:did_ftpluginは'ft'がセットされ(てFileType autpcommandが走りftplugin/*.vimが読み込まれ)た時点でletされるので使えない
    finish
endif

" mftはmftとしてしか使えない
if !exists('v:ft_isminor') || !v:ft_isminor
    finish
endif

" もしも、あるfiletypeのもとでしか動作しないというのであれば、ここで判定する
if &filetype !=# ...
    finish
endif

...

let b:b:did_ftplugin_○○ = 1

FileType autocommand派

In .vimrc

autocmd AnyGroupName FileType ○○ call s:func()

function! s:func() abort
    if !v:ft_isminor
        return
    endif
    ...
endfunction

@keik8128
Copy link
Author

keik8128 commented Mar 6, 2017

※例によって'ft'と'syn'両方に当てはまります

新しい関数

getfiletype({expr})
getminorfiletypes({expr})

{expr}|bufname()|に準じる
'ft'と'mft'を両方見て結果を返す

擬似コード

getfiletype(expr)
    ft = get_option(expr, 'filetype')
    return split(ft, '.')[0]

getminorfiletypes(expr)
    ft = get_option(expr, 'filetype')
    mft = get_option(expr, 'minorfiletypes')
    if contains(ft, '.')
        return split(ft, '.')[1:] + mft
    else
        return mft
  • TODO: filetypeやminorfiletypesなどは省略すべきか

  • TODO: 以下のような関数を利便性のために用意すべきか

" 厳密に{filetype}であるかどうか
function! s:ft_is(expr, filetype) abort
    let ft = getfiletype(a:expr)
    let mft = getminorfiletypes(a:expr)
    return ft ==# a:filetype && empty(mft)
endfunction

" major, minorを問わず{filetype}が含まれているか
function! s:ft_contains(expr, filetype) abort
    let ft = getfiletype(a:expr)
    let mft = getminorfiletypes(a:expr)
    return ft ==# a:filtype || index(mft, a:filetype) != -1
endfunction

互換性について

ファイルタイプが複合された時(ft=foo.bar)、fooでもbarでもないファイルタイプとなることを前提としたプラグイン・設定が壊れる.
例1)
doxygenは、vimに組み込まれているftplugin/syntaxの中で数少ない(唯一?)複合ファイルタイプを利用するファイルタイプであるが、doxygenが有効になっているかどうかを'ft'をみて決定するようなプラグインがあれば、動作が壊れる
'mft'が導入されれば当然doxygenもそれに準じて書き直されるべきで、その場合はft=c(やcpp, javaなど), mft=doxygenとなっているからである

例2)
.vimrcで、

" ここで、この辞書変数はファイルタイプをキーに取るものとし、このsomepluginは'mft'未対応の古いプラグインとする
let g:someplugin#config = {'foo': 'FOO'}

などと書いており、ユーザーがft=foo.barとしたときに、ユーザーの期待する動作が'FOO'が反映されないことだった場合.
すなわち、

ほとんどのプラグインが&filetype==#'foo'というようにしてファイルタイプを判定するので, この場合fooでもbarでもないファイルタイプとして扱われる

という、問題点として挙げられていた動作が、まさに期待していた動作だった場合.


今のところ思いつく互換性の問題は上の2つです. vim組み込みのファイルタイプで複合ファイルタイプに対応したものはごく少数(doxygenだけ?)であること、ユーザー側が複合ファイルタイプを積極的に利用しづらい状況であったことを鑑みると、互換性を保つために何らかのフラグを設けるといった対処は必要ないように思います.

Featureについて

  1. 新たなfeatureは作らず、'filtype'、'syntax'が有効になる条件に準じる
    • 現在の状態をバグだと捉える
  2. 新たなfeatureとして、+minorfiltypes+minorsyntaxをつくる
    • 機能追加と捉える

どちらをとっても、'mft'が使えるが'msyn'が使えないといった状況があり得るため、少なくとも標準のscriptはすべての場合について対応が必要


私は案1を推します



しばらく待って仕様について異論がないようであれば、この方向で実装を進めようと思います

@tyru
Copy link
Member

tyru commented Mar 6, 2017

個人的には、新しい関数や変数を導入すると、set shiftwidth=0 の機能のような、runtime ファイルの方の対応が遅れて結局使うに使えない状況になる可能性を危惧しています。
(この機能はほぼ 2年前の Vim 7.4.694 に追加されたにもかかわらず、runtime の indent プラグインのほとんどが対応していません。その理由はメンテナと連絡が付かないことや Vim の管理方法自身の問題といった複合的なものです。ここで詳しく説明するのは本題から逸れるので、すみませんが詳しくは上記 issue を参照してください)


そこで、「現状の対応策」の

新しいファイルタイプ, シンタックスを定義し, もとのftpluginやindent, syntaxをsourceする

この案の考えを進めて、以下のように任意の仮想ファイルタイプ(あるいは子ファイルタイプ)を作れるようにするとどうでしょうか?

filetype virtual {child-filetype} extends {filetype}

仮想ファイルタイプを作った後はそのファイルタイプに対して autocmd FileType などで個別の設定を追加できます。

@h-east
Copy link
Member

h-east commented Mar 6, 2017

Issueのタイトルや概要が動機の文章とどう繋がるのかが分からないでいます。
「動機」でハイライトしたいと言っているのはcommandの定義部分のAutocmdでしょうか?

command! -nargs=*
    \ Autocmd
    \ autocmd vimrc <args>

それとも、そのコマンドを使用している部分でしょうか?それとも両方?

Autocmd hoge

あと、「現状の問題点」のFileType autocommandが走らないは今でも:doautocmdを使えば実現可能ではないか思っていますけど、無理です?

@keik8128
Copy link
Author

keik8128 commented Mar 6, 2017

Re: @tyruさん

個人的には、新しい関数や変数を導入すると、set shiftwidth=0 の機能のような、runtime ファイルの方の対応が遅れて結局使うに使えない状況になる可能性を危惧しています。

これに関しては、この二つの仮定から、既存のruntime/以下にあるファイルの変更は(ほぼ)ないものと考えています

仮定1: mftに対するftpluginやindentは新しく作られる
すなわち, 必ずmftに対応している
仮定3: mftに対するプラグインはftとして読み込まれることはなく、必ずmftとして読み込まれる

例外として、

  • ドキュメント系
  • runtime/optwin.vim
  • runtime/filetype.vim
  • runtime/syntax/sntax.vim

すべてMaintainer: Bram Moolenaarですので、問題にはならないと思います


1つ上で、

'mft'が導入されれば当然doxygenもそれに準じて書き直されるべきで、

と書いていましたが、メンテナの問題を鑑み、書き直すか否かは保留します.


Re: @h-eastさん

ハイライトしたいのはAutocmdを使用している箇所です.

FileType autocommandが走らないは今でも:doautocmdを使えば実現可能

おっしゃる通り可能だと思います. FileType autocommandに関しては、doautocmdを明示的に書かなくてよくなる程度の意味しかありません. 解決したいのはむしろこちらの問題です

ほとんどのプラグインが&filetype==#'foo'というようにしてファイルタイプを判定するので, この場合fooでもbarでもないファイルタイプとして扱われる

@h-east
Copy link
Member

h-east commented Mar 6, 2017

@keik8128 私の最初の質問に答えて貰えると嬉しいです。

@keik8128
Copy link
Author

keik8128 commented Mar 6, 2017

Re: @h-eastさん

Issueのタイトルや概要が動機の文章とどう繋がるのかが分からないでいます。

私が考えている「複数のファイルタイプ」というのは、ft=ruby.pythonのような互いにほぼ関連のないファイルタイプの複合状態でも、Emacsにおけるmajor/minor modeでもなく、ft=ruby.rspec, ruby.rails, vim.vimrcといった、A.Bにおいて、BがAに付随する(B is an Aが成り立つ)状態です.
vimrcに特有の設定をしたいというのはその一つの例です

説明がわかりにくく申し訳ありません

@h-east
Copy link
Member

h-east commented Mar 6, 2017

@keik8128 なるほど。ただ、明示的にfiletypeをそういう指定をしなくても良いと思うのです。
ft=railsでいいのではないかと。syntax/rails.vim

runtime! syntax/ruby.vim

すればいいのではないかと思います。

現に、syntax/cpp.vimは、

" Read the C syntax to start with
runtime! syntax/c.vim
unlet b:current_syntax

という処理が入っています。これを踏襲すればいいのではないでしょうか?

@keik8128
Copy link
Author

keik8128 commented Mar 6, 2017

Re: @h-eastさん

ft=railsとすると、既存のプラグインで

if !exists('g:foo_plugin#config')
    let g:foo_plugin#config = {}
endif
let g:foo_plugin#config.ruby = ...

のようにしていた場合、railsに対しても

let g:foo_plugin#config.rails = g:foo_plugin#config.ruby

が必要になります.

また、rubyに対してこのfoo_pluginのデフォルト設定を使っていた場合、

let g:foo_plugin#config.rails = g:foo_plugin#config.ruby

とした箇所でfoo_pluginがautoloadされます

autoloadされるのを防ごうとすれば、

let g:foo_plugin#config.rails = {foo_plugin.vimからコピペしてきたft=rubyに対するデフォルト設定}

となってしまいます.

更に、そもそもこのようにユーザーが設定することを考慮していないプラグインも存在します

@tyru
Copy link
Member

tyru commented Mar 6, 2017

考察は非常に面白いと思ったのですが、自分も @h-east さんに同意見です。

現状、複数の filetype を設定するケース自体が(確かにそのようなシステムが無くて不便な時はありますが)あまり無い気がしていて、新たに minor filetype という概念を導入するほどではない、と思います。
大体のケースはファイル名やディレクトリ名決め打ちで auto-command を登録して、それぞれの設定を行ったりすることで解決してしまうと思います。
(そのような解決策があまりスマートではない、という意見は同意です)
※そのような解決策はしたくない場合、ディレクトリ以下にローカルな設定を書ける localrc.vim といったプラグインもあります。


…と書こうとしていたら先にコメントを書かれましたが、これは面白い視点だと思いました。
継承元との運用透過性(ft=rails とせず ft=ruby mft=rails とすることで ruby の設定をそのまま引き継ぐ)を意識したのですね。

しかしこの用途のためにこれらの関数やオプションを導入する、というのはやはりメリットが薄いように思います。
個人的には filetype virtual {child} extends {parent} の仕組みなら Vim が派生元を覚えておけるので、上記の運用透過性も実現できると思います。

@keik8128
Copy link
Author

keik8128 commented Mar 7, 2017

filetype virtual {child} extends {parent}

このコマンドがなにをするのかがいまいち理解できておりません. 以下のような理解で正しいでしょうか?

  • 'ft'は変更されない({parent}のまま)
  • {child}に対するFileType autocommandは走る
  • {child}に対するftplugin, indentは読まれる

ユーザー側から{child}や派生元({parent})が何なのかを知るには、やはり何らかのインターフェースが必要になると思いますが、もしこのインターフェースをオプションにすれば、結局'mft'に行き着いてしまうように思います.

大体のケースはファイル名やディレクトリ名決め打ちで auto-command を登録して、それぞれの設定を行ったりすることで解決してしまうと思います。

tpope/vim-railsを例に挙げると、このプラグインはrailsかどうかを「ファイル名やディレクトリ名決め打ちで auto-command を登録して、それぞれの設定を行っ」ていますが、ftがrubyのままなので、ほかのプラグインは今扱っているファイルがrailsであるのかを知るすべがありません(正確には、vim-railsに依存せずに知るすべがありません).
これによって、もしもrailsに対するプラグインを書こうとすれば、vim-railsに依存するか、自前で同様の判定を行うかしかありません.
この例ならば、vim-railsは非常に有名なプラグインでユーザー数も多いことから、vim-railsに依存しても問題ないかもしれませんが、Vim本体でこういったサポートをすれば、プラグイン同士の連携がとりやすくなるのではないでしょうか.


現状、複数の filetype を設定するケース自体が(確かにそのようなシステムが無くて不便な時はありますが)あまり無い気がしていて、新たに minor filetype という概念を導入するほどではない、と思います。

得られるメリットに比べて変更範囲が大きくなりすぎることはソースコードの調査段階で私自身感じていたことでもあります. せっかくソースコードを調べたので実装はしてみようと思いますが、本家に投げるかはその後また考え直したいと思います. @h-eastさん、@tyruさん、ありがとうございました.

@tyru
Copy link
Member

tyru commented Mar 7, 2017

すみません、コードだけでほとんど説明していませんでした。

ユーザー側から{child}や派生元({parent})が何なのかを知るには

まずこれに関しては、ユーザーが知る必要はないと思っています。
というのは、以下で説明するように派生先のファイルタイプが 派生元のファイルタイプ + 派生先固有の設定 のように透過的に振る舞えばユーザーがチェックして分岐する必要はないと思っているからですが、もし必要なケースがあるということでしたら教えてください。

このコマンドがなにをするのかがいまいち理解できておりません. 以下のような理解で正しいでしょうか?

  • 'ft'は変更されない({parent}のまま)
  • {child}に対するFileType autocommandは走る
  • {child}に対するftplugin, indentは読まれる

基本的に Yes ですが、1番目だけ補足します。

  • 'ft' は filetype virtual コマンドを実行した時は変更されない({parent}のまま)
  • しかし filetype virtual rails extends ruby とした時、ft=rails の時、ft=rails と ft=ruby の処理が両方走る

つまり、以下も行います。

  • {parent}に対する FileType autocommand も走る
  • {parent}に対する ftplugin, indent も読まれる

そうすれば #1034 (comment) のコメントのようなことは起きないと思います。

@keik8128
Copy link
Author

keik8128 commented Mar 7, 2017

しかし filetype virtual rails extends ruby とした時、ft=rails の時、ft=rails と ft=ruby の処理が両方走る

この点は私もそのつもりでいました. わかりにくい表現になってしまいすみません.

まずこれに関しては、ユーザーが知る必要はないと思っています。
というのは、以下で説明するように派生先のファイルタイプが 派生元のファイルタイプ + 派生先固有の設定 のように透過的に振る舞えばユーザーがチェックして分岐する必要はないと思っているからですが、もし必要なケースがあるということでしたら教えてください。

ファイルタイプごとに設定が変わるのはftpluginやindent以下において使うプラグインだけではないので、必要なケースはあると思っています.

if !exists('g:foo_plugin#config')
    let g:foo_plugin#config = {}
endif
let g:foo_plugin#config.ruby = ...
let g:foo_plugin#config.rails = {rubyとは違う設定}

このような設定をさせるプラグインは多く、これらの挙動を派生元と派生先で変えたいことがあります. ほとんどの場合ではft=rubyで振る舞ってほしいのですが、逆に挙動を変えたいときには何らかの形でこれがrailsであることを知る必要が出てきます. もしこのfoo_pluginがmftに対応すれば、mft=railsという付加情報を受け取ることができます. また、対応できていなくとも、少なくともft=rubyにはなります.
mftを新設する利点として既存のftにはほとんど影響を与えないことがあると思っていて、99%同じだがほんの少し挙動を変えたいといったときに、対応していれば100%の挙動をし、対応していない場合でも99%は求める挙動をしてくれます. この1%を埋めるためにここまで大掛かりにするべきかはまた別ですが...

@tyru
Copy link
Member

tyru commented Mar 9, 2017

すみません、返信が遅れました。
なるほど、プラグインで指定する場合は必要になるかもしれません。
自分の方でも mft が必要になるケースがあるか探ってみます。

@keik8128
Copy link
Author

実装終了しました。ドキュメントはおそらくまだまだ抜けがあります。
上に書いた仕様から以下が変更されています

  • 関数なし
  • minorfiletype => extrafiletypes, minorsyntaxes => extrasyntaxes
    Emacsのminor modeとは全く違うものなので混乱を避けるためリネーム

https://github.com/keik8128/vim/tree/feature/extrafiletypes

使用例:

" .vimrcの最後にモードラインとして
" vim: ft=vim:eft=vimrc

" もしくは .vim/eftdetect/vimrc.vim
autocmd BufNewFile,BufRead *vimrc* set eft=vimrc
" .vim/syntax/vimrc.vim
if exists("b:current_syntax_vimrc")
    finish
endif
if !v:syn_isextra
    finish
endif
if b:current_syntax !=# 'vim'
    finish
endif

" Autocmd
syn keyword vimrcAutocmd Autocmd skipwhite nextgroup=vimAutoEventList

" Plugin manager command
syn keyword vimrcPluginManager Plug

hi default link vimrcAutocmd       vimAutocmd
hi default link vimrcPluginManager vimCommand

let b:current_syntax_vimrc = 1

@h-east
Copy link
Member

h-east commented Mar 11, 2017

@keik8128 👍
本質的なところではないですが、1点だけ。
この行と次の行、意図せず文字が変わっているようです。
vim/vim@master...keik8128:feature/extrafiletypes#diff-bea881dfa9626bab7141337b0fcdb23eR3054

@keik8128
Copy link
Author

修正しました

@k-takata
Copy link
Member

á の部分、まだ差分が出ているようです。eval.txt は fenc=latin1 で編集をお願いします。

@keik8128
Copy link
Author

なるほど、encodingのせいでしたか。今度こそ修正できたはずです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants