cockscomblog?

cockscomb on hatena blog

Sublime Text で Perl のテスト実行するプラグイン作った

作った。 https://github.com/cockscomb/SublimeProve

Sublime Text 3 の開発版ずっと使ってるから Sublime Text 2 無視して書いた。Python 3 使えて便利。

Perl でテスト実行するやつで、コマンドパレットから prove method とか選ぶとカーソル位置のメソッドをテストする。パッケージ名とテストファイルの対応とかは適当にやってるから、汎用性が低い。Perl 書いてる人いないと思うし汎用的じゃないから Package Control に登録する予定はない。

プラグイン書くのに付随して生まれたふつうに便利なパーツを共有します。ここはたぶん Sublime Text 2 でも動く。

プロジェクトの root を得る

import sublime, sublime_plugin
import os.path

class GetProjectRootCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        print(self.get_project_root())

    def get_project_root(self):
        """/any/paths/.git seems repository's root directory"""
        filename = self.view.file_name()
        if not filename:
            return None

        dir = os.path.dirname(filename)
        while True:
            dot_git = os.path.join(dir, '.git')
            if os.path.exists(dot_git) and os.path.isdir(dot_git):
                return dir
            dir = os.path.abspath(os.path.join(dir, os.path.pardir))
            if os.path.dirname(dir) == dir: # System root
                return None

プロジェクトは git でバージョン管理されているだろうから .git があるところがプロジェクトの root ディレクトリだろうとすると、こういう感じ。

カーソル位置のクラスやメソッドを推定する

import sublime, sublime_plugin

class CurrentClassCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        current_region = self.view.sel()[0]
        current_class = self.get_region_name_by_selector(current_region, 'entity.name.type.class')
        # current_function = self.get_region_name_by_selector(current_region, 'entity.name.function')
        print(current_class)

    def get_region_name_by_selector(self, region, selector):
        """get name matching the selector lie directly on current cursor position
        Examples:
            'entity.name.type.class' for the class name,
            'entity.name.function' for the function name"""
        name_regions = self.view.find_by_selector(selector)

        name = None
        for name_region in name_regions:
            line = self.view.line(name_region)
            if region.b < line.a:
                break
            name = self.view.substr(name_region)

        return name

viewfind_by_selector っていうのを使うと、セレクターに合う region を配列で返してくれる。カーソル位置の直前のクラス定義やメソッド定義がカーソル位置のクラスやメソッドだということにすると、だいたい分かる。セレクターは entity.name.type.class とか entity.name.function みたいな感じ。シンタックスハイライトするのに使われてる感じのやつ。viewscope_name メソッドを使って探した。

本当は現在のスコープみたいなのから分かったらいいけど、そこまではできない(と思う)。インデントの情報を使えば精度を上げられるかもしれないけど、今回はこれくらいでもだいたいよさそうだった。

雑感

Emacs 使いたい気持ちもあるし全く使えないわけじゃない(つもり)けど、いろいろいい感じに設定するの面倒過ぎてできてない。いろいろ設定するのすごい苦手で、Mac も iPhone もなるべくデフォルトで使ってる。情弱だから設定できない。

Sublime Text はあんまり設定しなくてもそれなりに使えるし、適当に Python 書いたらプラグインできるから情弱でも使える。Apple 信者だからプロプライエタリへの抵抗感はない。

エンジニアだいたい Emacs とか Vim 使うから、Sublime Text 使ってると設定ファイルコピペしたりできない。諦めて暇なときに自分でプラグインとか作ってる。Python 書くと盛り上がってくるから楽しい。