26.2 Сохранение буферов

Когда вы редактируете файл в Emacs, вы фактически работаете с буфером, который посещает этот файл, — то есть содержимое файла копируется в буфер, и вы редактируете именно эту копию. Изменения в буфере не влияют на файл, пока вы не сохраните буфер, что означает копирование содержимого буфера в файл. Буферы, которые не посещают файл, также можно «сохранять» в некотором смысле, используя функции в буферно-локальном хуке write-contents-functions.

Команда: save-buffer &optional backup-option

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

save-buffer отвечает за создание резервных копий. Обычно backup-option равен nil, и save-buffer создаёт резервную копию, только если это первое сохранение после посещения файла. Другие значения backup-option требуют создания резервных копий в иных обстоятельствах:

  • С аргументом 4 или 64, что соответствует одному или трём C-u, функция save-buffer помечает эту версию файла как подлежащую резервному копированию при следующем сохранении буфера.
  • С аргументом 16 или 64, что соответствует двум или трём C-u, функция save-buffer безусловно создаёт резервную копию предыдущей версии файла перед его сохранением.
  • С аргументом 0 безусловно не создавать никакой резервной копии.
Команда: save-some-buffers &optional save-silently-p pred

Эта команда сохраняет некоторые изменённые буферы, посещающие файлы. Обычно она спрашивает пользователя о каждом буфере. Но если save-silently-p не равен nil, она сохраняет все буферы, посещающие файлы, без опроса пользователя.

Необязательный аргумент pred задаёт предикат, который определяет, какие буферы следует спрашивать (или сохранять молча, если save-silently-p не равен nil). Если pred равен nil, это означает использование значения save-some-buffers-default-predicate вместо pred. Если результат равен nil, это означает опрос только буферов, посещающих файлы. Если результат равен t, это означает предложение сохранить также некоторые другие не-файловые буферы — те, у которых буферно-локальное значение buffer-offer-save не равно nil (см. Уничтожение буферов). Пользователь, согласившийся на сохранение не-файлового буфера, должен будет указать имя файла для сохранения. Функция save-buffers-kill-emacs передаёт значение t для pred.

Если предикат не равен ни t, ни nil, то это должна быть функция без аргументов. Она будет вызвана в каждом буфере, чтобы определить, предлагать ли сохранение этого буфера. Если она возвращает значение, не равное nil, в некотором буфере, это означает, что сохранение этого буфера следует предложить.

Команда: write-file filename &optional confirm

Эта функция записывает текущий буфер в файл filename, делает буфер посещающим этот файл и помечает его как не изменённый. Затем она переименовывает буфер на основе filename, добавляя строку наподобие «<2>», если это необходимо для создания уникального имени буфера. Основную часть работы она выполняет, вызывая set-visited-file-name (см. Имя файла буфера) и save-buffer.

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

Если filename является именем каталога (см. Имена каталогов), write-file использует имя посещаемого файла в каталоге filename. Если буфер не посещает файл, вместо этого используется имя буфера.

Сохранение буфера вызывает несколько хуков. Оно также выполняет преобразование форматов (см. Преобразование форматов файлов). Обратите внимание, что эти хуки, описанные ниже, вызываются только функцией save-buffer, они не вызываются другими примитивами и функциями, которые записывают текст буфера в файлы, и в частности автосохранение (см. Автосохранение) не вызывает эти хуки.

Переменная: write-file-functions

Значение этой переменной — список функций, вызываемых перед записью буфера в его посещаемый файл. Если одна из них возвращает значение, не равное nil, считается, что файл уже записан, и остальные функции не вызываются, а обычный код записи файла не выполняется.

Если функция в write-file-functions возвращает значение, не равное nil, она отвечает за создание резервной копии (если это уместно). Для этого выполните следующий код:

(or buffer-backed-up (backup-buffer))

Возможно, вы захотите сохранить значение режима файла, возвращаемое backup-buffer, и использовать его (если оно не равно nil) для установки битов режима записываемого файла. Именно это обычно делает save-buffer. См. Создание резервных файлов.

Функции хука в write-file-functions также отвечают за кодирование данных (если требуется): они должны выбрать подходящую кодировку и преобразование концов строк (см. Системы кодирования в Lisp), выполнить кодирование (см. Явное кодирование и декодирование) и установить last-coding-system-used в использованную систему кодирования (см. Кодирование и ввод-вывод).

Если вы устанавливаете этот хук локально в буфере, предполагается, что он связан с файлом или способом получения содержимого буфера. Таким образом, переменная помечается как постоянная локальная, чтобы смена основного режима не изменяла буферно-локальное значение. С другой стороны, вызов set-visited-file-name сбросит его. Если это не то, что вам нужно, возможно, вы захотите использовать write-contents-functions вместо него.

Хотя это не обычный хук, вы можете использовать add-hook и remove-hook для управления списком. См. Хуки.

Переменная: write-contents-functions

Работает так же, как write-file-functions, но предназначена для хуков, относящихся к содержимому буфера, а не к конкретному посещаемому файлу или его расположению, и может использоваться для создания произвольных процессов сохранения для буферов, которые вообще не посещают файлы. Такие хуки обычно настраиваются основными режимами как буферно-локальные привязки для этой переменной. Эта переменная автоматически становится буферно-локальной при установке; переключение на новый основной режим всегда сбрасывает эту переменную, но вызов set-visited-file-name не делает этого.

Если любая из функций в этом хуке возвращает значение, не равное nil, считается, что файл уже записан, остальные функции не вызываются и функции из write-file-functions также не вызываются.

При использовании этого хука для сохранения буферов, не посещающих файлы (например, буферов специальных режимов), имейте в виду, что если функция не сможет сохранить правильно и вернёт значение nil, save-buffer продолжит запрашивать у пользователя файл для сохранения буфера. Если это нежелательно, рассмотрите возможность завершения функции с ошибкой.

Пользовательская опция: before-save-hook

Этот обычный хук запускается перед сохранением буфера в его посещаемом файле, независимо от того, выполняется ли это обычным способом или одним из хуков, описанных выше. Например, программа copyright.el использует этот хук, чтобы убедиться, что сохраняемый файл содержит текущий год в уведомлении об авторских правах.

Пользовательская опция: after-save-hook

Этот обычный хук запускается после сохранения буфера в его посещаемом файле.

Пользовательская опция: file-precious-flag

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

Побочным эффектом является то, что резервные копии обязательно создаются копированием. См. Резервное копирование переименованием или копированием?. В то же время сохранение ценного файла всегда разрывает все жёсткие связи между сохраняемым файлом и другими именами файлов.

Некоторые режимы присваивают этой переменной значение, не равное nil, в качестве буферно-локального значения в определённых буферах.

Пользовательская опция: require-final-newline

Эта переменная определяет, могут ли файлы записываться без завершающей перевода строки. Если значение переменной равно t, то save-buffer молча добавляет перевод строки в конце буфера, если его там нет. Если значение равно visit, Emacs добавляет недостающий перевод строки сразу после посещения файла. Если значение равно visit-save, Emacs добавляет недостающий перевод строки как при посещении, так и при сохранении. Для любого другого значения, не равного nil, save-buffer спрашивает пользователя, нужно ли добавлять перевод строки каждый раз, когда возникает такая ситуация.

Если значение переменной равно nil, то save-buffer вообще не добавляет переводов строк. Значение nil используется по умолчанию, но некоторые основные режимы устанавливают его в t в определённых буферах.

См. также функцию set-visited-file-name (см. Имя файла буфера).