L'Isola di Niente
L'Isola di Niente » Gedit Tips » Gedit プラグインの作り方(v3.10 以前)

Gedit プラグインの作り方(v3.10 以前)

このページは Gedit 3.10 以前の解説です。

準備

プラグインは C か Python でしか作れません、ココでは Python のみを解説します。
Version 3.6 までが Python2、3.8 と 3.10 が Python3 です。

公式 HowTo Apps/Gedit/PythonPluginHowTo - GNOME Wiki!
は 2015 年 2 月現在 3.10 以前のままなので有効です。

*.plugin
*.py

の最低 2 つのファイルが必要、Python コードはもちろん分割してもよい。

*.plugin

下記の要領で testtest.plugin という名前にして保存しておきます。
[Plugin]
Loader=python3
Module=testtest
IAge=3
Name=testtest
Name[ja]=テストテスト
Description=plugin test
Description[ja]=プラグインのテスト
Authors=sasakima-nao <sasakimanao@gmail.com>
Copyright=Copyright © 2015 sasakima-nao <sasakimanao@gmail.com>
Website=http://palepoli.skr.jp/

キー
Loader3.6 以前で使う場合は python
Module読み込む Python スクリプトから拡張子を除いた名前
IAge3(固定)
NameGedit の設定でプラグインタブを開いた時に表示される名前
DescriptionGedit の設定でプラグインタブを開いた時に表示される説明
***[ja]各国ごとに翻訳
見ての通り

v2 との違い
- 拡張子が gedit-plugin から plugin
- セクション名が [Plugin]
- IAge が 3
- v3.8 以降は Python3

*.py

上記 Module で指定した testtest.py スクリプトを作成します。
v2 とは全然違っているので注意。

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

from gi.repository import GObject, Gedit, Gtk

class TestPligin(GObject.Object, Gedit.WindowActivatable):
    __gtype_name__ = "TestPligin"
    window = GObject.property(type=Gedit.Window)
    def __init__(self):
        GObject.Object.__init__(self)
        self.messagebox("init")

    def do_activate(self):
        self.messagebox("activate")

    def do_deactivate(self):
        self.messagebox("deactivate")

    def do_update_state(self):
        #self.messagebox("update")
        pass

    def messagebox(self, text):
        dlg = Gtk.MessageDialog(
                self.window,
                Gtk.DialogFlags.MODAL,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.OK,
                text)
        dlg.set_title("テスト")  
        dlg.run()  
        dlg.destroy()

直接実行ではないので先頭の #!/usr/bin/env python3 は不要です。
もちろん __main__ もいりません、クラスとメソッドのみを記述する。
3.8 以降は Python3 であることを意識してください。
utf-8 指定は Python3 では不要ですが 3.6 以前互換用に。

多重継承の敬称元を3つから選ぶ。
Gedit.AppActivatable
Gedit.WindowActivatable
Gedit.ViewActivatable
普通なら Gedit.WindowActivatable でいい、意味はなんとなく解るはず。

__gtype_name__ は class 名と同じにしなければいけない。
Gedit の Window オブジェクトは上記のように取得する。

__init__(self) は Python お約束の初期化を。

この messagebox はなんじゃ?と思うでしょうが動作を理解しやすいように入れてみた。

配置

作成した2つのファイルは以下のディレクトリを作成し配置、これで準備は完了。

~/.local/share/gedit/plugins

このスクリプトを Gedit で書いた場合は Gedit を再起動しないと指定できません。
起動時にプラグインディレクトリをスキャンするようなので間違えないように。

試してみる


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

img/testtest3_1.png

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

gi による動的処理なので v2 時とは違い init は有効にする毎に反応します。
init では self.window は None として処理されるので親ウインドウ無しダイアログになる。
ということで v3 では再起動せずともプラグインコードの書き換えが可能になったようです。

do_update_state() がどうなるかはコメントアウトを外して試してください。
インターフェイスに変更があると敏感に反応するようで鬼のように反応しますから注意。

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

コードを書いてみる

本家サイトではインターフェイス部分の分離を勧めていますが、理解が早いように直書きします。
というか、私自身が直書きでしか作っていないが特に問題は無いので。

ココでは私が公開している html_escape プラグインをそのまま載せてみる。
<>& をエンティティーに変換、私的に Web ページ手書き時には欠かせないプラグイン。
下記のようなコード貼り付けで変換したい場合に利用します。

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

#    Gedit html_escape plugin version 3.0.1
#    Copyright © 2011-2013 sasakima-nao <sasakimanao@gmail.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.

from gi.repository import GObject, Gedit, Gtk

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

class HtmlEscapePlugin(GObject.Object, Gedit.WindowActivatable):
    __gtype_name__ = "HtmlEscapePlugin"
    window = GObject.property(type=Gedit.Window)
    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        # Get GtkUIManager
        manager = self.window.get_ui_manager()
        # Create GtkActionGroup
        self._action_group = Gtk.ActionGroup("EscHtmlPluginActions")
        # GtkActionEntry(name, stock_id, label, accelerator, tooltip, callback)
        actions = [("EscHtml", None, "HTML エスケイプ", "<Control><Shift>E", "<>& をエンティティーに変換", self.on_esc_html_activate)]
        # Add GtkActionGroup
        self._action_group.add_actions(actions)
        # Insert GtkUIManager
        manager.insert_action_group(self._action_group, -1)
        self._ui_id = manager.add_ui_from_string(ui_str)
        
    def do_deactivate(self):
        manager = self.window.get_ui_manager()
        manager.remove_ui(self._ui_id)
        manager.remove_action_group(self._action_group)
        manager.ensure_update()
        

    def do_update_state(self):
        self._action_group.set_sensitive(self.window.get_active_document() != None)
    
    def on_esc_html_activate(self, action, data=None):
        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)
        result = ""
        for s in text:
            if s == "<":
                s = "&lt;"
            elif s == ">":
                s = "&gt;"
            elif s == "&":
                s = "&amp;"
            result += s
        buf.delete_selection(True, True)
        buf.insert_at_cursor(result)

    def messagebox(self, text):
        dlg = Gtk.MessageDialog(
                self.window,  
                Gtk.DialogFlags.MODAL,  
                Gtk.MessageType.WARNING, 
                Gtk.ButtonsType.OK,  
                text)  
        r = dlg.run()  
        dlg.destroy()

上から順番に解説。
ui_str の XML はメニューに追記する定義です。
FileMenu, ToolsMenu 等にも入れることができる、細かくは Gedit のソースコードで調べてね。
EditOps_3 はポップアップの何段目かを指定、数値部分を変更すれば解ります。
ココを指定せずに menuitem を入れると一番下に入るようです。
menuitem name と action は GtkActionEntry を作る時に利用するので独自名で。

__init__ は Python お約束。
この時点では self.window は None ですので注意。

do_activate でロードされた時に上記で指定したメニューを Gedit 本体に挿入。
do_deactivate で挿入したメニューを削除。
パネルを自作して本体に挿入や削除をする場合もこのハンドラで行います。
def do_activate(self):
    # etc...
    bottom = self.window.get_bottom_panel()
    bottom.add_item(self.outputpanel, "Test", "Test", image)

def do_deactivate(self):
    # etc...
    bottom = self.window.get_bottom_panel()
    bottom.remove_item(self.outputpanel)
この作業は Gtk+ そのものなので Gtk+ のヘルプで。

GtkActionEntry の最後で callback 指定がありますのでハンドラを作成する。
後は self.window をから辿って Gedit の個々部品にアクセスして処理を行っていく。
この self.window は HowTo ページの下のほうに書かれているメソッドが用意されています。

このメソッドを利用して様々な処理を行えばプラグインの完成です。
シグナルを利用したい場合も上記のようにコネクトすれば利用できます。
これ以上は Gtk+ の解説になるのでコードの解説はここまで。

Gedit 及び Eye of Gnome プラグインページに置いています。
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.