Выбрать главу

from Blender import Draw,Text,Registry

import bpy

import re

Для того, чтобы сигнализировать о любых ошибках, как например, ошибочное регулярное выражение, или о том, что не нашлось ни одного сопоставления, мы определяем простую функцию popup():

def popup(msg):

   Draw.PupMenu(msg+'%t|Ok')

   return

Поскольку мы хотим помнить последнее регулярное выражение, которое ввёл пользователь, мы используем реестр Блендера и, следовательно, мы определяем ключ для использования:

keyname = 'regex'

Функция run() связывает всю функциональность вместе; она извлекает активный текстовый буфер и завершается, если его не нашлось:

def run():

   txt = bpy.data.texts.active

   if not txt: return

Далее, она извлекает позицию курсора внутри этого буфера:

   row,col = txt.getCursorPos()

Прежде, чем показать пользователю всплывающее окно для ввода регулярного выражения, мы проверяем, есть ли уже сохраненное ранее выражение в реестре. Мы просто извлекаем его, и если это терпит неудачу, мы ставим выражением по-умолчанию пустую строку (выделено). Заметьте, что мы не передаем никаких дополнительных параметров в функцию GetKey(), поскольку мы хотим сохранить любую информацию на диск в этом случае. Если пользователь вводит пустую строку, мы просто делаем возврат без поиска:

   d=Registry.GetKey(keyname)

   try:

      default = d['regex']

   except:

      default = ''

   pattern = Draw.PupStrInput('Regex: ',default,40)

   if pattern == None or len(pattern) == 0 : return

Мы компилируем регулярное выражение, чтобы убедиться, что оно корректно, и если это терпит неудачу, мы показываем сообщение и выходим:

   try:

      po = re.compile(pattern)

   except:

      popup('Illegal expression')

      return

Теперь, когда мы уверены, что регулярное выражение - верное, мы проходим по всем строкам текстового буфера, начиная со строки, на которой находится курсор (выделено). С каждой строкой мы сопоставляем наше скомпилированное регулярное выражение (или с частью строки после курсора, если это первая строка).

   first = True

   for string in txt.asLines(row):

      if first :

         string = string[coclass="underline" ]

      mo = re.search(po,string)

Если есть сопоставление, мы отмечаем его начало в пределах строки и его длину (должным образом исправленную, если это строка первая) и устанавливаем позицию курсора на текущую строку и в начало сопоставления (выделено). Мы также устанавливаем "позицию выделения" в позицию сопоставления плюс длина сопоставления, таким образом наше сопоставление будет выделено, и затем делаем возврат. Если нет сопоставления в пределах строки, мы увеличиваем индекс строки row и продолжаем цикл.

Если ничего не остается для перебора, мы сигнализируем пользователю, что мы не нашли ни одного сопоставления. В любом случае, мы сохраняем регулярное выражение в реестре для использования заново:

      if mo != None :

         i = mo.start()

         l = mo.end()-i

         if first :

            i += col

         txt.setCursorPos(row,i)

         txt.setSelectPos(row,i+l)

         break

      row += 1

      first = False

   else :

      popup('No match')

   Registry.SetKey(keyname,{'regex':pattern})

if __name__ == '__main__':

   run()

Полный код доступен как regex.py в файле regex.blend, но может быть размещён в каталоге скриптов Блендер с подходящим именем, как например, textplugin_regex.py.

Расширение редактора - взаимодействие с Subversion

При активной разработке скриптов может оказаться сложно следить за изменениями или возвращаться к предыдущим версиям. Это не уникально для написания скриптов Питона в Блендере, поэтому системы управления версиями развиваются уже много лет. Одна из хорошо известных, и широко используемых - это Subversion (http://subversion.tigris.org). В этом разделе мы показываем, как может быть дополнен редактор, чтобы отправлять или обновлять текстовые файлы из хранилища.