Bagaimana cara menetapkan tanda di elisp dan memiliki pilihan shift?

9

Perilaku normal Emacs ketika mode tanda-transien aktif adalah bahwa ketika Anda melakukan pemilihan-shift, maka jika perintah berikutnya adalah gerakan non-shift, tanda dinonaktifkan. Misalnya, setelah perintah M-l(untuk menandai baris saat ini dengan fungsi di bawah) dan C-f, tanda dinonaktifkan. Bagaimana cara meniru perilaku itu dari elisp sesudahnya (set-mark-command nil)?

Sebagai contoh:

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

Sekarang lakukan Ml Cf dan wilayah akan tumbuh, tetapi sebaliknya, saya ingin perilaku default, yaitu wilayah untuk menonaktifkan saat Cf, dan tumbuh dengan CSf.

EDIT : haruskah menggunakan fungsi yang berbeda untuk set-mark-command yang memungkinkan ini? Saya tidak dapat menemukannya.

mikl
sumber
Saya percaya itu tidak mungkin (dan saya mungkin salah). Selama suatu wilayah aktif, perintah navigasi akan mengubah pilihan. Penggunaan pemilihan shift C-S-fdianalogikan dengan C-SPC(mengaktifkan suatu wilayah) + C-f(navigasi). Anda mungkin bisa mendapatkan apa yang Anda inginkan dengan mengikat C-f ke fungsi pembungkus yang pertama menonaktifkan suatu wilayah jika aktif dan kemudian mulai melakukan apa yang C-fdilakukan ( forward-char); dan ikat C-S-flangsung ke forward-char. Perhatikan bahwa jika Anda pernah menggunakan emacs dalam mode terminal, C-fdan C-S-fkeduanya akan berperilaku sebagai C-fterminal tidak dapat membedakan keduanya.
Kaushal Modi
Juga pembungkus dan penjilidan yang Anda lakukan C-fakan berlaku untuk semua perintah navigasi lain yang Anda gunakan juga.
Kaushal Modi
btw C-fsetelah M-ltidak memperluas wilayah karena tidak ada wilayah aktif di akhir M-l(yang terikat downcase-wordsecara default).
Kaushal Modi
1
@ KaushalModi Saya berpikir bahwa yang M-ldirujuk oleh OP bukan pengikatan default ( downcase-word), tetapi pengikatan kustommy-mark-current-line
nispio
memang @nispio.
mikl

Jawaban:

8

Karena terjemahan shift dan aktivasi sementara mark ditangani oleh loop perintah, Anda perlu memanggil versi interaktif dari fungsi gerakan untuk mendapatkan perilaku pemilihan shift yang sesuai dari mereka:

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

Memperbarui:

Sejak menulis jawaban di atas, saya meluangkan waktu untuk belajar lebih banyak tentang bagaimana pemilihan shift benar-benar bekerja di bawah tenda. Ini menetapkan nilai simbol transient-mark-modemenjadi sel kontra bentuk (only . OLDVAL), di mana OLDVALnilai sebelum pemilihan shift.

Solusi di bawah ini menghindari penggunaan call-interactivelydengan mengaktifkan tanda sesuai kebutuhan, dan menetapkan nilai yang sesuai transient-mark-mode. Pada dasarnya, saya menganggap solusi ini kurang dari hack daripada yang pertama.

Sebagai bonus, sekarang memiliki hitungan ulang opsional, dan akan memperpanjang pilihan saat ini di kedua arah jika tanda sudah aktif.

;; (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
sumber
1
Keduanya bekerja dengan sempurna dan yang lama sangat berguna! Terima kasih banyak!
mikl