Журнал LinuxFormat - перейти на главную

LXF97:GtkSourceView

Материал из Linuxformat
Перейти к: навигация, поиск

Движок текстового редактора

Если возможностей чистого GtkTextView для вашего приложения уже недостаточно или вы просто решили по-быстрому написать лучшую IDE всех времен и народов – начните с урока GtkSourceView от Петра Семилетова.

В состав библиотеки Gtk входит отличный виджет текстового редактора, воплощенный в виде взаимодополняющих классов GtkTextBuffer, GtkSourceView и ряда других, вспомогательных (мы писали про них в LXF93). Но ради универсальности этого виджета его разработчики пожертвовали некоторыми вещами. Например, нет встроенного механизма redo/undo, нет также подсветки синтаксиса различных языков программирования, хотя виджет обладает способностью задавать цвет и параметры шрифта при отображении отдельных участков текста.

Однако среди разрабочиков известного редактора GEdit вырос виджет-надстройка над GetTextView – и называется он GtkSourceView (http://gtksourceview.sourceforge.net). В нем есть все то, чего недостает в стандартном виджете: и движок redo/undo, и подсветка синтаксиса, и отображение правой границы – так называемого margin’а, и многое другое.

Сейчас развитие GtkSourceView стоит на пороге перехода на новую ветку – под номером два. Вторая версия еще считается нестабильной, а API ее не устоялось. В этой статье я постараюсь дать представление и о современной версии библиотеки, и о грядущей. Замечу также, что я предполагаю ваше умение работать с обычным GtkTextView. Как я упоминал, GtkSourceView – лишь надстройка над GtkTextView, поэтому работа с GtkSourceView подразумевает использование и «стандартных» функций из Gtk.

Чтобы создать новый виджет GtkSourceView, используется функция Gtk_source_view_new:

 GtkWidget *text_view = gtk_source_view_new ();

Классу буфера для GtkSourceView, вместо GtkTextBuffer, соответствует GtkSourceBuffer. Для его создания надо вызвать функцию gtk_source_buffer_new:

 GtkSourceBuffer *text_buffer = gtk_source_buffer_new (table);

В качестве параметра мы передаем этой функции экземпляр таблицы с определениями тэгов пользовательской подсветки (вне движка подсветки GtkSourceView). Напомню, что в текстовом движке Gtk, тэг – это объект, содержащий параметры форматирования текста, как то: шрифт, цвет и тому подобное.

Для движка GtkSourceView первой версии, таблица имеет тип GtkSourceTagTable. Во второй версии GtkSourceView надо использовать стандартный тип из GtkGtkTextTagTable. Можно передавать в параметре значение NULL. Тэги вам понадобятся, только если вы захотите неким образом размечать текст – например, подчеркивать слова с ошибками. Создание тэгов, помещение их в таблицу и последующее применение (тэги применяются в тексте к месту, ограниченному итераторами) – тема, выходящая за рамки данной статьи.

Для получения текста из GtkSourceBuffer и помещения его туда применяются те же функции, что и для GtkTextBuffergtk_text_buffer_get_text и gtk_text_buffer_set_text. Передавая экземпляр GtkSourceBuffer в качестве параметра, можете приводить его к типу (макросом GTK_TEXT_BUFFER), а можете не приводить – все равно передается указатель, а компилятор может выдавать предупреждения в зависимости от своих настроек. Однако ничего дурного не случится, если вы вместо:

  gchar *text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer));

напишете такое:

  gchar *text = gtk_text_buffer_get_text (buffer);

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

Итак, с текстовым содержимым GtkSourceBuffer мы разобрались. Теперь давайте применим к загруженному тексту подсветку синтаксиса – если таковая, конечно же, предусмотрена для конкретного языка движком: создания подсветки «пользовательского» языка мы касаться не будем. Используем готовые, «встроенные» модули подсветки – физически это XML-файлы, в которых заданы правила подсветки.

Само собой, виджет не догадывается по помещенному в него тексту, подсветку синтаксиса какого языка надо использовать. Эту процедуру необходимо запрограммировать Работать будем опять-таки с буфером.

В GtkSourceView 1:

  gtk_source_buffer_set_language (buffer, language);
  gtk_source_buffer_set_highlight (buffer, TRUE);

В GtkSourceView 2:

  gtk_source_buffer_set_language (buffer, language);
  gtk_source_buffer_set_highlight_syntax (buffer, TRUE);

Функция gtk_source_buffer_set_language устанавливает нужную подсветку (удаляя при этом все тэги типа GtkSourceTag из таблицы тэгов переданного буфера), а gtk_source_buffer_set_highlight (либо gtk_source_buffer_set_highlight_syntax) включает ее. А вот что такое переменная language в параметре первой функции? Определена она так:

  GtkSourceLanguage *language = NULL;

Каким образом связать переменную language с подсветкой файлов определенного типа? В первой версии GtkSourceView есть функция с очень длинным названием: gtk_source_languages_manager_get_language_from_mime_type. Она получает два параметра – указатель на менеджер языков и строку, задающую тип MIME (для загруженного файла).

Менеджер языков – это переменная типа GtkSourceLanguagesManagerGtkSourceView 1') и GtkSourceLanguageManagerGtkSourceView 2). В первом случае получаем экземпляр нужного класса с помощью функции gtk_source_languages_manager_new, во втором лучше использовать новое средство, функцию gtk_source_language_manager_get_default. Вручную уничтожать полученные объекты не нужно.

Итак, для получения механизма подсветки, соответствующего некоторому типу MIME, используется примерно следующее:

  language = gtk_source_languages_manager_get_language_from_mime_type (source_languages_manager, mime_string);

Однако тут возникают два вопроса. Как быть в GtkSourceView 2, где покамест нет функции, «отдающей» нам язык по переданному типу MIME? И как вообще получить MIME для файла?

На первый вопрос ответ очевиден – надо писать свою функцию. В каталоге tests исходных текстов GtkSourceView 2 есть образец – смотрите файл test-widget.c, функцию get_language_for_mime_type. Не самое удачное воплощение алгоритма, но оно работает, и вы будете иметь представление, куда двигаться дальше.

Теперь о типах MIME. Есть несколько библиотек, позволяющих работать с ними. Самый естественный способ для программы, основанной на Gtk – обратиться к библиотеке GnomeVFS (LXF94):

  GnomeVFSFileInfo *info = gnome_vfs_file_info_new ();
  GnomeVFSResult r = gnome_vfs_get_file_info (filename, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE);
  gchar *mime = gnome_vfs_file_info_get_mime_type (info);
  // тут что-то делаем со строкой mime, затем освобождаем память, выделенную под структуру info:
  gnome_vfs_file_info_unref (info);

Итого – в переменной mime, покуда память для info не освобождена, имеем значение, соответствующее типу MIME для файла, чье имя передано в переменной filename.

Не забудьте, что перед использованием функций GnomeVFS надо инициализировать эту библиотеку (gnome_vfs_init), а после завершения работы вызвать gnome_vfs_shutdown.

Итак, подсветка заработала. Что еще мы можем с ней сделать? Изменить цвета. В GtkSourceView 1 можно, с помощью довольно громоздкого кода, назначить параметры подсветки для каждого элемента каждого доступного языка, например, для строки в HTML или CSS. В GtkSourceView 2 появился более удобный способ изменения цветов – использование схем. Схема здесь – это, грубо говоря, предустановленный набор цветов. Во время написания этих строк, в составе GtkSourceView идет 3 схемы – classic, kate и tango. Как выбрать схему?

Сначала раздобудем список идентификаторов установленных в системе схем:

 GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default ();
 gchar **scheme_ids;
 g_object_get (manager, “scheme-ids”, &scheme_ids, NULL);
 GList *ids = NULL;
 gint c = g_strv_length (scheme_ids) - 1;
 gint i;
 for (i = 0; i <= c; i++)
   ids = g_list_prepend (ids, scheme_ids[i]);

Здесь мы получаем менеджер схем по умолчанию, а затем считываем из него свойство scheme-ids в массив scheme_ids. После чего, для удобства, перемещаем идентификаторы в список ids. Со списком GList удобнее работать, если у вас есть готовые функции для создания виджетов-меню или виджетов-списков на основе данных из GList. А массивы представляются мне чем-то старорежимным.

Далее, зная идентификаторы доступных схем, мы можем затребовать нужную схему по ее идентификатору:

 GtkSourceStyleScheme *scheme = gtk_source_style_scheme_manager_get_scheme (manager, cheme_id);

Осталось лишь назначить схему буферу GtkSourceBuffer:

 gtk_source_buffer_set_style_scheme (buffer, scheme);

Чем еще полезным нас может порадовать GtkSourceView2? Механизмом Undo/Redo. По умолчанию любое изменение текста в буфере подлежит отмене либо обратному действию. Если вам надо временно этот механизм отключить, используйте функции gtk_source_buffer_begin_not_undoable_action и gtk_source_buffer_end_not_undoable_action. Любые действия с текстом в буфере между их вызовами не будут включены в очередь отмены. Так, например, следует поступить при первой вставке текста из загруженного файла – иначе, когда пользователь будет применять отмену, он рано или поздно дойдет до пустого документа.

Для программного вызова отмены и отмены отмены (redo, как вы догадались) нам даны функции gtk_source_buffer_undo и gtk_source_buffer_redo. Можно также проверить, доступны ли эти операции, и установить наибольшую длину очереди движка замен – указать, сколько в ней может быть элементов.

Кроме того, движок GtkSourceView предоставляет много функций, полезных разработчикам редакторов для программистов. Это управление автоматическим отступом и параметрами табуляции, отображение номеров строк слева от текста, работа с маркерами (полезно для показа каких-нибудь закладок) и многое другое.

Обе версии GtkSourceView – первую и вторую – можно установить одновременно, они не мешают одна другой. Если вы пишете программу с использованием GtkSourceView, то стоит подумать над поддержкой обеих версий, ведь в старых дистрибутивах (да и в стабильной ветке Debian) вторая версия появится не скоро.

Проверить наличие установленной библиотеки и включить ее в параметры сборки можно разными способами. Приведенный ниже код (предназначенный для размещения в configure.in) проверяет, установлены ли в системы библиотеки GtkSourceView2 и GnomeVFS 2. Если да, то они добавляются к параметрам сборки, а в файле config.h будет определена константа gtksourceview2_SUPPORTED, проверяя которую, мы сможем узнать, есть поддержка GtkSourceView2 или нет:

  echo -n “checking for GtkSourceView2... “
  if pkg-config --exists gtksourceview-2.0 ; then
            LIBS=”$LIBS `pkg-config --libs gtksourceview-2.0 `”
            CFLAGS=”$CFLAGS `pkg-config --cflags gtksourceview-2.0 `”
            AC_DEFINE(GTKSOURCEVIEW2_SUPPORTED, 1, [GTKSOURCEVIEW2_SUPPORTED])
            echo “yes”
            echo -n “checking for gnome-vfs-2.0... “
            if pkg-config --exists gnome-vfs-2.0 ; then
                          LIBS=”$LIBS `pkg-config --libs gnome-vfs-2.0`”
                          CFLAGS=”$CFLAGS `pkg-config --cflags gnome-vfs-2.0`”
                          echo “yes”
            else
                          echo “no”
            fi
  else
            echo “no”
  fi

Сходным способом можно проверить и наличие GtkSourceView 1.

Все это касается стандартной системы сборки/установки с помощью Autotools – Scons, CMake и прочие настраиваются аналогично (с поправкой на синтаксис, разумеется). Для удобной работы с пользовательской настройкой подсветки в первой версии GtkSourceView вам еще понадобится библиотека GConf, чтобы держать настройки цветов в хранилище. Все подробности можно найти в исходных текстах GEdit или TEA. LXF

Персональные инструменты
купить
подписаться
Яндекс.Метрика