Bagaimana cara otomatis menghitung garis awal dan akhir ketika memasukkan file sumber dalam mode-org?

10

Saya punya di bawah ini dalam dokumentasi saya:

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

Di sini baris 14 adalah tempat saya miliki class basic extends ..dan baris 116 adalah tempat saya punya endclass.

Apakah ada cara untuk memasukkan angka 14 dan 117 secara otomatis (= 116 +1) sehingga saya tidak perlu memperbaruinya secara manual setiap kali saya memodifikasinya code/basic.sv?

Kaushal Modi
sumber
Jadi Anda selalu ingin itu beralih dari kelas ke kelas akhir?
Malabarba
1
Tidak. Itu contohnya. Saya sedang memikirkan solusi di mana saya dapat memberikan regex untuk garis awal dan akhir .. Sesuatu akan mengevaluasi fungsiorg-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Kaushal Modi
Salah satu caranya adalah, menempatkan semacam spidol unik (mulai akhir) di file yang disertakan dan menemukannya dengan fungsi yang akan dihubungkan org-export-before-processing-hookke preprocess untuk nomor baris. Cara lain hanya mengirim fitur mail permintaan ke mailing list org :)
kindahero

Jawaban:

8

Ini pilihan lain. Yang ini mari kita sesuaikan ekspresi reguler berdasarkan per-sertakan. Seharusnya lebih cocok dengan beberapa alur kerja karena Anda tidak terbatas pada definisi berbasis ekstensi.

Menggunakan

Lakukan sesuatu seperti yang berikut ini di file org Anda. (Kata :lineskunci adalah opsional)

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

Fungsi akan mengunjungi "my-class.sv" dan mencari dua regexps, dan kemudian akan memperbarui :lineskata kunci sesuai dengan hasil pertandingan.

Jika :range-begintidak ada, kisarannya adalah "-80".
Jika :range-endtidak ada, kisaran akan menjadi "14-".

Kode

(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)))))
Malabarba
sumber
2
Ini bagus! Sekarang saya dapat menggunakan ini untuk mengekspor beberapa cuplikan dari file yang sama. Snippet 1: #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1". Snippet 2: #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2". Eksekusi tanpa cacat! Terima kasih telah menerapkan ini secepat ini !
Kaushal Modi
5

Cara terbaik yang dapat saya pikirkan adalah memperbarui nomor-nomor ini segera sebelum mengekspor atau sebelum mengevaluasi.

Pembaru

Ini adalah fungsi yang melewati buffer. Anda dapat mengikatnya ke kunci, atau menambahkannya ke kail. Kode berikut memperbarui baris setiap kali Anda menyimpan file , tetapi jika kasus penggunaan Anda berbeda, cari tahu yang mana yang Anda butuhkan! (org-mode penuh dengan kait)

(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

Di sinilah Anda mendefinisikan regexps yang akan digunakan sebagai baris pertama dan terakhir yang akan disertakan. Anda dapat memberikan daftar regexps untuk setiap ekstensi file.

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

Pekerja latar belakang

Ini adalah pria yang melakukan sebagian besar pekerjaan.

(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))))))))
Malabarba
sumber
1
Jika saya dapat menyarankan, edebug dua fungsi dan kemudian memanggil yang pertama dengan Mx. Itu harus sangat informatif. :-)
Malabarba
Fungsi itu sendiri berjalan dengan baik. Tetapi hook perlu menyampaikan argumen ke fungsi yang dipanggil. Dari dokumentasi untuk org-export-before-processing-hook, Every function in this hook will be called with one argument: the back-end currently used, as a symbol. Karena kita tidak melewati argumen apa pun, kita mendapatkan kesalahan run-hook-with-args: Wrong number of arguments. Sekarang saya tidak yakin argumen apa yang akan ditambahkan endless/update-includes... (&optional dummy)?
Kaushal Modi
@kaushalmodi oops, salahku. Saya sudah memperbarui jawabannya. Anda dapat menggunakan hal yang Anda tulis juga.
Malabarba
Oke .. menambahkan (&optional dummy)sebenarnya berhasil! Tetapi efek samping yang menarik dari memanggil fungsi melalui hook. Jika saya memanggil fungsi menggunakan M-x, itu memodifikasi .orgfile dengan nomor baris yang diperbarui. Tetapi jika saya hanya mengekspor ke html dan mengizinkan kait untuk memanggil fungsi, nomor baris yang diperbarui hanya tercermin dalam file yang diekspor, BUKAN dalam .orgfile.
Kaushal Modi
@kaushalmodi Ya, begitulah cara kerja kait org. Anda dapat menambahkannya ke save-hook sebelumnya.
Malabarba