28.2 Текущий буфер

В целом, в сеансе Emacs может быть много буферов. В любой момент времени один из них обозначается как текущий буфер — буфер, в котором происходит большая часть редактирования. Большинство примитивов для просмотра или изменения текста работают неявно с текущим буфером (см. Текст).

Обычно буфер, отображаемый в выбранном окне (см. Выбор окон), является текущим буфером, но это не всегда так: программа на Lisp может временно обозначить любой буфер как текущий, чтобы работать с его содержимым, не меняя то, что отображается на экране. Самая базовая функция для обозначения текущего буфера — это set-buffer.

Функция: current-buffer

Эта функция возвращает текущий буфер.

(current-buffer)
     ⇒ #<buffer buffers.texi>
Функция: set-buffer buffer-or-name

Эта функция делает buffer-or-name текущим буфером. buffer-or-name должен быть существующим буфером или именем существующего буфера. Значение возвращаемое — это сделанный текущим буфер.

Эта функция не отображает буфер в каком-либо окне, поэтому пользователь не обязательно может увидеть буфер. Но программы на Lisp теперь будут работать с ним.

Когда команда редактирования возвращается в цикл команд редактора, Emacs автоматически вызывает set-buffer для буфера, отображаемого в выбранном окне (см. Выбор окон). Это делается для предотвращения путаницы: это гарантирует, что буфер, в котором находится курсор, когда Emacs считывает команду, является буфером, к которому применяется эта команда (см. Цикл команд). Таким образом, вы не должны использовать set-buffer для видимого переключения на другой буфер; для этого используйте функции, описанные в Переключение на буфер в окне.

При написании функции на Lisp не полагайтесь на это поведение цикла команд для восстановления текущего буфера после операции. Команды редактирования также могут вызываться как функции Lisp другими программами, а не только из цикла команд; это удобно для вызывающей стороны, если подпрограмма не меняет, какой буфер является текущим (если, конечно, это не цель подпрограммы).

Чтобы временно работать с другим буфером, поместите set-buffer внутрь формы save-current-buffer. Вот, например, упрощенная версия команды append-to-buffer:

(defun append-to-buffer (buffer start end)
  "Добавить текст области в BUFFER."
  (interactive "BДобавить в буфер: \nr")
  (let ((oldbuf (current-buffer)))
    (save-current-buffer
      (set-buffer (get-buffer-create buffer))
      (insert-buffer-substring oldbuf start end))))

Здесь мы привязываем локальную переменную для записи текущего буфера, а затем save-current-buffer организует его повторное назначение текущим позже. Далее, set-buffer делает указанный буфер текущим, а insert-buffer-substring копирует строку из исходного буфера в указанный (и теперь текущий) буфер.

Альтернативно, мы можем использовать макрос with-current-buffer:

(defun append-to-buffer (buffer start end)
  "Добавить текст области в BUFFER."
  (interactive "BДобавить в буфер: \nr")
  (let ((oldbuf (current-buffer)))
    (with-current-buffer (get-buffer-create buffer)
      (insert-buffer-substring oldbuf start end))))

В любом случае, если буфер, к которому добавляется текст, отображается в каком-либо окне, следующее повторное отображение покажет, как изменился его текст. Если он не отображается ни в одном окне, вы не увидите изменения немедленно на экране. Команда заставляет буфер временно стать текущим, но не заставляет его отображаться.

Если вы делаете локальные привязки (с помощью let или аргументов функции) для переменной, которая также может иметь буфер-локальные привязки, убедитесь, что тот же буфер является текущим в начале и в конце области действия локальной привязки. В противном случае вы можете привязать его в одном буфере и отвязать в другом!

Не полагайтесь на использование set-buffer для возврата к текущему буферу, потому что это не сработает, если произойдет выход, пока неверный буфер является текущим. Например, в предыдущем примере было бы неправильно делать это:

  (let ((oldbuf (current-buffer)))
    (set-buffer (get-buffer-create buffer))
    (insert-buffer-substring oldbuf start end)
    (set-buffer oldbuf))

Использование save-current-buffer или with-current-buffer, как мы сделали, корректно обрабатывает выход, ошибки и throw, а также обычную оценку.

Специальная форма: save-current-buffer body…

Специальная форма save-current-buffer сохраняет идентификатор текущего буфера, оценивает формы body и, наконец, восстанавливает этот буфер как текущий. Значение возвращаемое — это значение последней формы в body. Текущий буфер восстанавливается даже в случае аномального выхода через throw или ошибку (см. Нелокальные выходы).

Если буфер, который был текущим, был уничтожен к моменту выхода из save-current-buffer, то, конечно, он не будет восстановлен как текущий. Вместо этого остается текущим тот буфер, который был текущим непосредственно перед выходом.

Макрос: with-current-buffer buffer-or-name body…

Макрос with-current-buffer сохраняет идентификатор текущего буфера, делает buffer-or-name текущим, оценивает формы body и, наконец, восстанавливает текущий буфер. buffer-or-name должен указывать на существующий буфер или имя существующего буфера.

Значение возвращаемое — это значение последней формы в body. Текущий буфер восстанавливается даже в случае аномального выхода через throw или ошибку (см. Нелокальные выходы).

Макрос: with-temp-buffer body…

Макрос with-temp-buffer оценивает формы body с временным буфером в качестве текущего буфера. Он сохраняет идентификатор текущего буфера, создает временный буфер и делает его текущим, оценивает формы body и, наконец, восстанавливает предыдущий текущий буфер, уничтожая временный буфер.

По умолчанию информация об отмене (см. Отмена) не записывается во временный буфер, созданный этим макросом (но body может это включить, если потребуется). Временный буфер также не выполняет хуки kill-buffer-hook, kill-buffer-query-functions (см. Уничтожение буферов) и buffer-list-update-hook (см. Список буферов).

Значение возвращаемое — это значение последней формы в body. Вы можете вернуть содержимое временного буфера, используя (buffer-string) в качестве последней формы.

Текущий буфер восстанавливается даже в случае аномального выхода через throw или ошибку (см. Нелокальные выходы).

См. также with-temp-file в Запись в файлы.