Elisp'te çok satırlı öğretileri ele almanın daha iyi bir yolu var mı?


9

Elisp'in (genel olarak LISP'nin çok satırlı öğretileri işleyip işlemediğinden emin değilim) nefret ediyorum.

(defun foo ()
  "This is
a multi
liner
docstring"
  (do-stuff))

Tabii ki böyle bir şey yapabilseydim

(defun foo ()
  (eval-when-compile 
    (concat
      "This is\n"
       "a multi\n"
       "line\n"
       "docstring"))
  (do-stuff))

girintinin tutarlı olması için.

Ne yazık ki, eval-when-compile işi yapmaz.

Herhangi bir fikri olan var mı?


İçine genişleyecek bir makro oluşturmak oldukça kolay olmalıdır defun. Bu yaklaşımın dezavantajı - ve büyük olanı, kodunuzu arayan kodları ayrıştıran herhangi bir yazılımı (elisp derleyici / yorumlayıcı dışında) karıştıracak olmasıdır defun.
Harald Hanche-Olsen

3
Tuhaf bir şekilde, hilenizin çalışmamasının nedeni eval-when-compile, sonucunu alıntılamaktır (bir değerden bir ifadeye dönüştürmek). Biraz daha akıllı olsaydı ve sadece kendi kendine alıntı yapmadığında sonucunu vermiş olsaydı işe yarardı.
Stefan

Yanıtlar:


7

Tabii ki bir my-defunmakro kolay çıkış yoludur. Ancak daha basit bir çözüm

(advice-add 'eval-when-compile :filter-return
            (lambda (exp)
              (if (and (eq 'quote (car-safe exp))
                       (stringp (cadr exp)))
                  (cadr exp)
                exp)))

Bu, en azından işlevin gerçekte tanımlanmadan önce makro genişletildiği tüm durumlarda, ana kullanım durumlarını içermesi gereken (örneğin bir dosyadan yüklendiyse, bayt derlenmişse veya tanımlanmışsa), hilenizi çalıştıracaktır. aracılığıyla M-C-x).

Yine de, bu mevcut kodun tümünü düzeltmeyecektir, bu yüzden belki de daha iyi bir cevap şudur:

;; -*- lexical-binding:t -*-

(defun my-shift-docstrings (orig ppss)
  (let ((face (funcall orig ppss)))
    (when (eq face 'font-lock-doc-face)
      (save-excursion
        (let ((start (point)))
          (parse-partial-sexp (point) (point-max) nil nil ppss 'syntax-table)
          (while (search-backward "\n" start t)
            (put-text-property (point) (1+ (point)) 'display
                               (propertize "\n  " 'cursor 0))))))
    face))

(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            (font-lock-mode 1)
            (push 'display font-lock-extra-managed-props)
            (add-function :around (local 'font-lock-syntactic-face-function)
                          #'my-shift-docstrings)))

bu sadece docstringleri 2 boşluk kaydırmalı, ancak tamponun gerçek içeriğini etkilemeden sadece ekran tarafında değiştirmelidir.


1
İkinci çözümünüzü gerçekten seviyorum. Ama mantıksız tavsiye korkum ilk başta beni menteşelendiriyor. :-)
Malabarba

6

Bunun gibi bir makro kullanabilirsiniz:

(defmacro my-defun (name arglist &rest forms)
  "Like `defun', but concatenates strings."
  (declare (indent defun))
  (let (doc-lines)
    (while (and (stringp (car-safe forms))
                (> (length forms) 1))
      (setq doc-lines
            (append doc-lines (list (pop forms)))))
    `(defun ,name ,arglist
       ,(mapconcat #'identity doc-lines "\n")
       ,@forms)))

Ardından işlevlerinizi şu şekilde tanımlayabilirsiniz:

(my-defun test (a)
  "Description"
  "asodksad"
  "ok"
  (interactive)
  (+ 1 a))

Yine de, böyle marjinal bir fayda için standartlara karşı gitmemenizi şiddetle tavsiye ederim. Sizi rahatsız eden “düzensiz girinti” sadece 2 sütundadır, bahsetmemek gerekirse, daha önemli olan ilk belge satırını vurgulamaya yardımcı olur.


Aslında, bir defun gövdesi olan değerlendirildi (fonksiyon denir) ve fonksiyon tanımlandığı zaman makro genleştirilmektedir. Bu yüzden onun hilesi çalışmalı / çalışabilirdi.
Stefan

@Stefan Doğru. Unutulan eval-when-compilebir makro idi.
Malabarba

-1

Doktrinleri şu şekilde tanımlayan paketler gördüm:

(defun my-function (x y) "
this is my docstring
that lines always lines up
across multiple lines."
  (+ x y))

İlk alıntıyı ilk satıra yerleştirip ardından metni sıraya gelecek şekilde sonraki satıra yerleştirin. Kesinlikle standart değil ama bunu yapan tek kişi sen olmayacaksın.


1
Bu kötü bir fikir. Apropos gibi bağlamlarda, sadece öğretinin ilk satırı gösterilir, böylece ilk satır bilgi sağlamalıdır (ve kendi başına durmalıdır). Bu şekilde boş bir açıklama alırsınız.
Gilles 'SO- kötü olmayı bırak'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.