Comment définir la marque dans elisp et avoir une sélection de décalage?

9

Le comportement normal d'Emacs lorsque le mode de marque transitoire est actif est que lorsque vous effectuez une sélection de décalage, alors si la commande suivante est un mouvement sans décalage, la marque est désactivée. Par exemple, après les commandes M-l(pour marquer la ligne actuelle avec la fonction ci-dessous) et C-f, la marque est désactivée. Comment émuler ce comportement d'Elisp après (set-mark-command nil)?

Par exemple:

(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)

Maintenant, faites Ml Cf et la région augmentera, mais à la place, je veux que le comportement par défaut, c'est-à-dire que la région se désactive lorsque Cf, et grandisse avec CSf.

EDIT : devrait utiliser une fonction différente de set-mark-command qui permet cela? Je n'en ai pas trouvé.

mikl
la source
Je pense que ce n'est pas possible (et je peux me tromper). Tant qu'une région est active, les commandes de navigation modifient la sélection. La sélection par décalage à l'aide C-S-fest analogue à C-SPC(activation d'une région) + C-f(navigation). Vous pouvez probablement obtenir ce que vous voulez en vous liant C-f à une fonction wrapper qui désactive d'abord une région si elle est active, puis continue de faire ce C-fqui ( forward-char); et lier C-S-fdirectement à forward-char. Notez que si jamais vous utilisez emacs en mode terminal, C-fet C-S-fque vous vous comporterez tous les deux C-fcar le terminal ne pourra pas distinguer les deux.
Kaushal Modi
L'encapsuleur et la liaison que vous avez C-fappliqués s'appliqueraient également à toutes les autres commandes de navigation que vous utilisez également.
Kaushal Modi
btw C-fafter M-ln'étend pas la région car il n'y a pas de région active à la fin de M-l(qui est liée à downcase-wordpar défaut).
Kaushal Modi
1
@KaushalModi Je pense que la M-lréférence à l'OP n'est pas la liaison par défaut ( downcase-word), mais la liaison personnalisée demy-mark-current-line
nispio
en effet @nispio.
mikl

Réponses:

8

Étant donné que la traduction de décalage et l'activation temporaire de la marque sont gérées par la boucle de commande, vous devrez appeler les versions interactives des fonctions de mouvement afin d'obtenir le comportement de sélection de décalage approprié:

;; (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)

Mise à jour:

Depuis la rédaction de la réponse ci-dessus, j'ai pris le temps d'en apprendre un peu plus sur le fonctionnement réel de la sélection des équipes sous le capot. Il définit la valeur du symbole de transient-mark-modecomme une contre-cellule du formulaire (only . OLDVAL), où OLDVALest la valeur avant la sélection de décalage.

La solution ci-dessous évite l'utilisation de call-interactivelyen activant la marque au besoin et en définissant la valeur appropriée de transient-mark-mode. Fondamentalement, je considère que cette solution est moins un hack que la première.

En prime, il a désormais un nombre de répétitions facultatif et étendra la sélection actuelle dans les deux sens si la marque est déjà active.

;; (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
la source
1
Les deux fonctionnent parfaitement et la chose oldval est très utile! Merci beaucoup!
mikl