пятница, 5 декабря 2008 г.

Магические файлы

Расскажу про одну особенность в SXEmacs — find-file-magic-files-alist.

Всегда есть специальные файлы, которые не нужно открывать как текстовые, а нужно его специальным образом обработать и отобразить какую-нибудь информацию. К таким файлам относятся, например, директории. Я сомневаюсь, что вы хотели бы при выполнении команды C-x C-f /tmp RET увидеть бинарное содержимое файла /tmp (напомню, что директории это такие же файлы как и все остальные). Вы наверняка хотели бы, чтобы запустился dired над этой директорией и вы увидели бы её содержимое. В GNU Emacs и XEmacs это сделано явно, то есть при открытие файла (вызове find-file-noselect, а остальное семейство find-file-функций использует эту) происходит проверка, является ли файл директорией и если да, то запускается dired.

Этот подход очень ограниченный, так как не только директории могут быть магическими файлами. Поэтому в SXEmacs была введена новая переменная — find-file-magic-files-alist. Это обычный alist (список пар), в котором голова пары это предикат получающий имя файла и возвращающий non-nil в случае если файл магический, а хвост пары это одноарная функция, получающая имя файла (про который уже известно, что он магический) и обязательно возвращающая какой-нибудь буфер, в котором содержится интерпретация этого магического файла.

По умолчанию в find-file-magic-files-alist всего одна пара — (file-directory-p . find-file-try-dired-noselect). Как вы догадались это для работы dired.

Мы уже знаем про мощный инструмент работы с изображениями — Wand-mode. Хотелось бы сделать так, что если какой-нибудь файл может быть открыт с помощью Wand-display, то и использовать его для таких файлов. Скажем, что файлы с изображениями — магические и воспользуемся переменной find-file-magic-files-alist:

(push '(Wand-file-supported-for-read-p . Wand-display-noselect)
      find-file-magic-files-alist) 

или и того проще:

(Wand-find-file-enable) 

теперь если мы откроем файл с картинкой с помощью C-x C-f (или любой другой командой find-file-семейства), то у нас запуститься Wand-mode.

Заметим, что предикаты в find-file-magic-files-alist должны быть очень точными. Если вдруг какой-нибудь предикат вернёт non-nil для немагического файла - это приведёт к проблемам. На счастье в SXEmacs есть команда-функция magic:file-type, которая воспользуется прелестями libmagic и вернёт вероятный тип файла. Наверняка вы знаете программу file(1), которая использует libmagic.

Ещё один пример магический файлов. Это файлы с базами SQLite. Я уж точно не хочу открыв, с помощью C-x C-f, файл с базой увидеть её бинарное содержимое. Заместо хотелось бы, что бы запустилась программа sqlite, натравленная на этот файл, и я бы мог давать всякие команды, SQLные ли запросы или всякие .tables и т.д. Напишем пару функций - предикат и открывалку:

(defun lg-sqlite-file-p (filename)
  "Return non-nil if FILENAME is actually SQLite format 3 file."
  (with-temp-buffer
    (insert-file-contents-literally filename nil 0 15)
    (string= (buffer-substring) "SQLite format 3")))

(defun lg-sqlite-find-file (file)
  (require 'sql)
  (setq sql-database file)
  (funcall (sql-product-feature :sqli-connect 'sqlite))
  (setq sql-interactive-product 'sqlite)
  (setq sql-buffer (current-buffer))
  (sql-interactive-mode)
  (rename-buffer (format "*SQL:%s*" (file-name-nondirectory file)))
  (current-buffer)) 

Если у вас есть рабочий ffi-sqlite, то можете воспользоваться уже готовым предикатом - sqlite-file-p. Теперь добавим элемент в find-file-magic-files-alist:

(push '(lg-sqlite-file-p . lg-sqlite-find-file)
      find-file-magic-files-alist)

Всё, теперь можно открывать файлы с базами SQLiteC-x C-f ~/test.db RET.

Аналогичным образом можно сделать, например, чтобы запускался gdb-with-core с правильными аргументами при открытии core файлов.

Вообще, Емаксу необходим более продвинутый механизм автоматического определения, что делать с файлом на замену давно устаревшего auto-mode-alist. find-file-magic-files-alist может стать неплохим началом в создании такого механизма.

ReST source Скачать оригинал

Комментариев нет: