Có cách nào tốt hơn để xử lý các tài liệu đa dòng trong elisp không?


9

Tôi ghét cái cách mà elisp (không chắc chắn nếu LISP nói chung) xử lý các tài liệu đa dòng.

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

Tôi chắc chắn ước gì tôi có thể làm một cái gì đó như

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

để vết lõm phù hợp.

Thật không may, eval-khi-biên dịch không thực hiện công việc.

Có ai có ý tưởng nào?


Nó khá dễ dàng để tạo một macro sẽ mở rộng thành một defun. Hạn chế của cách tiếp cận đó - và nó là một nhược điểm lớn - đó là sẽ gây nhầm lẫn cho bất kỳ phần mềm nào (ngoài trình biên dịch / trình thông dịch elisp) đang phân tích cú pháp mã của bạn để tìm defuns.
Harald Hanche-Olsen

3
Thật thú vị, lý do tại sao thủ thuật của bạn không hoạt động là eval-when-compiletrích dẫn kết quả của nó (để biến nó từ một giá trị thành một biểu thức). Nếu nó thông minh hơn một chút và chỉ trích dẫn kết quả của nó khi nó không tự trích dẫn, nó sẽ hoạt động.
Stefan

Câu trả lời:


7

Tất nhiên một my-defunmacro là cách dễ dàng. Nhưng một giải pháp đơn giản hơn sẽ là

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

Điều này sẽ làm cho thủ thuật của bạn hoạt động, ít nhất là trong tất cả các trường hợp hàm được khai thác vĩ mô trước khi nó thực sự được xác định, bao gồm các trường hợp sử dụng chính (ví dụ: nếu nó được tải từ một tệp, nếu nó được biên dịch byte hoặc nếu nó được xác định thông qua M-C-x).

Tuy nhiên, điều này sẽ không sửa tất cả các mã hiện có, vì vậy có lẽ câu trả lời tốt hơn là:

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

chỉ nên thay đổi các tài liệu theo 2 khoảng trắng, nhưng chỉ ở phía hiển thị, mà không ảnh hưởng đến nội dung thực tế của bộ đệm.


1
Tôi thực sự thích giải pháp thứ hai của bạn. Nhưng nỗi sợ hãi phi lý của tôi về lời khuyên làm cho tôi bản lề lúc đầu. :-)
Malabarba

6

Bạn có thể sử dụng một macro như thế này:

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

Sau đó, bạn có thể xác định chức năng của mình như thế này:

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

Tuy nhiên, tôi muốn mạnh mẽ khuyến cáo không đi ngược lại các tiêu chuẩn cho một lợi ích cận biên như vậy. Việc thụt lề không thường xuyên, mà làm phiền bạn chỉ bằng 2 cột, chưa kể nó giúp làm nổi bật dòng tài liệu đầu tiên quan trọng hơn.


Trên thực tế, phần thân của một defun được ước tính (khi hàm được gọi) và nó được mở rộng macro khi hàm được định nghĩa. Vì vậy, mẹo của anh ta nên / có thể làm việc.
Stefan

@Stefan Đó là sự thật. Quên eval-when-compilelà một vĩ mô.
Malabarba

-1

Tôi đã thấy các gói xác định các tài liệu như thế này:

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

Đặt trích dẫn đầu tiên trên dòng đầu tiên sau đó bắt đầu văn bản trên dòng tiếp theo để tất cả chúng xếp hàng. Đó chắc chắn không phải là tiêu chuẩn nhưng bạn sẽ không phải là người duy nhất làm điều đó.


1
Đó là một ý tưởng tồi. Trong các bối cảnh như Apropose, chỉ dòng đầu tiên của chuỗi doc được hiển thị, do đó dòng đầu tiên sẽ cung cấp thông tin (và tự đứng vững). Bằng cách này bạn có được một mô tả trống.
Gilles 'SO- ngừng trở nên xấu xa'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.