Как найти, какой файл предоставляет (d) функцию в emacs elisp - PullRequest
6 голосов
/ 08 марта 2012

В настоящее время я использую переменную load-history , чтобы найти файл, из которого появилась функция.

предположим, чтобы найти файл, к которому пришла функция gnus from.

Я выполняю следующий код в чистом буфере, который последовательно печатает имя файла и символы в отдельных строках.

(dolist (var load-history)
  (princ (format "%s\n" (car var)))
  (princ (format "\t%s\n" (cdr var))))

, а затем выполняет поиск «(обеспечить. gnus)» и затем перемещаетсяточка в начале строки (Ctrl + A).Имя файла в предыдущей строке - это файл, из которого была получена функция.

Что-то не так с этим методом или существует лучший метод.

Ответы [ 4 ]

8 голосов
/ 08 марта 2012

Я действительно не знаю, что вы пытаетесь сделать с этим, но вот несколько заметок.

  • Ваш метод в порядке. В моей книге хорош любой способ взломать собственное решение проблемы.

  • @ Том прав, что вам не нужно этого делать, потому что проблема уже решена для вас системой помощи. т.е. C-h f

Но это не так интересно. Допустим, вы действительно хотите автоматическое, более элегантное решение. Вы хотите функцию - locate-feature с этой подписью:

(defun locate-feature (feature)
  "Return file-name as string where `feature' was provided"
  ...)

Метод 1 load-history подход

Я просто опишу шаги, которые я предпринял, чтобы решить эту проблему:

  1. У вас уже есть самая важная часть - найдите переменную с необходимой вам информацией.

  2. Я сразу замечаю, что в этой переменной много данных. Если я вставлю его в буфер одной строкой, Emacs будет недоволен, потому что он плохо работает с длинными строками. Я знаю, что пакет prett-print сможет красиво отформатировать эти данные. Поэтому я открываю свой *scratch* буфер и запускаю

    M-: (вставить (история загрузки pp-в-строку))

  3. Теперь я вижу структуру данных, с которой я имею дело. Вроде бы (в псевдокоде):

    ((file-name
      ((defun|t|provide . symbol)|symbol)*)
     ...)
    
  4. Теперь я просто пишу функцию

    (eval-when-compile (require 'cl))
    (defun locate-feature (feature)
      "Return file name as string where `feature' was provided"
      (interactive "Sfeature: ")
      (dolist (file-info load-history)
        (mapc (lambda (element)
                (when (and (consp element)
                           (eq (car element) 'provide)
                           (eq (cdr element) feature))
                  (when (called-interactively-p 'any)
                    (message "%s defined in %s" feature (car file-info)))
                  (return (car file-info))))
              (cdr file-info))))
    

    Код здесь довольно прост. Спросите Emacs о функциях, которые вы не понимаете.

Способ 2, помощь, подход

Метод первый работает для функций. Но что, если я хочу знать, где-нибудь Доступная функция определена? Не только особенности.

C-h f уже говорит мне об этом, но я хочу, чтобы имя файла в строке, а не весь подробный текст справки. Я хочу это:

(defun locate-function (func)
  "Return file-name as string where `func' was defined or will be autoloaded"
  ...)

Вот и мы.

  1. C-h f - моя отправная точка, но я действительно хочу прочитать код, который определяет describe-function. Я делаю это:

    C-h k C-h f C-x o вкладка введите

  2. Теперь я нахожусь в help-fns.el по определению describe-function. Я хочу работать только с этим определением функции. Итак, сужение по порядку:

    C-x n d

  3. У меня есть догадка, что интересная команда будет иметь в своем названии "find" или "locate", поэтому я использую occur для поиска интересных строк:

    M-s o найти \ | найти

    Нет совпадений. Хммм. Не много строк в этом defun. describe-function-1, кажется, делает настоящую работу, поэтому мы попробуем это.

  4. Я могу посетить определение describe-function-1 через C-h f . Но у меня уже есть файл открыт. imenu доступно сейчас:

    C-x n w M-x имя desc * 1 вкладка введите

  5. Сузить и искать снова:

    C-x n d M-s o up enter

    Я вижу find-lisp-object-file-name, что выглядит многообещающе.

  6. После прочтения C-hf find-lisp-object-file-name Я придумываю:

    (defun locate-function (func)
      "Return file-name as string where `func' was defined or will be autoloaded"
      (interactive "Ccommand: ")
      (let ((res (find-lisp-object-file-name func (symbol-function func))))
        (when (called-interactively-p 'any)
          (message "%s defined in %s" func res))
        res))
    

А теперь иди повеселись, изучая Emacs.

4 голосов
/ 03 января 2015

Просто используйте symbol-file.Он сканирует load-history, который имеет формат:

Each entry has the form `(provide . FEATURE)',
`(require . FEATURE)', `(defun . FUNCTION)', `(autoload . SYMBOL)',
`(defface . SYMBOL)', or `(t . SYMBOL)'.  Entries like `(t . SYMBOL)'
may precede a `(defun . FUNCTION)' entry, and means that SYMBOL was an
autoload before this file redefined it as a function.  In addition,
entries may also be single symbols, which means that SYMBOL was
defined by `defvar' or `defconst'.

Так назовите его как:

(symbol-file 'scheme 'provide)        ; Who provide feature.
(symbol-file 'nxml-mode-hook 'defvar) ; Where variable defined.
(symbol-file 'message-send 'defun)    ; Where function defined.
(symbol-file 'scheme)    ; Look for symbol despite its type.
2 голосов
/ 08 марта 2012

Для этого есть locate-library.

Попробуйте ... М -: (locate-library "my-feature")

Например: (locate-library "gnus")

1 голос
/ 08 марта 2012

В этом нет ничего плохого, но почему это проще, чем получить справку по клавише или функции?Если вы, например, используете команду gnus и хотите знать, откуда она берется, вы можете использовать C-h k, и она сообщает вам, из какого файла elisp пришло его определение.

...