L'Isola di Niente
L'Isola di Niente » Gedit Tips » Gedit プラグインの作り方(v2)

Gedit プラグインの作り方(v2)

このページは Gedit 2 (GNOME2) 及び Windows 版の解説です。

2013.11.03 公式 URL 変更及び Windows 版用追記による変更

本家の解説ページ

公式 HowTo # 注意、URL が変更になっています
Apps/Gedit/PythonPluginHowToOld - GNOME Wiki!

プラグインは C か Python2 でしか作れません、ココでは Python のみを解説します。
Python3 は利用できません、GUI は PyGtk を利用して作成していきます。
PyGTK 2.0 Reference Manual

とにかく gedit.Plugin のサブクラスを作ってしまえばいい。
そしてそのコードを参照する INI ファイルを作って gedit-plugin と拡張子を付ける。
インスタンス化は勝手に Gedit が行うので __main__ 関数は不要。

実験

Plugin に命名したい名前を決めておいて gedit-plugin という拡張子の INI ファイルを作ります。

[Gedit Plugin]
Loader=python
Module=testtest
IAge=2
Name=testtest
Name[ja]=テストテスト
Description=plugin test
Description[ja]=プラグインのテスト
Authors=sasakima-nao <m6579ne998z@gmail.com>
Copyright=Copyright © 2009 sasakima-nao <m6579ne998z@gmail.com>
Website=http://palepoli.skr.jp/


Loader は Python で書くならこう書く。
Module は読み込む Python スクリプトから拡張子を除いた名前を指定。
IAge は現在の Gedit のメジャーバージョンなので 2 でオケ。
Name は Gedit の設定でプラグインタブを開いた時に表示される名前
Description は Gedit の設定でプラグインタブを開いた時に表示される説明

以下は解説の必要は無いですよね。
Name と Description は [ja] を付加すると日本語版用の表示が可能です。
とりあえずコレで testtest.gedit-plugin という名前にして保存しておきます。

次に Module で指定される testtest.py スクリプトを作成します。

#-*- coding:utf-8 -*-

import gedit
import gtk

class TestTest(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)
        self.messagebox("init")

    def activate(self, window):
        self.messagebox("activate")

    def deactivate(self, window):
        self.messagebox("deactivate")

    def update_ui(self, window):
        self.messagebox("ui")
    
    def messagebox(self, text):
        dlg = gtk.MessageDialog(None,  
                                gtk.DIALOG_MODAL,  
                                gtk.MESSAGE_WARNING, 
                                gtk.BUTTONS_OK,  
                                text)  
        r = dlg.run()  
        dlg.destroy()


直接実行ではないので先頭の #!/usr/bin/env python は不要です。
日本語をコメントに入れる場合は先頭に utf-8 指定を忘れずに。

gedit.Plugin.__init__(self) はお約束なのでこのまま書くだけ。
この messagebox はなんじゃ?と思うでしょうが動作を理解しやすいように入れてみた。
そして作成した2つのファイルを以下のディレクトリに配置、これで準備は完了。
# Linux
~/.gnome2/gedit/plugins
# Windows
%PROGRAMFILES(X86)%\gedit\lib\gedit-2\plugins
このスクリプトを Gedit で書いた場合は Gedit を再起動しないと指定できません。
起動時にプラグインディレクトリをスキャンするようなので間違えないように。

試してみる


再起動すると設定のプラグインタブに「テストテスト」がある。

img/setting1.png

チェックを入れたり外したりして有効無効を試してみましょう。
有効にすると init と activate のダイアログが出ました。
しかし init は最初にチェックを入れた時以外は反応しません。
deactivate は無効にすると反応しますね。

次に他のファイルを開いたり一旦終了したり保存したりしてみます。
山ほど ui が反応します、インターフェイスに変更があると敏感に反応するようで。
うっとうしいのでテストが終わったら pass に書き換えておいてね。

と、上記の activate なんかは Gedit が吐くシグナルのハンドラだと理解できました。
このハンドラを利用して初期化処理なんかを行います。

Windows 版

gedit
上記に gedit win32 binary というインストール EXE のリンクから落とせます。
GTK2, GConf, Python2, PyGtk 等の構成部品はすべてライブラリとして同梱されています。
ので別途で Python 等を用意することなく利用できます。

ただし、いくつかの標準プラグインは UNIX 依存なので使えないようです。
又 Python 等はライブラリなので Gedit をインストールしても Gedit 以外からは使えません。
同梱されている Python は 2.6 です、2.7 以降に追加された関数は使えません。
つまり自分で Python3 を導入してもプラグインは Python 2.6 で作る必要がある。

コードを書いてみる

本家サイトではインターフェイス部分の分離を勧めていますが、理解が早いように直書きします。

需要がありそうなものを作りたいので
「選択範囲の行の先頭全部に引用マーク > を付ける」
なんてのがよさそうなのでやってみる。

#-*- coding:utf-8 -*-

import gedit
import gtk

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu name="EditMenu" action="Edit">
            <placeholder name="EditOps_3">
                <menuitem name="testtest" action="testtest"/>
            </placeholder>
        </menu>
    </menubar>
</ui>
"""

class TestTest(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)

    def activate(self, window):
        self._window = window
        # GtkUIManager を得る
        manager = self._window.get_ui_manager()
        # GtkActionGroup を新規で作成
        self._action_group = gtk.ActionGroup("TestTestActions")
        # GtkActionEntry を作成
        # name, stock_id, label, accelerator, tooltip, callback
        actions = [("testtest", None, "引用に変換", None, "すてーたすばー", self.on_testtest_activate)]
        # GtkActionGroup に挿入
        self._action_group.add_actions(actions)
        # GtkUIManager に追加
        manager.insert_action_group(self._action_group, -1)
        self._ui_id = manager.add_ui_from_string(ui_str)
        
    def deactivate(self, window):
        manager = self._window.get_ui_manager()
        manager.remove_ui(self._ui_id)
        manager.remove_action_group(self._action_group)
        manager.ensure_update()
        

    def update_ui(self, window):
        pass
    
    def on_testtest_activate(self, action):
        view = self._window.get_active_view()
        buf = view.get_buffer()
        try:
            begin, end = buf.get_selection_bounds()
        except:
            self.messagebox("変換したいテキストを選択してください")
            return
        text = begin.get_text(end)
        lines = text.split("\n")
        result = ""
        for line in lines:
            result += "> %s\n" % line
        buf.delete_selection(True, True)
        # 一番最後に改行が入ってしまうので取っ払う
        buf.insert_at_cursor(result[:-1])
            
        
    def messagebox(self, text):
        dlg = gtk.MessageDialog(self._window,  
                                gtk.DIALOG_MODAL,  
                                gtk.MESSAGE_WARNING, 
                                gtk.BUTTONS_OK,  
                                text)  
        r = dlg.run()  
        dlg.destroy()


順番に解説。
ui_str の XML はメニューに追記する定義です。
menu name を EditMenu にすると「編集」、ToolsMenu にすると「ツール」に入る。
EditOps_3 はポップアップの何段目かを指定、数値部分を変更すれば解ります。
ココを指定せずに menuitem を入れると一番下に入るようです。
menuitem name と action は GtkActionEntry を作る時に利用するので独自名で。

__init__ は解説不要。
activate でロードされた時に上記で指定したメニューを Gedit に突っ込みます。
deactivate で突っ込んだメニューを削除という流れです。
この作業は Gtk+ そのものなので Gtk+ のヘルプでどうぞ(ぉい!

GtkActionEntry の最後で callback 指定がありますのでハンドラを作成する。
activate で保存しておいた self._window が Gedit の gedit.Window オブジェクトである。
このオブジェクトは HowTo ページの下のほうに書かれているメソッドが用意されています。

get_active_view() メソッドで現在の Gedit 上でアクティブなビューが取得できます。
このビューは GtkSourceView てか PyGtksourceview2 そのものである。

PyGtksourceview2 Reference Manual

又 GtkSourceView は GtkTextView のサブクラスなので GtkTextView のメソッドも使える。
ということで上記のソースはそのメソッドを使って選択範囲のテキストを加工する例である。
これ以上は Gtk+ の解説になるのでコードの解説はここまで。
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.