Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Як написати плагін до gedit

with 2 comments

Директорія

Плагіни до gedit розміщуються в двох місцях:

  • /usr/lib/gedit-2/plugins/ – для всієї системи
  • ~/.gnome2/gedit/plugins/ – для конкретного користувача.

Вибираємо другий варіант. Директорію plugins в нашому випадку треба створити.

Файл інформації

Тепер в нашій директорії треба створити файл: sample.gedit-plugin. (sample – назва нашого плагіну). Що плагін буде робити – придумаємо по дорозі. Його вміст:

 
  [Gedit Plugin]
  Loader=python
  Module=sample
  IAge=2
  Name=Sample
  Description=A Python plugin example
  Authors= Bunyk T.O. <tbunyk@gmail.com>
  Copyright= Public domain
  Website=https://bunyk.wordpress.com/

  • Два перші рядки кажуть що це пайтонівський плагін до ґедіта.
  • Module – файл плагіна (без розширення py). Також можна задати не файл, а каталог, в якому має бути файл __init__.py
  • IAge – версія плагіна, і в інструкції писало що має бути завжди 2
  • Name – ім’я що буде показане в списку плагінів
  • Description – аналогічно
  • Три останні рядки – інформація про автора та плагін.

Файл з кодом

Тепер треба створити файл з кодом плагіна. (sample.py, як ми вказали в полі Module). Його вміст:

 
  import gedit
  
  class SamplePlugin(gedit.Plugin):
      def activate(self, window):
          print "Sample plugin activated"
  
      def deactivate(self, window):
          print "Sample plugin deactivated" 
  
      def update_ui(self, window):
          print "Sample plugin updates ui"

Зберігаємо файли, і перезапускаємо gedit. Заходимо в Edit -> Preferences -> Plugins і шукаємо в списку наш. Ура!

Якщо перезапускати gedit в терміналі, і потім закрити його, то ми побачимо, що він друкує такі повідомлення:

 
  Sample plugin activated
  Sample plugin updates ui
  Sample plugin updates ui
  Sample plugin updates ui
  Sample plugin deactivated

Клас плагіна наслідується від базового класу gedit.Plugin, який описує такі методи (які можна перевантажити):

  • activate(self, gedit.Window)
  • deactivate(self, gedit.Window)
  • update_ui(self, gedit.Window)

Gedit – програма що завжди працює в одному екземплярі. При запуску він перевіряє чи не існує вже запущеного екземпляру програми, і якщо так, то передає контроль йому. Тому створюється тільки один екземпляр плагіна (при запуску основної програми). Але плагіни зазвичай відповідають вікнам. Для цього й створені функції activate та deactivate, які викликаються відповідно при створенні та знищенні вікна.

Функція update_ui викликається коли плагіну варто перевірити, чи не пора обновити стан інтерфейсу.

Зазвичай, при створенні вікна, створюють новий екземпляр плагіну, який прив’язують до цього вікна. Так кожне вікно має свій плагін. Але так казали в офіційній документації, а в Расселла Бітті була краща ідея, яку я і використаю.

Пункт в меню

Тепер давайте зробимо пункт в меню, при натискуванні на який, в вікні з’являється традиційний привітальний напис.

Документація трохи недописана, але є класний плагін – python console, в якому можна інтерактивно виконувати команди. Щоб дізнатись які методи має документ, відкриваємо нову вкладку, консоль, і пишемо:

 
  doc=window.get_active_document()
  doc.set_text("\n".join(dir(doc)))

В вікні редагування з’являється список методів документа. Це звісно не документація, але вже хоч щось… Не розумію, як в такій класній програмі докстрінги можуть бути відсутніми? Може це тому що вона написана на C?

Так я вияснив наприклад, що щоб взяти увесь текст документа треба зробити так:

 
  text = doc.get_text(doc.get_start_iter(),doc.get_end_iter())

Потім можна з цим текстом попрацювати, і повернути назад, функцією doc.set_text()

Інтерфес gedit, як “щирої” гномської програми написаний на gtk. На жаль, gtk, я все ще не знаю, тому просто використаю готовий скрипт Рассела Бітті [4], трохи його підправивши. Хоча, щоб підправити, треба таки розібратись. При активації програма створює таку собі групу дій (ActionGroup).

Щоб створити групу дій, використовують конструктор

 
  gtk.ActionGroup(name)

де name – унікальне ім’я групи.

Потім в цю групу додають дії.

 
  actiongroup.add_actions(entries, user_data=None)

Де entries – це список кортежів такого формату:

  • Ім’я дії. Має бути таке саме як значення атрибута action в тезі menuitem що знаходиться в menu_str (перевірено експериментально).
  • Ідентифікатор дії. Необов’язковий (може мати значення None), якщо задана мітка.
  • Мітка дії. Буде відображатись в меню, як назва. Необов’язкова якщо заданий ідентифікатор.
  • Акселератор дії, в форматі який розуміє функція gtk.accelerator_parse(). Необов’язковий (можна писати None).
  • Спливаюча підказка дії. Теж необов’язкова.
  • Функція яка запускається, при активації дії. Теж може заміщуватись None, хоча тоді не ясно, а нащо взагалі дію?

В user_data Рассел передавав об’єкт window, і мені лінь перевіряти, що буде якщо передати туди щось інше.

Далі група дій передається менеджеру інтерфейсу.

 
  manager = window.get_ui_manager()
  manager.insert_action_group(self._action_group, -1)

Метод insert_action_group() додає об’єкт класу gtk.ActionGroup в список груп. Другий параметр означає позицію в яку додають. Якщо вона від’ємна – додають в кінець. Дії груп що ближче до початку списку приховують дії груп що ближче до кінця, якщо в них однакові імена.

Ну, і нарешті сама програма:

 
  #!coding: utf-8
  import gedit
  import gtk
  
  menu_str = """
  <ui>
    <menubar name="MenuBar">
      <menu name="EditMenu" action="Edit">
        <placeholder name="EditOps_3">
          <separator name="SampleSep1"/>
          <menuitem name="Sample" action="Sample"/>
        </placeholder>
      </menu>
    </menubar>
  </ui>
  """
  
  class SamplePlugin(gedit.Plugin):
    def __init__(self):
      gedit.Plugin.__init__(self)
  
    def hello(self, action, window):
      doc  = window.get_active_document()
      doc.begin_user_action()
      doc.insert_at_cursor("Привіт, світе!")
      doc.end_user_action()
  
    def activate(self, window):
      actions = [
        ('Sample', None, 'Привітатись', '<Shift><Control>h', "Додати привітання", self.hello)
      ]
  
      self._action_group = gtk.ActionGroup("SampleActions")
      self._action_group.add_actions(actions, window)
      manager = window.get_ui_manager()
      manager.insert_action_group(self._action_group, -1)
      self._ui_id = manager.add_ui_from_string(menu_str)
     
    def deactivate(self, window):
      manager = window.get_ui_manager()
      manager.remove_ui(self._ui_id)
      manager.remove_action_group(self._action_group)
      self._action_group = None
      self._ui_id = None

Тепер є пункт в меню Edit -> Привітатись, який вставляє в документ фразу “Привіт, світе!”, і відповідна комбінація клавіш Ctrl+Shift+H. Справа зроблена. Залишилось ще трохи порозбиратись з GTK, і вияснити як додати до плагіна діалогове вікно, і розібратись з модулем subprocess щоб вияснити, як з коду Python взаємодіяти по трубах з всякими grep, man, і іншими програмами, що спілкуються текстом.

Посилання

  1. Офіційна інструкція на gnome.org
  2. Расселл Бітті, про те, як він написав плагін що вставляє дату.
  3. Інструкція PyGTK про ActionGroups
  4. Скрипт Рассела Бітті
Advertisements

Written by bunyk

Листопад 12, 2010 at 17:44

Оприлюднено в Інструменти, Кодерство

Tagged with ,

Відповідей: 2

Subscribe to comments with RSS.

  1. Понравилось, что ты выяснил всякие фишки)
    вспомнил вот это: http://kino-matrix.ru/glava%204/index2.htm (там про эксперименты)

    jtimv

    Листопад 12, 2010 at 21:53

    • Ну, виясняти – напевне в цьому і полягає наукова робота 🙂 Так і напишу в своїй курсовій “в даній роботі з’ясовано …”

      І дякую за посилання. Цікава книжка.

      bunyk

      Листопад 12, 2010 at 22:11


Залишити відповідь

Заповніть поля нижче або авторизуйтесь клікнувши по іконці

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: