Làm cách nào để tự động tính toán các dòng bắt đầu và kết thúc khi bao gồm các tệp nguồn ở chế độ org?


10

Tôi có tài liệu dưới đây:

#+INCLUDE: "code/basic.sv" :src systemverilog :lines "14-117"

Ở đây dòng 14 là nơi tôi có class basic extends ..và dòng 116 là nơi tôi có endclass.

Có cách nào để tự động chèn các số 14 và 117 (= 116 + 1) để tôi không phải cập nhật thủ công mỗi khi tôi sửa đổi code/basic.svkhông?


Vì vậy, bạn luôn muốn nó đi từ lớp này đến lớp cuối?
Malabarba

1
Không. Đó là một ví dụ. Tôi đang nghĩ đến một giải pháp nơi tôi có thể cung cấp regex cho các dòng bắt đầu và kết thúc .. Một cái gì đó sẽ đánh giá một chức năngorg-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Kaushal Modi

Một cách là, đặt một số loại dấu duy nhất (bắt đầu kết thúc) trong tệp được bao gồm và tìm thấy chúng với chức năng sẽ được nối vào org-export-before-processing-hookđể xử lý trước cho số dòng. Một cách khác là chỉ cần gửi một thư yêu cầu tính năng đến danh sách gửi thư org :)
kindahero

Câu trả lời:


8

Đây là một lựa chọn khác. Cái này là cho phép bạn tùy chỉnh các biểu thức chính quy trên cơ sở bao gồm. Nó sẽ phù hợp hơn với một số quy trình công việc vì bạn không bị giới hạn trong các định nghĩa dựa trên tiện ích mở rộng.

Sử dụng

Làm một cái gì đó như sau trong tập tin org của bạn. ( :linesTừ khóa là tùy chọn)

#+INCLUDE: "code/my-class.sv" :src systemverilog :range-begin "^class" :range-end "^endclass" :lines "14-80"

Hàm sẽ truy cập "my- class.sv" và tìm kiếm hai biểu thức chính đó, sau đó nó sẽ cập nhật :linestừ khóa theo kết quả khớp.

Nếu :range-beginthiếu, phạm vi sẽ là "-80".
Nếu :range-endthiếu, phạm vi sẽ là "14-".

Mật mã

(add-hook 'before-save-hook #'endless/update-includes)

(defun endless/update-includes (&rest ignore)
  "Update the line numbers of #+INCLUDE:s in current buffer.
Only looks at INCLUDEs that have either :range-begin or :range-end.
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
  (interactive)
  (when (derived-mode-p 'org-mode)
    (save-excursion
      (goto-char (point-min))
      (while (search-forward-regexp
              "^\\s-*#\\+INCLUDE: *\"\\([^\"]+\\)\".*:range-\\(begin\\|end\\)"
              nil 'noerror)
        (let* ((file (expand-file-name (match-string-no-properties 1)))
               lines begin end)
          (forward-line 0)
          (when (looking-at "^.*:range-begin *\"\\([^\"]+\\)\"")
            (setq begin (match-string-no-properties 1)))
          (when (looking-at "^.*:range-end *\"\\([^\"]+\\)\"")
            (setq end (match-string-no-properties 1)))
          (setq lines (endless/decide-line-range file begin end))
          (when lines
            (if (looking-at ".*:lines *\"\\([-0-9]+\\)\"")
                (replace-match lines :fixedcase :literal nil 1)
              (goto-char (line-end-position))
              (insert " :lines \"" lines "\""))))))))

(defun endless/decide-line-range (file begin end)
  "Visit FILE and decide which lines to include.
BEGIN and END are regexps which define the line range to use."
  (let (l r)
    (save-match-data
      (with-temp-buffer
        (insert-file file)
        (goto-char (point-min))
        (if (null begin)
            (setq l "")
          (search-forward-regexp begin)
          (setq l (line-number-at-pos (match-beginning 0))))
        (if (null end)
            (setq r "")
          (search-forward-regexp end)
          (setq r (1+ (line-number-at-pos (match-end 0)))))
        (format "%s-%s" l r)))))

2
Điều đó thật tuyệt! Bây giờ tôi có thể sử dụng điều này để xuất nhiều đoạn mã từ cùng một tệp. Đoạn 1 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1". Đoạn 2 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2". Việc thực hiện là hoàn hảo! Cảm ơn đã thực hiện điều này nhanh chóng!
Kaushal Modi

5

Cách tốt nhất tôi có thể nghĩ đến là cập nhật những con số này ngay lập tức trước khi xuất hoặc trước khi đánh giá.

Trình cập nhật

Đây là chức năng đi qua bộ đệm. Bạn có thể liên kết nó với một khóa, hoặc thêm nó vào một cái móc. Đoạn mã sau cập nhật các dòng bất cứ khi nào bạn lưu tệp , nhưng nếu trường hợp sử dụng của bạn khác, chỉ cần tìm ra hook nào bạn cần! (chế độ org có đầy đủ các hook)

(add-hook 'before-save-hook #'endless/update-includes)

(defun endless/update-includes (&rest ignore)
  "Update the line numbers of all #+INCLUDE:s in current buffer.
Only looks at INCLUDEs that already have a line number listed!
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
  (interactive)
  (when (derived-mode-p 'org-mode)
    (save-excursion
      (goto-char (point-min))
      (while (search-forward-regexp
              "^\\s-*#\\+INCLUDE: *\"\\([^\"]+\\)\".*:lines *\"\\([-0-9]+\\)\""
              nil 'noerror)
        (let* ((file (expand-file-name (match-string-no-properties 1)))
               (lines (endless/decide-line-range file)))
          (when lines
            (replace-match lines :fixedcase :literal nil 2)))))))

Các quy tắc

Đây là nơi bạn xác định regexps sẽ được sử dụng làm dòng đầu tiên và cuối cùng được đưa vào. Bạn có thể đưa ra một danh sách các biểu thức chính cho mỗi phần mở rộng tệp.

(defcustom endless/extension-regexp-map 
  '(("sv" ("^class\\b" . "^endclass\\b") ("^enum\\b" . "^endenum\\b")))
  "Alist of regexps to use for each file extension.
Each item should be
    (EXTENSION (REGEXP-BEGIN . REGEXP-END) (REGEXP-BEGIN . REGEXP-END))
See `endless/decide-line-range' for more information."
  :type '(repeat (cons string (repeat (cons regexp regexp)))))

Công nhân nền

Đây là anh chàng làm hầu hết công việc.

(defun endless/decide-line-range (file)
  "Visit FILE and decide which lines to include.
The FILE's extension is used to get a list of cons cells from
`endless/extension-regexp-map'. Each cons cell is a pair of
regexps, which determine the beginning and end of region to be
included. The first one which matches is used."
  (let ((regexps (cdr-safe (assoc (file-name-extension file)
                                  endless/extension-regexp-map)))
        it l r)
    (when regexps
      (save-match-data
        (with-temp-buffer
          (insert-file file)
          (while regexps
            (goto-char (point-min))
            (setq it (pop regexps))
            (when (search-forward-regexp (car it) nil 'noerror)
              (setq l (line-number-at-pos (match-beginning 0)))
              (when (search-forward-regexp (cdr it) nil 'noerror)
                (setq regexps nil
                      r (line-number-at-pos (match-end 0))))))
          (when r (format "%s-%s" l (+ r 1))))))))

1
Nếu tôi có thể đề xuất, hãy edebug hai hàm và sau đó gọi hàm đầu tiên bằng Mx. Điều đó nên rất nhiều thông tin. :-)
Malabarba

Các chức năng tự chạy tốt. Nhưng hook cần truyền một đối số cho hàm mà nó đang gọi. Từ các tài liệu cho org-export-before-processing-hook, Every function in this hook will be called with one argument: the back-end currently used, as a symbol. Vì chúng tôi không vượt qua bất kỳ đối số, chúng tôi nhận được lỗi run-hook-with-args: Wrong number of arguments. Bây giờ tôi không chắc nên thêm đối số nào vào endless/update-includes... (&optional dummy)?
Kaushal Modi

@kaushalmodi ôi, xấu quá. Tôi đã cập nhật câu trả lời. Bạn có thể sử dụng những gì bạn đã viết là tốt.
Malabarba

OK .. thêm (&optional dummy)thực sự làm việc! Nhưng một tác dụng phụ thú vị của việc gọi hàm thông qua hook. Nếu tôi gọi hàm bằng cách sử dụng M-x, nó sẽ sửa đổi .orgtệp với số dòng được cập nhật. Nhưng nếu tôi chỉ xuất sang html và cho phép hook gọi hàm, các số dòng được cập nhật chỉ được phản ánh trong tệp đã xuất, KHÔNG có trong .orgtệp.
Kaushal Modi

@kaushalmodi Vâng, đó là cách org hook hoạt động. Thay vào đó, bạn có thể thêm nó vào trước-save-hook.
Malabarba
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.