Flutterの自動生成ファイルと実装ファイルを切り替えできるようにVimのマッピングを設定した
最近また改めてFlutterでアプリを作ったりしてまして、Riverpodも結構進化しているらしくキャッチアップしてます。なにやらriverpod_generatorでコード生成するのがおすすめらしいみたいな話があり試してます。
riverpod_generator
riverpod_generatorの使い方やメリットは以前購入した村松さんの記事が参考になりました(該当箇所はいまのところ無料です)。プロバイダのホットリロードが可能になるあたりは嬉しいですね。
切り替えるのは簡単で、たとえばシンプルなFutureProviderを作りたい場合…以下のコードは Isarっていデータベース を開くコードなんですが、
final isarProvider = FutureProvider<Isar>((ref) async {
return Isar.open([MemoSchema]);
});
(keepAlive: true)
Future<Isar> isar(IsarRef ref) async {
return Isar.open([MemoSchema]);
}
という感じで、従来まで使っていたisarProvider
みたなやつは、自動生成されたファイルのほうに記述されるようになりました。ちなみに、このサンプルでコード生成すると、以下のようなファイルが生成されていました。
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'isar_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$isarHash() => r'222169261f8ccbaf7b55c3ada3ca3b7c8cb5aa81';
/// See also [isar].
(isar)
final isarProvider = FutureProvider<Isar>.internal(
isar,
name: r'isarProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$isarHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef IsarRef = FutureProviderRef<Isar>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
実際にこのProviderを使いたい場面では、従来通りisarProvider
を呼び出して使います。
困っていること
でまあここからがようやく本題なんですが、例えばこういったProviderを使っている側のクラスなりをいじってる時に「このProviderってどんな実装だったっけ?」って確認したいことあるじゃないですか。で、まあLSPなりの機能を使って定義ジャンプしますよね。
するとどうでしょう、当然ながら自動生成されたほうのファイルを開いちゃうわけです。俺は実装のほうを見たいんだ、ってなるじゃないですか。こっちじゃねーっすよと。
しかしながらですよ。定義ジャンプする時によしなにしてくれればいいんだけど、それはなかなか難しそうな気がするんですねきっと。
というわけで、xxx.g.dart
とxxx.dart
というファイルを交互に開けるようなキーマップを追加しましたという話になるわけです。
Vimスクリプトのコード
シンプルに関数一個でdart
でしか使わないので、以下のようなファイルを~/.vim/ftplugin/dart.vim
に突っ込んで使ってます。キーマッピングはga
とかやってますけど、お好みにあわせて変更してください。
if exists("b:dart_ftplugin") | finish | endif
let b:dart_ftplugin = 1
command! -buffer -nargs=? SwitchPart call <SID>SwitchPartFile()
nnoremap <buffer> <silent> ga :cal<SID>SwitchPartFile()<cr>
if exists('*s:SwitchPartFile') | finish | endif
function! s:SwitchPartFile()
let current_file = expand('%')
let target_file = substitute(current_file, '\v(\.g)?\.dart$', '.g.dart', '')
if target_file == current_file
let target_file = substitute(current_file, '\v(\.g)?\.dart$', '.dart', '')
endif
if filereadable(target_file)
exe 'e '.fnameescape(target_file)
else
echoh ErrorMsg | echo 'Target file not readable.' | echoh None
endif
endfunction
まだ使い込んでいるわけじゃないんで便利かよくわからないんですけども、同じように困っている方の助けになれば。
Discussion