Каждый буфер имеет специальный маркер, который обозначается как метка. Когда буфер только создан, этот маркер существует, но не указывает никуда; это означает, что метка в этом буфере пока отсутствует. Последующие команды могут установить метку.
Метка задаёт позицию, ограничивающую диапазон текста для многих команд,
таких как kill-region и indent-rigidly. Эти команды
обычно действуют на текст между точкой и меткой, который называется
областью. Если вы пишете команду, которая работает с областью,
не обращайтесь к метке напрямую; вместо этого используйте
interactive со спецификацией ‘r’. Это предоставляет значения
точки и метки как аргументы команде при интерактивном вызове, но позволяет
другим программам на Лиспе задавать аргументы явно. См. Символьные коды для interactive.
Некоторые команды устанавливают метку как побочный эффект. Команды должны
делать это только в том случае, если это может быть полезно пользователю,
и никогда для своих внутренних целей. Например, команда replace-regexp
устанавливает метку в значение точки перед выполнением замен,
потому что это позволяет пользователю удобно вернуться туда после завершения замены.
После того как метка появилась в буфере, она обычно никогда не перестаёт
существовать. Однако она может стать неактивной, если включён режим
Transient Mark. Локальная переменная буфера mark-active, если она
не nil, означает, что метка активна. Команда может вызвать функцию
deactivate-mark для непосредственной деактивации метки или может
запросить деактивацию метки по возврату в цикл команд редактора, установив
переменную deactivate-mark в значение, не равное nil.
Если режим Transient Mark включён, некоторые команды редактирования, которые обычно применяются к тексту возле точки, вместо этого применяются к области, когда метка активна. Это основная причина использования режима Transient Mark. (Другая причина — это возможность подсветки области, когда метка активна. См. Отображение в Emacs.)
В дополнение к метке каждый буфер имеет кольцо меток, которое представляет
собой список маркеров, содержащих предыдущие значения метки. Когда команды
редактирования изменяют метку, они должны обычно сохранять старое значение метки
в кольце меток. Переменная mark-ring-max задаёт максимальное количество
записей в кольце меток; как только список достигает этой длины, добавление
нового элемента удаляет последний элемент.
Существует также отдельное глобальное кольцо меток, но оно используется только в нескольких конкретных пользовательских командах и не имеет отношения к программированию на Лиспе. Поэтому мы не описываем его здесь.
Эта функция возвращает позицию метки текущего буфера в виде целого числа
или nil, если в этом буфере никогда не была установлена метка.
Если режим Transient Mark включён и mark-even-if-inactive равен
nil, то mark сигнализирует об ошибке, если метка неактивна.
Однако если force не равен nil, то mark игнорирует
неактивность метки и в любом случае возвращает позицию метки (или nil).
Эта функция возвращает маркер, представляющий метку текущего буфера. Это не копия, а маркер, используемый внутренне. Следовательно, изменение позиции этого маркера напрямую повлияет на метку буфера. Не делайте этого, если только вы не хотите именно такого эффекта.
(setq m (mark-marker))
⇒ #<marker at 3420 in markers.texi>
(set-marker m 100)
⇒ #<marker at 100 in markers.texi>
(mark-marker)
⇒ #<marker at 100 in markers.texi>
Как и любой маркер, этот маркер можно установить на любой буфер по вашему желанию. Если вы заставите его указывать на любой буфер, отличный от того, меткой которого он является, это даст полностью согласованные, но довольно странные результаты. Мы рекомендуем вам не делать этого!
Эта функция устанавливает метку в позицию position и активирует метку. Старое значение метки не помещается в кольцо меток.
Обратите внимание: Используйте эту функцию, только если вы хотите,
чтобы пользователь видел, что метка переместилась, и вы хотите, чтобы
предыдущая позиция метки была потеряна. Обычно, когда устанавливается новая
метка, старая должна помещаться в mark-ring. По этой причине
большинство приложений должны использовать push-mark и
pop-mark, а не set-mark.
Начинающие программисты на Emacs Lisp часто пытаются использовать метку не по назначению. Метка сохраняет позицию для удобства пользователя. Команда редактирования не должна изменять метку, если только изменение метки не является частью пользовательской функциональности команды. (И в этом случае этот эффект должен быть задокументирован.) Чтобы запомнить позицию для внутреннего использования в программе на Лиспе, сохраните её в переменной Лиспа. Например:
(let ((beg (point))) (forward-line 1) (delete-region beg (point))).
Эта функция устанавливает метку текущего буфера в позицию position и
помещает копию предыдущей метки в mark-ring. Если
position равен nil, то используется значение точки.
Функция push-mark обычно не активирует метку.
Чтобы сделать это, укажите t для аргумента activate.
Сообщение ‘Mark set’ отображается, если только nomsg не равен
nil.
Эта функция извлекает верхний элемент из mark-ring и делает
эту метку фактической меткой буфера. Это не перемещает точку в
буфере и ничего не делает, если mark-ring пуст. Она
деактивирует метку.
Эта переменная, если она не равна nil, включает режим Transient Mark.
В режиме Transient Mark каждый примитив, изменяющий буфер, устанавливает
deactivate-mark. Как следствие, большинство команд, изменяющих
буфер, также деактивируют метку.
Когда режим Transient Mark включён и метка активна, многие команды,
которые обычно применяются к тексту возле точки, вместо этого применяются к
области. Такие команды должны использовать функцию use-region-p,
чтобы проверить, должны ли они работать с областью. См. Область.
Программы на Лиспе могут устанавливать transient-mark-mode в значения,
отличные от nil и t, чтобы временно включить режим Transient Mark.
Если значение равно lambda, режим Transient Mark автоматически
выключается после любого действия, такого как изменение буфера, которое
обычно деактивировало бы метку. Если значение равно (only . oldval),
то transient-mark-mode устанавливается в значение oldval после
любой последующей команды, которая перемещает точку и не является
сдвигово-транслируемой (см. сдвиговая трансляция), или после любого другого
действия, которое обычно деактивировало бы метку. (Выделение области
мышью временно включает transient-mark-mode таким образом.)
Если эта переменная не равна nil, программы на Лиспе и пользователь
Emacs могут использовать метку даже тогда, когда она неактивна. Эта опция
влияет на поведение режима Transient Mark. Когда опция не равна nil,
деактивация метки отключает подсветку области, но команды, использующие
метку, ведут себя так, как будто метка всё ещё активна.
Если команда редактора устанавливает эту переменную в значение, не равное
nil, то цикл команд редактора деактивирует метку после возврата
команды (если включён режим Transient Mark). Все примитивы, изменяющие
буфер, устанавливают deactivate-mark, чтобы деактивировать метку,
когда команда завершена. Установка этой переменной делает её локальной для буфера.
Чтобы написать код на Лиспе, который изменяет буфер, но не вызывает
деактивацию метки по завершении команды, привяжите
deactivate-mark к nil вокруг кода, выполняющего
изменение. Например:
(let (deactivate-mark) (insert " "))
Если режим Transient Mark включён или force не равен nil,
эта функция деактивирует метку и выполняет нормальный хук
deactivate-mark-hook. В противном случае она ничего не делает.
Метка активна, когда эта переменная не равна nil. Эта
переменная всегда локальна для буфера в каждом буфере. Не используйте
значение этой переменной, чтобы решить, должна ли команда, которая обычно
работает с текстом возле точки, работать с областью вместо этого. Используйте
для этого функцию use-region-p (см. Область).
Эти нормальные хуки выполняются соответственно, когда метка становится активной
и когда она становится неактивной. Хук activate-mark-hook
также выполняется, когда область реактивируется, например, после использования
команды, которая переключается обратно в буфер с активной меткой.
Эта функция реализует поведение выделения сдвигом для команд
перемещения точки. См. Выделение сдвигом в Руководстве GNU Emacs.
Она вызывается автоматически циклом команд Emacs всякий раз, когда
команда с символом ‘^’ в своей спецификации interactive
вызывается перед выполнением самой команды
(см. ^).
Если shift-select-mode не равен nil и текущая команда
была вызвана через сдвиговую трансляцию (см. сдвиговая трансляция), эта функция устанавливает метку и временно
активирует область, если только область не была уже временно активирована
таким образом. В противном случае, если область была временно активирована,
она деактивирует метку и восстанавливает переменную
transient-mark-mode к её предыдущему значению.
Значение этой локальной для буфера переменной является списком сохранённых предыдущих меток текущего буфера, сначала самые последние.
mark-ring
⇒ (#<marker at 11050 in markers.texi>
#<marker at 10832 in markers.texi>
…)
Значение этой переменной является максимальным размером mark-ring. Если
в mark-ring помещается больше меток, чем это значение,
push-mark отбрасывает старую метку, когда добавляет новую.
Когда включён режим Delete Selection (см. Delete Selection в Руководстве GNU Emacs), команды, работающие с
активной областью (она же “выделение”), ведут себя несколько иначе.
Это работает путём добавления функции delete-selection-pre-hook в
pre-command-hook (см. Обзор цикла команд). Эта функция
вызывает delete-selection-helper для удаления выделения в
соответствии с командой. Если вы хотите адаптировать команду для режима
Delete Selection, поместите свойство delete-selection на
символ функции (см. Доступ к свойствам символов); команды, у которых нет
этого свойства на своём символе, не будут удалять выделение. Это
свойство может иметь одно из нескольких значений для настройки поведения в
соответствии с тем, что должна делать команда; подробности см. в строках
документации delete-selection-pre-hook и delete-selection-helper.