Bagaimana cara membuat yasnippet dan perusahaan bekerja lebih baik?

22

Dalam emacs saya, katakanlah, saya menggunakan "elisp"yasnippet untuk memperpanjang blok lisp dalam mode-org. Tetapi sebelum saya memperpanjangnya, perusahaan dipicu terlebih dahulu, yang memberi saya menu seperti "1. elisp1, 2. elisp2"tanpa opsi "elisp". Sekarang jika saya gunakan tabuntuk memperpanjang yasnippet, selalu menjengkelkan yang "elisp1"selalu pertama kali muncul di layar. Jadi saya perlu menghapus "1"dulu, dan melakukan ekstensi snippet yasnippet.

Jadi sebagai solusi, saya selalu menggunakan tombol panah kiri untuk mematikan menu penyelesaian perusahaan terlebih dahulu, tetapi kursor sekarang akan pergi ke "elis|p", jadi sekali lagi saya menggunakan tombol panah kanan untuk menggerakkan kursor ke ujung "elisp|", dan memperpanjang snippet.

Inilah pertanyaan saya: bagaimana saya dapat mengikat tabkunci pertama kali memicu yasnippet tetapi tidak perusahaan untuk menyelamatkan saya?

Leu_Grady
sumber
1
Saya menggunakan tabuntuk companydan C-ountuk yasnippet. Saya dapat menjelaskan lebih lanjut jika Anda tertarik.
abo-abo
@ abo-abo, terima kasih balas. Saya tahu saya bisa melakukannya seperti yang Anda lakukan, tetapi saya mengikat Co ke perintah lain, dan parahnya saya telah melatih otot tangan saya untuk beradaptasi tab. Jadi saya tidak ingin mengubah ikatannya.
Leu_Grady
Itu sebabnya saya bertanya :) Tidak ada gunanya mengoceh tentang bagaimana C-obisa memperluas singkatan dan snippet dan membuka garis dll jika Anda tidak tertarik.
abo-abo
tampaknya menarik, dapatkah Anda menjelaskan lebih lanjut? :)
Leu_Grady

Jawaban:

22

Inilah yang saya buat untuk diri saya sendiri, menghadapi masalah yang sama. Ini dari halaman Emacs Wiki mode perusahaan , tetapi sangat diperluas:

(defun check-expansion ()
  (save-excursion
    (if (looking-at "\\_>") t
      (backward-char 1)
      (if (looking-at "\\.") t
    (backward-char 1)
    (if (looking-at "->") t nil)))))

(defun do-yas-expand ()
  (let ((yas/fallback-behavior 'return-nil))
    (yas/expand)))

(defun tab-indent-or-complete ()
  (interactive)
  (cond
   ((minibufferp)
    (minibuffer-complete))
   (t
    (indent-for-tab-command)
    (if (or (not yas/minor-mode)
        (null (do-yas-expand)))
    (if (check-expansion)
        (progn
          (company-manual-begin)
          (if (null company-candidates)
          (progn
            (company-abort)
            (indent-for-tab-command)))))))))

(defun tab-complete-or-next-field ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand)))
      (if company-candidates
      (company-complete-selection)
    (if (check-expansion)
      (progn
        (company-manual-begin)
        (if (null company-candidates)
        (progn
          (company-abort)
          (yas-next-field))))
      (yas-next-field)))))

(defun expand-snippet-or-complete-selection ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand))
      (company-abort))
      (company-complete-selection)))

(defun abort-company-or-yas ()
  (interactive)
  (if (null company-candidates)
      (yas-abort-snippet)
    (company-abort)))

(global-set-key [tab] 'tab-indent-or-complete)
(global-set-key (kbd "TAB") 'tab-indent-or-complete)
(global-set-key [(control return)] 'company-complete-common)

(define-key company-active-map [tab] 'expand-snippet-or-complete-selection)
(define-key company-active-map (kbd "TAB") 'expand-snippet-or-complete-selection)

(define-key yas-minor-mode-map [tab] nil)
(define-key yas-minor-mode-map (kbd "TAB") nil)

(define-key yas-keymap [tab] 'tab-complete-or-next-field)
(define-key yas-keymap (kbd "TAB") 'tab-complete-or-next-field)
(define-key yas-keymap [(control tab)] 'yas-next-field)
(define-key yas-keymap (kbd "C-g") 'abort-company-or-yas)

Pada dasarnya, ini membuat <tab>melakukan hal yang benar sebagian besar waktu. Menekan tab akan

  • Indentasi baris saat ini,
  • Jika ada yasnippet untuk diperluas, perluas, bahkan jika ini berarti membatalkan penyelesaian perusahaan (saya tidak menggunakan banyak singkatan, jadi belum ada dukungan singkatan),
  • Jika penyelesaian perusahaan sedang berlangsung, lengkapi dengan item yang dipilih,
  • Kalau tidak, coba gunakan perusahaan untuk memulai pelengkapan otomatis,
  • Jika tidak ada yang dilengkapi secara otomatis dan kami berada di placeholder yasnippet, lewati ke placeholder berikutnya.

Perhatikan bahwa jika ada peluang untuk pelengkapan otomatis dan saat ini Anda mengedit di tempat penampung cuplikan, situasinya ambigu. Sebagai kompromi, saya terikat C-<tab>untuk langsung beralih ke placeholder berikutnya.

Fakta bahwa nama snippet tidak muncul di menu perusahaan dan keberadaan snippet secara diam-diam mengubah perilaku kunci tab tidak terlalu bagus, sayangnya ... Meskipun setidaknya mungkin untuk mengetik <return>alih-alih mendapatkan penyelesaian sebagai gantinya dari cuplikan.

Kristóf Marussy
sumber
Ini sepertinya mengganggu magit. Menyebabkan tab in magit naik Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>. Adakah yang bisa saya perbaiki?
zsquare
@zsquare Saya tidak menggunakan magit (saya tahu, saya gila) jadi saya tidak bisa menguji ini untuk memastikan, tapi kedengarannya seperti keymap magit untuk TAB, yang mengikatnyamagit-section-toggle , bertentangan dengan baris di (global-set-key [tab] 'tab-indent-or-complete)atas. Perbaikan cepat dan kotor adalah dengan menambahkan tanda centang di awal fungsi di tab-indent-or-completeatas untuk melihat apakah kita dalam mode magit, misalnya untuk variabel global yang diaktifkan magit-mode-hook.
dodgethesteamroller
ini luar biasa, terima kasih! :) titik gaya kecil, whencukup banyak if+progn
Matt Briggs
@zsquare Untuk mendukung tab dalam mode magit, tambahkan ini ke tab-indent-or-completecond `((diturunkan-mode-p 'magit-mode) (magit-section-toggle (magit-current-section)))`
Bae
Untuk mendukung ido alih-alih menyelesaikan minibuffer default, ganti kond dengan `((minibufferp) (ido-complete))`
Bae
10

Berikut kode yang saya gunakan:

(global-set-key "\C-o" 'aya-open-line)

(defun aya-open-line ()
  "Call `open-line', unless there are abbrevs or snippets at point.
In that case expand them.  If there's a snippet expansion in progress,
move to the next field. Call `open-line' if nothing else applies."
  (interactive)
  (cond ((expand-abbrev))

        ((yas--snippets-at-point)
         (yas-next-field-or-maybe-expand))

        ((ignore-errors
           (yas-expand)))

        (t
         (open-line 1))))

aya-open-linedari auto-yasnippet melakukan lebih dari sekadar open-line:

  • mencoba untuk memperluas singkatan
  • ia mencoba untuk pindah ke bidang yasnippet berikutnya
  • ia mencoba memperluas yasnippet
  • akhirnya, ia memanggil open-linejika semuanya gagal
abo-abo
sumber
terima kasih untuk cuplikanmu. Cukup bagus. Tapi masalahnya masih ada. Ketika saya pertama kali menggunakannya C-o, itu hanya menutup menu perusahaan, jadi saya perlu menekan dua kali untuk memperpanjang yasnippet.
Leu_Grady
Saya tidak punya masalah seperti itu: C-odengan menu perusahaan yang aktif akan menutup menu dan memperluas cuplikan.
abo-abo