Как установить отметку в elisp и иметь выбор смещения?

9

Нормальным поведением Emacs, когда активен режим переходных меток, является то, что когда вы делаете выбор смещением, то, если следующая команда является движением без смещения, метка деактивируется. Например, после команд M-l(чтобы отметить текущую строку с помощью функции ниже) и C-f, метка деактивируется. Как подражать этому поведению из elisp после (set-mark-command nil)?

Например:

(defun my-mark-current-line ()
  (interactive)
  (beginning-of-line)
  (set-mark-command nil)
  (end-of-line)
  (forward-char))

(global-set-key (kbd "M-l") 'my-mark-current-line)

Теперь сделайте Ml Cf и регион будет расти, но вместо этого я хочу поведение по умолчанию, то есть регион будет деактивироваться при Cf, и расти с CSf.

РЕДАКТИРОВАТЬ : следует использовать функцию, отличную от команды set-mark-command, которая позволяет это? Я не мог найти ни одного.

Mikl
источник
Я считаю, что это невозможно (и я могу ошибаться). Пока регион активен, навигационные команды будут изменять выбор. Использование shift-выбора C-S-fаналогично C-SPC(активация региона) + C-f(навигация). Вы, вероятно, можете получить то, что хотите, связавшись C-f с функцией-оболочкой, которая сначала деактивирует область, если она активна, а затем переходит к тому, что C-fделает ( forward-char); и привязать C-S-fнепосредственно к forward-char. Обратите внимание, что если вы когда-либо будете использовать emacs в режиме терминала, C-fи C-S-fоба будут вести себя так, C-fкак если бы терминал не мог различить два.
Каушал Моди
Кроме того, оболочка и привязка, которые вы сделали, C-fбудут применяться ко всем другим командам навигации, которые вы используете.
Каушал Моди
Кстати, C-fпосле M-lне расширяет регион, потому что нет активного региона в конце M-l(который связан downcase-wordпо умолчанию).
Каушал Моди
1
@KaushalModi Я думаю, что M-lуказанная OP является не привязкой по умолчанию ( downcase-word), а пользовательской привязкойmy-mark-current-line
nispio
действительно @nispio.
Микл

Ответы:

8

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

;; (source: http://emacs.stackexchange.com/a/22166/93)
(defun my-mark-current-line ()
  (interactive)
  (beginning-of-line)
  (setq this-command-keys-shift-translated t)
  (call-interactively 'end-of-line)
  (call-interactively 'forward-char))

(global-set-key (kbd "M-l") 'my-mark-current-line)

Обновить:

С тех пор как я написал ответ выше, я потратил немного времени на то, чтобы узнать, как на самом деле работает выбор смены. Это устанавливает значение символа, transient-mark-modeчтобы быть cons-ячейкой формы (only . OLDVAL), где OLDVALявляется значением до выбора сдвига.

Приведенное ниже решение позволяет избежать использования call-interactively, активируя метку по мере необходимости и устанавливая соответствующее значение transient-mark-mode. По сути, я считаю, что это решение менее опасно, чем первое.

В качестве бонуса теперь он имеет дополнительный счетчик повторов и расширит текущий выбор в любом направлении, если отметка уже активна.

;; (source: http://emacs.stackexchange.com/a/22166/93)
(defun my-mark-current-line (&optional arg)
  "Uses shift selection to select the current line.
When there is an existing shift selection, extends the selection
in the appropriate direction to include current line."
  (interactive "p")
  (let ((oldval (or (cdr-safe transient-mark-mode) transient-mark-mode))
        (backwards (and mark-active (> (mark) (point))))
        (beg (and mark-active (mark-marker))))
    (unless beg
      (if backwards (end-of-line) (beginning-of-line))
      (setq beg (point-marker)))
    (if backwards (end-of-line (- 1 arg)) (beginning-of-line (+ 1 arg)))
    (unless mark-active
      (push-mark beg nil t))
    (setq transient-mark-mode (cons 'only oldval))))
nispio
источник
1
Оба работают отлично, а oldval вещь очень полезна! большое спасибо!
Микл