Выход
Ввод C-g во время выполнения функции Lisp вызывает выход Emacs из выполняемого действия. Это означает, что управление возвращается к самому внутреннему активному циклу команд.
Ввод C-g в то время как цикл команд ожидает ввода с клавиатуры не вызывает выход; он действует как обычный входной символ. В простейшем случае различия нет, так как C-g обычно выполняет команду keyboard-quit, действие которой — выход. Однако, когда C-g следует за префиксной клавишей, они объединяются, образуя неопределённую клавишу. Эффект заключается в отмене префиксной клавиши и любого префиксного аргумента.
В минибуфере C-g имеет другое определение: он прерывает работу минибуфера. Это означает, что он выходит из минибуфера, а затем выходит (просто выход вернёт управление в цикл команд *внутри* минибуфера). Причина, по которой C-g не вызывает прямой выход, когда читатель команд считывает ввод, заключается в том, что его значение можно переопределить в минибуфере таким образом. C-g, следующий за префиксной клавишей, не переопределяется в минибуфере и имеет свой обычный эффект отмены префиксной клавиши и префиксного аргумента. Это также было бы невозможно, если бы C-g всегда вызывал прямой выход.
Когда C-g вызывает прямой выход, он делает это, установив переменную quit-flag в значение t. Emacs проверяет эту переменную в соответствующие моменты и выходит, если она не равна nil. Установка значения quit-flag в отличное от nil приводит к выходу.
На уровне кода C выход не может происходить где угодно; только в специальных местах, которые проверяют quit-flag. Причина в том, что выход в других местах может привести к несогласованности внутреннего состояния Emacs. Поскольку выход отложен до безопасного места, он не может привести к сбою Emacs.
Некоторые функции, такие как read-key-sequence или read-quoted-char, полностью предотвращают выход, даже если они ожидают ввода. Вместо выхода C-g служит запрошенным вводом. В случае read-key-sequence это приводит к особому поведению C-g в цикле команд. В случае read-quoted-char это позволяет использовать C-q для цитирования C-g.
Вы можете предотвратить выход в части функции Lisp, присвоив переменной inhibit-quit значение, отличное от nil. Затем, хотя C-g всё ещё устанавливает quit-flag в t, как обычно, обычный результат этого — выход — предотвращается. В конечном итоге inhibit-quit вернётся к значению nil, например, при размотке привязки в конце формы let. В это время, если quit-flag всё ещё отлично от nil, запрашиваемый выход происходит немедленно. Это поведение идеально подходит, когда необходимо убедиться, что выход не произойдёт внутри критической секции программы.
В некоторых функциях (например, read-quoted-char) C-g обрабатывается особым способом, не связанным с выходом. Это делается путём чтения ввода с привязанным к нему inhibit-quit и значением t, и установкой quit-flag в nil до того, как inhibit-quit вернётся к значению nil снова. Этот фрагмент определения read-quoted-char демонстрирует, как это делается; он также показывает, что нормальный выход разрешён после первого символа ввода.
(defun read-quoted-char (&optional prompt)
"…documentation…"
(let ((message-log-max nil) done (first t) (code 0) char)
(while (not done)
(let ((inhibit-quit first)
…)
(and prompt (message "%s-" prompt))
(setq char (read-event))
(if inhibit-quit (setq quit-flag nil)))
…set the variable code…)
code))
- Переменная: quit-flag
Если эта переменная имеет значение, отличное от
nil, то Emacs выходит немедленно, еслиinhibit-quitимеет значение, отличное отnil. Ввод C-g обычно устанавливаетquit-flagв значение, отличное отnil, независимо отinhibit-quit.
- Переменная: inhibit-quit
Эта переменная определяет, должен ли Emacs выходить, когда
quit-flagустановлено в значение, отличное отnil. Еслиinhibit-quitимеет значение, отличное отnil, тоquit-flagне имеет специального эффекта.
- Макрос: with-local-quit тело…
-
Этот макрос последовательно выполняет формы тело, но позволяет выходу, по крайней мере локально, внутри тело, даже если
inhibit-quitимело значение, отличное отnilза пределами этого конструкта. Он возвращает значение последней формы в тело, если не произошло выхода из-за выхода, в противном случае он возвращаетnil.Если
inhibit-quitравноnilпри входе вwith-local-quit, он выполняет только тело, а установкаquit-flagвызывает обычный выход. Однако, еслиinhibit-quitимеет значение, отличное отnil, так что обычный выход задерживается, отличное отnilзначениеquit-flagвызывает специальный вид локального выхода. Это завершает выполнение тело и выходит из телаwith-local-quitсquit-flagвсё ещё имеющим значение, отличное отnil, так что другой (обычный) выход произойдёт, как только это будет разрешено. Еслиquit-flagуже имеет значение, отличное отnilв начале тело, локальный выход происходит немедленно, и тело не выполняется вообще.Этот макрос в основном полезен в функциях, которые могут вызываться из таймеров, фильтров процессов, сторожей процессов,
pre-command-hook,post-command-hookи других местах, гдеinhibit-quitобычно привязан к значениюt.
- Команда: keyboard-quit
Эта функция сигнализирует условие
quitс значением(signal 'quit nil). Это то же самое, что и выход. (См.signalв Ошибка.)
Чтобы выйти без прерывания определения или выполнения макроса клавиатуры, можно сигнализировать условие minibuffer-quit. Это почти тот же эффект, что и условие quit, за исключением того, что обработка ошибок в цикле команд обрабатывает его без выхода из определения или выполнения макроса клавиатуры.
Можно указать другой символ, кроме C-g, для выхода. См. функцию set-input-mode в Режимах ввода.
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Quitting.html