วิธีคำนวณบรรทัดเริ่มต้นและสิ้นสุดโดยอัตโนมัติเมื่อรวมไฟล์ต้นฉบับในโหมดองค์กร


10

ฉันมีด้านล่างในเอกสารของฉัน:

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

นี่คือสาย 14 เป็นที่ที่ผมมีclass basic extends ..และสาย 116 endclassเป็นที่ที่ฉันมี

มีวิธีการอัตโนมัติแทรกหมายเลข 14 และ 117 (= 116 + 1) เพื่อที่ฉันจะได้ไม่ต้องด้วยตนเองปรับปรุงพวกเขาทุกครั้งที่ผมปรับเปลี่ยนcode/basic.sv?


ดังนั้นคุณต้องการให้มันเปลี่ยนจากคลาสเป็นคลาสเอนด์หรือไม่
Malabarba

1
ไม่นั่นเป็นตัวอย่าง ฉันกำลังคิดวิธีแก้ปัญหาที่ฉันสามารถให้ regex สำหรับจุดเริ่มต้นและจุดสิ้นสุด .. บางสิ่งจะประเมินฟังก์ชันorg-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Kaushal Modi

วิธีหนึ่งคือการวางเครื่องหมายเฉพาะ (เริ่มต้นสิ้นสุด) ลงในไฟล์ที่รวมและค้นหาด้วยฟังก์ชั่นซึ่งจะเชื่อมต่อorg-export-before-processing-hookกับการประมวลผลล่วงหน้าสำหรับหมายเลขบรรทัด อีกวิธีหนึ่งก็คือส่งจดหมายขอคุณสมบัติไปยังรายชื่อผู้รับจดหมายขององค์กร :)
23414 kindahero

คำตอบ:


8

นี่คือตัวเลือกอื่น อันนี้คือให้คุณปรับแต่งการแสดงออกปกติบนพื้นฐานรวมต่อ ควรเหมาะสมกับเวิร์กโฟลว์บางส่วนเนื่องจากคุณไม่ได้จำกัดความหมายที่อิงตามส่วนขยาย

ใช้

ทำสิ่งต่อไปนี้ในไฟล์องค์กรของคุณ ( :linesคำหลักเป็นตัวเลือก)

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

ฟังก์ชั่นจะไปที่ "my-class.sv" และค้นหา regexps ทั้งสองนั้นจากนั้นจะอัปเดต:linesคำหลักตามผลลัพธ์การจับคู่

หาก:range-beginหายไปช่วงจะเป็น "-80"
หาก:range-endหายไปช่วงจะเป็น "14-"

รหัส

(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
มันเยี่ยมมาก! ตอนนี้ฉันสามารถใช้สิ่งนี้เพื่อส่งออกตัวอย่างหลายไฟล์จากไฟล์เดียวกัน Snippet #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1"1: Snippet #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2"2: การประหารชีวิตนั้นไร้ที่ติ! ขอขอบคุณที่ใช้สิ่งนี้อย่างรวดเร็ว!
Kaushal Modi

5

วิธีที่ดีที่สุดที่ฉันสามารถคิดได้คือการอัปเดตตัวเลขเหล่านี้ทันทีก่อนส่งออกหรือก่อนประเมินผล

Updater

นี่คือฟังก์ชันที่ต้องผ่านบัฟเฟอร์ คุณสามารถผูกมันไว้กับกุญแจหรือเพิ่มลงในตะขอ โค้ดต่อไปนี้จะอัพเดตบรรทัด เมื่อใดก็ตามที่คุณบันทึกไฟล์แต่ถ้ากรณีการใช้งานของคุณแตกต่างกันเพียงแค่ค้นหาว่าคุณต้องการ hook อะไร! (โหมดองค์กรเต็มไปด้วย hooks)

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

Regexps

นี่คือที่ที่คุณกำหนด regexps ซึ่งจะใช้เป็นบรรทัดแรกและบรรทัดสุดท้ายที่จะรวม คุณสามารถให้รายการ regexps สำหรับแต่ละนามสกุลไฟล์

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

ผู้ทำงานเบื้องหลัง

นี่คือคนที่ทำงานส่วนใหญ่

(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
หากฉันอาจแนะนำ edebug ทั้งสองฟังก์ชั่นแล้วเรียกใช้ครั้งแรกกับ Mx ควรมีข้อมูลมาก :-)
Malabarba

ฟังก์ชั่นของตัวเองทำงานได้ดี แต่ขอจะต้องผ่านการโต้แย้งไปยังฟังก์ชั่นที่มันกำลังเรียก จากเอกสารสำหรับ,org-export-before-processing-hook Every function in this hook will be called with one argument: the back-end currently used, as a symbolในขณะที่เรายังไม่ได้ผ่านการโต้แย้งใด ๆ run-hook-with-args: Wrong number of argumentsที่เราได้รับข้อผิดพลาด ตอนนี้ฉันไม่แน่ใจว่าสิ่งที่โต้แย้งเพื่อเพิ่มendless/update-includes... (&optional dummy)?
Kaushal Modi

@kaushalmodi อุ้ยฉันไม่ดี ฉันได้อัพเดตคำตอบแล้ว คุณสามารถใช้สิ่งที่คุณเขียนได้เช่นกัน
Malabarba

ตกลง .. การเพิ่ม(&optional dummy)ใช้งานได้จริง! แต่ผลข้างเคียงที่น่าสนใจของการเรียกฟังก์ชั่นผ่านทาง hook หากฉันเรียกใช้ฟังก์ชั่นM-xนี้จะเป็นการแก้ไข.orgไฟล์ด้วยหมายเลขบรรทัดที่อัปเดต แต่ถ้าฉันส่งออกเป็น html และอนุญาตให้ hook เรียกใช้ฟังก์ชันหมายเลขบรรทัดที่อัปเดตจะแสดงเฉพาะในไฟล์ที่ส่งออกเท่านั้นไม่ใช่ใน.orgไฟล์
Kaushal Modi

@kaushalmodi ใช่นั่นเป็นวิธีการทำงานของ org org คุณสามารถเพิ่มลงใน before-save-hook แทน
Malabarba
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.