Jak ustawić znacznik w elisp i wybrać opcję shift?

9

Normalne zachowanie Emacsa, gdy aktywny jest tryb znaku przejściowego, polega na tym, że po dokonaniu wyboru shift, znak jest nieaktywny, jeśli następne polecenie jest ruchem bez zmiany. Na przykład po poleceniach M-l(aby zaznaczyć bieżącą linię za pomocą funkcji poniżej) i C-fznak jest wyłączony. Jak naśladować to zachowanie z elisp po (set-mark-command nil)?

Na przykład:

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

Teraz wykonaj Ml Cf, a region będzie się rozwijał, ale zamiast tego chcę, aby zachowanie domyślne, tj. Region dezaktywował się, gdy Cf, i rozwijał się wraz z CSf.

EDYCJA : czy należy użyć funkcji innej niż set-mark-command, która na to pozwala? Nie mogłem znaleźć.

mikl
źródło
Uważam, że nie jest to możliwe (i mogę się mylić). Dopóki region jest aktywny, polecenia nawigacyjne będą zmieniać wybór. Korzystanie z wyboru shift C-S-fjest analogiczne do C-SPC(aktywowanie regionu) + C-f(nawigacja). Prawdopodobnie możesz uzyskać to, co chcesz, łącząc C-f się z funkcją otoki, która najpierw dezaktywuje region, jeśli jest aktywny, a następnie przechodzi do robienia tego co C-frobi ( forward-char); i wiążą się C-S-fbezpośrednio z forward-char. Zauważ, że jeśli kiedykolwiek użyjesz emacsa w trybie terminala C-fi C-S-foba będą się zachowywać, ponieważ C-fterminal nie może ich rozróżnić.
Kaushal Modi
Również opakowanie i powiązanie, które wykonałeś C-f, dotyczyłoby również wszystkich innych poleceń nawigacyjnych, których używasz.
Kaushal Modi
btw C-fafter M-lnie rozszerza regionu, ponieważ na końcu nie ma aktywnego regionu M-l(który jest downcase-worddomyślnie związany).
Kaushal Modi
1
@KaushalModi Myślę, że M-lprzywołane przez OP nie jest domyślnym powiązaniem ( downcase-word), ale niestandardowym wiązaniemmy-mark-current-line
nispio
rzeczywiście @nispio.
mikl

Odpowiedzi:

8

Ponieważ translacja shift i tymczasowa aktywacja znaku są obsługiwane przez pętlę poleceń, będziesz musiał wywołać interaktywne wersje funkcji ruchu, aby uzyskać od nich odpowiednie zachowanie wyboru zmiany:

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

Aktualizacja:

Od czasu napisania powyższej odpowiedzi poświęciłem trochę czasu, aby dowiedzieć się więcej o tym, jak wybór zmiany biegów naprawdę działa pod maską. Ustawia wartość symbolu, transient-mark-modektóra ma być komórką przeciwną formularza (only . OLDVAL), gdzie OLDVALjest wartością przed wyborem przesunięcia.

Poniższe rozwiązanie pozwala uniknąć użycia call-interactivelyaktywując znak w razie potrzeby i ustawiając odpowiednią wartość transient-mark-mode. Zasadniczo uważam to rozwiązanie za mniej hackowe niż pierwsze.

Jako bonus ma teraz opcjonalną liczbę powtórzeń i rozszerzy bieżący wybór w obu kierunkach, jeśli znak jest już aktywny.

;; (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
źródło
1
Oba działają idealnie, a oldval jest bardzo przydatny! wielkie dzięki!
mikl