これは 日本情報クリエイト Engineer's Advent Calendar 2017 の6日目の記事です。
はじめに
私はvimのライトユーザーですが、少し前に unite.vim から denite.nvim 乗り換えました。
使っているプラグインもそれほど多くなく、移行自体は簡単にできましたがまだまだunite.vimに比べてプラグインが少ない気がします。。。
そんなdenite.nvimのプラグインの中にgitを操作する denite-git というプラグインがあります。
unite.vimにも同系統のプラグインがあり、とても重宝していたので早速入れてみました。
(denite.nvimおよびdenite-gitのインストール方法については割愛します)
branch操作をdeniteで!
とても便利に使っていたdenite-gitですが一つ気になることが・・・
それは、branchの操作が行えないことです。
uniteで生活していたときには、このブランチ操作をとても重宝しておりましたのでどうしても欲しい!!
というわけで、branch操作を行えるように機能を追加してみました。
sourceの追加
今回始めてdeniteのプラグインに手を出してみたのですが、sourceの追加は驚くほど簡単!
./rplugin/python3/denite/source/
以下にファイルを一つ作ってその中にSource
とKind
というクラスを作るだけ。1
Source
にはdeniteのウィンドウに表示させる内容を表示させるための処理を(この場合はブランチの一覧)、Kind
には表示された内容に対する処理をそれぞれ記述します。
ブランチの一覧を取得するコードはこんな感じです。
class Source(BaseSource):
def __init__(self, vim):
super().__init__(vim)
self.name = 'gitbranch'
self.kind = Kind(vim)
def on_init(self, context):
cwd = os.path.normpath(self.vim.eval('expand("%:p:h")'))
context['__root'] = _find_root(cwd)
def gather_candidates(self, context):
root = context['__root']
if not root:
return []
args = ['git', 'branch', '--no-color', '-a']
candidates = []
try:
p = subprocess.run(commands, cwd=root, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lines = p.stdout.decode(encoding).split('\n')
except subprocess.CalledProcessError:
lines = []
for line in lines:
if not line:
continue
path = os.path.join(root, line[3:])
current_symbol = line[0]
candidates.append({
'word': line,
'action__path': line[2:],
'source__root': root,
'source__current': current_symbol == '*',
'source__remote': line[2:10] == 'remotes/',
})
return candidates
...
gather_candidates
というメソッド内にbranchの一覧を返す処理を記述するだけです。
kindの追加
さて、コレでブランチの一覧を表示することができるようになったので、後はブランチに対する操作をKindに記述するだけです。
Kind
クラスにaction_hoge
というメソッドを生やせばそれだけでhogeというアクションが追加されるので実行したい操作の種類だけaction_*
というメソッドを追加していけばいいですね。
...
class Kind(BaseKind):
def __init__(self, vim):
super().__init__(vim)
self.persist_actions += ['open', 'delete'] # pylint: disable=E1101
self.redraw_actions += ['open', 'delete'] # pylint: disable=E1101
self.name = 'gitbranch'
self.default_action = 'open'
def action_open(self, context):
target = context['targets'][0]
args = ['git', 'checkout']
root = target['source__root']
path = target['action__path']
if target['source__remote'] : path = path[8:]
args.append(path)
run_command(args, root)
def action_delete(self, context):
target = context['targets'][0]
args = []
root = target['source__root']
path = target['action__path']
force = util.input(self.vim, context, 'Force delete? [y/n] : ', 'n') == 'y'
if target['source__remote']:
if force == True:
args ['git', 'push', 'origin', ':' + target['action__path'][8:]]
else:
args = ['git', 'branch', '-D' if force == True else '-d', target['action__path']]
if len(args) > 0 : run_command(args, root)
def action_merge(self, context):
target = context['targets'][0]
args = ['git', 'merge', target['action__path']]
root = target['source__root']
if target['source__remote'] == False and target['source__current'] == False:
run_command(args, root)
ここではopen(checkout)、delete、mergeの3つのアクションを追加しました。2
選択した業の情報はcontext['targets']
に入りますのでこの中から必要な情報を取得して実行したい操作を行います。
まとめ
機能追加という形ですが少しだけ触ってみたところ、とても簡単に書けてしまいました。
みなさんも色々なプラグインを作ってvimライフを充実させましょう!!