조직 모드에서 소스 파일을 포함 할 때 시작 및 끝 줄을 자동으로 계산하는 방법은 무엇입니까?


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
아뇨. 예입니다. 시작 및 끝 줄에 정규식을 제공 할 수있는 솔루션을 생각하고 있습니다. 뭔가 기능을 평가할 것입니다.org-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Kaushal Modi

한 가지 방법은 포함 된 파일에 일종의 고유 한 마커 (시작 부분) org-export-before-processing-hook를 배치하고 행 번호의 전처리에 연결되는 함수로이를 찾는 것입니다 . 또 다른 방법은 기능 요청 메일을 조직 메일 링리스트로 보내는 것입니다. :)
kindahero

답변:


8

다른 옵션이 있습니다. 이것은 정규 표현식을 포함별로 사용자 정의 할 수있게합니다. 확장 기반 정의로 제한되지 않으므로 일부 워크 플로에 더 적합합니다.

쓰다

조직 파일에서 다음과 같은 작업을 수행하십시오. ( :lines키워드는 선택 사항입니다)

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

이 함수는 "my-class.sv"를 방문하여 두 정규 표현식을 검색 한 다음 :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
대단해! 이제 이것을 사용하여 동일한 파일에서 여러 스 니펫을 내보낼 수 있습니다. 발췌문 1 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1". 코드 조각 2 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2". 처형은 완벽합니다! 이것을 빨리 구현해 주셔서 감사합니다 !
Kaushal Modi

5

내가 생각할 수있는 가장 좋은 방법은 내보내기 직전에 또는 평가하기 전에이 숫자를 업데이트하는 것입니다.

업데이터

이것은 버퍼를 통과하는 기능입니다. 키에 바인딩하거나 후크에 추가 할 수 있습니다. 다음 코드 는 파일을 저장할 때마다 줄을 업데이트 하지만 사용 사례가 다른 경우 필요한 후크를 찾으십시오! (org 모드는 후크 로 가득합니다 )

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

정규식

여기에 포함 할 첫 번째 및 마지막 행으로 사용될 정규식을 정의합니다. 각 파일 확장자에 대한 정규식 목록을 제공 할 수 있습니다.

(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

OK .. 추가가 (&optional dummy)실제로 작동했습니다! 그러나 후크를 통해 함수를 호출하면 흥미로운 부작용이 발생합니다. 를 사용하여 함수를 호출하면 업데이트 된 줄 번호로 파일을 M-x수정합니다 .org. 그러나 단순히 html로 내보내고 후크가 함수를 호출하도록 허용하면 업데이트 된 줄 번호가 파일이 아닌 내 보낸 파일에만 반영됩니다 .org.
Kaushal Modi

@kaushalmodi 그렇습니다. org 훅이 작동하는 방식입니다. 대신 저장 전 후크에 추가 할 수 있습니다.
Malabarba
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.