LoginSignup
5
2

More than 5 years have passed since last update.

denite-gitを改造してみる

Last updated at Posted at 2017-12-05

これは 日本情報クリエイト 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/ 以下にファイルを一つ作ってその中にSourceKindというクラスを作るだけ。1

Sourceにはdeniteのウィンドウに表示させる内容を表示させるための処理を(この場合はブランチの一覧)、Kindには表示された内容に対する処理をそれぞれ記述します。

ブランチの一覧を取得するコードはこんな感じです。

gitbranch.py
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_*というメソッドを追加していけばいいですね。

gitbranch.py
...

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)deletemergeの3つのアクションを追加しました。2
選択した業の情報はcontext['targets']に入りますのでこの中から必要な情報を取得して実行したい操作を行います。

まとめ

機能追加という形ですが少しだけ触ってみたところ、とても簡単に書けてしまいました。
みなさんも色々なプラグインを作ってvimライフを充実させましょう!!


  1. sourceとkindをファイルで分割する場合はそれぞれ./rplugin/python3/denite/source/./rplugin/python3/denite/kind以下にファイルを作って分割しましょう。 

  2. run_commandは外部コマンドを実行する関数でSource.gather_candidates()内で行っていることとほとんど同じす。 

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2